ETH Price: $2,634.27 (-3.09%)

Contract

0xE13E9010e818D48df1A0415021d9526ef845e2Cd
 

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Sell And Withdra...173739542023-05-30 19:55:47629 days ago1685476547IN
0xE13E9010...ef845e2Cd
0 ETH0.0058458245.07331357
Sell And Withdra...173737902023-05-30 19:22:47630 days ago1685474567IN
0xE13E9010...ef845e2Cd
0 ETH0.0050986938.04317214
Sell And Withdra...173736642023-05-30 18:57:35630 days ago1685473055IN
0xE13E9010...ef845e2Cd
0 ETH0.0059213845.61012677
Sell And Withdra...173736282023-05-30 18:50:23630 days ago1685472623IN
0xE13E9010...ef845e2Cd
0 ETH0.0010744347.04607818
Sell And Withdra...173733782023-05-30 17:59:47630 days ago1685469587IN
0xE13E9010...ef845e2Cd
0 ETH0.0076401659.01020228
Sell And Withdra...165190742023-01-30 10:34:35750 days ago1675074875IN
0xE13E9010...ef845e2Cd
0 ETH0.0019933215.12767669
Sell And Withdra...165190592023-01-30 10:31:35750 days ago1675074695IN
0xE13E9010...ef845e2Cd
0 ETH0.0019364314.44742068
Sell And Withdra...165190412023-01-30 10:27:59750 days ago1675074479IN
0xE13E9010...ef845e2Cd
0 ETH0.0018570514.30528665
Sell And Withdra...165190272023-01-30 10:25:11750 days ago1675074311IN
0xE13E9010...ef845e2Cd
0 ETH0.0018730614.46595888
Sell And Withdra...158681962022-10-31 12:59:23841 days ago1667221163IN
0xE13E9010...ef845e2Cd
0 ETH0.0024689618.5619766
Sell And Withdra...154035142022-08-24 14:46:55909 days ago1661352415IN
0xE13E9010...ef845e2Cd
0 ETH0.0043690915.88445743
Sell And Withdra...144228932022-03-20 11:07:561066 days ago1647774476IN
0xE13E9010...ef845e2Cd
0 ETH0.0022991216.46845143
Sell And Withdra...140749692022-01-25 13:17:531120 days ago1643116673IN
0xE13E9010...ef845e2Cd
0 ETH0.0164001196.59229093
Sell And Withdra...135686882021-11-07 9:52:381199 days ago1636278758IN
0xE13E9010...ef845e2Cd
0 ETH0.0105723680.23529723
Sell And Withdra...135686762021-11-07 9:49:561199 days ago1636278596IN
0xE13E9010...ef845e2Cd
0 ETH0.011162385.97899581
Sell And Withdra...135686582021-11-07 9:45:221199 days ago1636278322IN
0xE13E9010...ef845e2Cd
0 ETH0.0100175174.73913461
Sell And Withdra...134851112021-10-25 7:03:171212 days ago1635145397IN
0xE13E9010...ef845e2Cd
0 ETH0.0035484571.88053284
Sell And Withdra...133990842021-10-11 19:12:521226 days ago1633979572IN
0xE13E9010...ef845e2Cd
0 ETH0.01503456115.36917208
Sell And Withdra...133920752021-10-10 16:46:451227 days ago1633884405IN
0xE13E9010...ef845e2Cd
0 ETH0.0097366372.64355482
Sell And Withdra...133920632021-10-10 16:44:331227 days ago1633884273IN
0xE13E9010...ef845e2Cd
0 ETH0.0204219274.24346779
Sell And Withdra...133920582021-10-10 16:43:041227 days ago1633884184IN
0xE13E9010...ef845e2Cd
0 ETH0.008530365.70571172
Sell And Withdra...133920512021-10-10 16:41:521227 days ago1633884112IN
0xE13E9010...ef845e2Cd
0 ETH0.0092515272.87077498
Sell And Withdra...133920382021-10-10 16:40:081227 days ago1633884008IN
0xE13E9010...ef845e2Cd
0 ETH0.0090061869.01341805
Sell And Withdra...133909542021-10-10 12:45:091227 days ago1633869909IN
0xE13E9010...ef845e2Cd
0 ETH0.0224044181.45431272
Sell And Withdra...133909542021-10-10 12:45:091227 days ago1633869909IN
0xE13E9010...ef845e2Cd
0 ETH0.0109175681.45431272
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block
From
To
173739542023-05-30 19:55:47629 days ago1685476547
0xE13E9010...ef845e2Cd
0.06818888 ETH
173739542023-05-30 19:55:47629 days ago1685476547
0xE13E9010...ef845e2Cd
0.06818888 ETH
173737902023-05-30 19:22:47630 days ago1685474567
0xE13E9010...ef845e2Cd
0.07039424 ETH
173737902023-05-30 19:22:47630 days ago1685474567
0xE13E9010...ef845e2Cd
0.07039424 ETH
173736642023-05-30 18:57:35630 days ago1685473055
0xE13E9010...ef845e2Cd
0.10989098 ETH
173736642023-05-30 18:57:35630 days ago1685473055
0xE13E9010...ef845e2Cd
0.10989098 ETH
173733782023-05-30 17:59:47630 days ago1685469587
0xE13E9010...ef845e2Cd
0.05309808 ETH
173733782023-05-30 17:59:47630 days ago1685469587
0xE13E9010...ef845e2Cd
0.05309808 ETH
165190742023-01-30 10:34:35750 days ago1675074875
0xE13E9010...ef845e2Cd
0.3616617 ETH
165190742023-01-30 10:34:35750 days ago1675074875
0xE13E9010...ef845e2Cd
0.3616617 ETH
165190592023-01-30 10:31:35750 days ago1675074695
0xE13E9010...ef845e2Cd
0.19988341 ETH
165190592023-01-30 10:31:35750 days ago1675074695
0xE13E9010...ef845e2Cd
0.19988341 ETH
165190412023-01-30 10:27:59750 days ago1675074479
0xE13E9010...ef845e2Cd
0.19666741 ETH
165190412023-01-30 10:27:59750 days ago1675074479
0xE13E9010...ef845e2Cd
0.19666741 ETH
165190272023-01-30 10:25:11750 days ago1675074311
0xE13E9010...ef845e2Cd
0.14071311 ETH
165190272023-01-30 10:25:11750 days ago1675074311
0xE13E9010...ef845e2Cd
0.14071311 ETH
158681962022-10-31 12:59:23841 days ago1667221163
0xE13E9010...ef845e2Cd
0.03834921 ETH
158681962022-10-31 12:59:23841 days ago1667221163
0xE13E9010...ef845e2Cd
0.03834921 ETH
154035142022-08-24 14:46:55909 days ago1661352415
0xE13E9010...ef845e2Cd
0.07618276 ETH
154035142022-08-24 14:46:55909 days ago1661352415
0xE13E9010...ef845e2Cd
0.07618276 ETH
144228932022-03-20 11:07:561066 days ago1647774476
0xE13E9010...ef845e2Cd
0.38080537 ETH
144228932022-03-20 11:07:561066 days ago1647774476
0xE13E9010...ef845e2Cd
0.38080537 ETH
140749692022-01-25 13:17:531120 days ago1643116673
0xE13E9010...ef845e2Cd
1.67977724 ETH
140749692022-01-25 13:17:531120 days ago1643116673
0xE13E9010...ef845e2Cd
1.67977724 ETH
135686882021-11-07 9:52:381199 days ago1636278758
0xE13E9010...ef845e2Cd
0.60241846 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
VanillaRouter

Compiler Version
v0.6.8+commit.0bbfe453

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, GNU GPLv3 license
File 1 of 12 : VanillaRouter.sol
// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity ^0.6.8;

import "@openzeppelin/contracts/math/SafeMath.sol";
import "./VanillaGovernanceToken.sol";
import "./UniswapTrader.sol";

/// @dev Needed functions from the WETH contract originally deployed in https://etherscan.io/address/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2#code
interface IWETH {
    function deposit() external payable;

    function withdraw(uint256 amount) external;
}

/**
    @title The main entrypoint for Vanilla
*/
contract VanillaRouter is UniswapTrader {
    string private constant _ERROR_TRADE_EXPIRED = "b1";
    string private constant _ERROR_TRANSFER_FAILED = "b2";
    string private constant _ERROR_TOO_MANY_TRADES_PER_BLOCK = "b3";
    string private constant _ERROR_NO_TOKEN_OWNERSHIP = "b4";
    string private constant _ERROR_RESERVELIMIT_TOO_LOW = "b5";
    string private constant _ERROR_NO_SAFE_TOKENS = "b6";

    uint256 public immutable epoch;
    VanillaGovernanceToken public immutable vnlContract;
    uint128 public immutable reserveLimit;

    using SafeMath for uint256;

    // data for calculating volume-weighted average prices, average purchasing block, and limiting trades per block
    struct PriceData {
        uint256 ethSum;
        uint256 tokenSum;
        uint256 weightedBlockSum;
        uint256 latestBlock;
    }

    // Price data, indexed as [owner][token]
    mapping(address => mapping(address => PriceData)) public tokenPriceData;

    /**
       @dev Emitted when tokens are sold.
       @param seller The owner of tokens.
       @param token The address of the sold token.
       @param amount Number of sold tokens.
       @param eth The received ether from the trade.
       @param profit The calculated profit from the trade.
       @param reward The amount of VanillaGovernanceToken reward tokens transferred to seller.
       @param reserve The internally tracker Uniswap WETH reserve before trade.
     */
    event TokensSold(
        address indexed seller,
        address indexed token,
        uint256 amount,
        uint256 eth,
        uint256 profit,
        uint256 reward,
        uint256 reserve
    );

    /**
       @dev Emitted when tokens are bought.
       @param buyer The new owner of tokens.
       @param token The address of the purchased token.
       @param eth The amount of ether spent in the trade.
       @param amount Number of purchased tokens.
       @param reserve The internally tracker Uniswap WETH reserve before trade.
     */
    event TokensPurchased(
        address indexed buyer,
        address indexed token,
        uint256 eth,
        uint256 amount,
        uint256 reserve
    );

    /**
        @notice Deploys the contract and the VanillaGovernanceToken contract.
        @dev initializes the token contract for safe reference and sets the epoch for reward calculations
        @param uniswapRouter The address of UniswapRouter contract
        @param limit The minimum WETH reserve for a token to be eligible in profit mining
        @param safeList The list of ERC-20 addresses that are considered "safe", and will be eligible for rewards
    */
    constructor(
        address uniswapRouter,
        uint128 limit,
        address[] memory safeList
    ) public UniswapTrader(uniswapRouter, limit, safeList) {
        vnlContract = new VanillaGovernanceToken();
        epoch = block.number;
        require(limit > 0, _ERROR_RESERVELIMIT_TOO_LOW);
        require(safeList.length > 0, _ERROR_NO_SAFE_TOKENS);
        reserveLimit = limit;
    }

    modifier beforeDeadline(uint256 deadline) {
        require(deadline >= block.timestamp, _ERROR_TRADE_EXPIRED);
        _;
    }

    /**
        @notice Buys the tokens with Ether. Use the external pricefeed for pricing.
        @dev Buys the `numToken` tokens for all the msg.value Ether, before `blockTimeDeadline`

        @param token The address of ERC20 token to be bought
        @param numToken The amount of ERC20 tokens to be bought
        @param blockTimeDeadline The block timestamp when this buy-transaction expires
     */
    function depositAndBuy(
        address token,
        uint256 numToken,
        uint256 blockTimeDeadline
    ) external payable beforeDeadline(blockTimeDeadline) {
        IWETH weth = IWETH(_wethAddr);
        uint256 numEth = msg.value;
        weth.deposit{value: numEth}();

        // execute swap using WETH-balance of this contract
        _executeBuy(msg.sender, address(this), token, numEth, numToken);
    }

    /**
        @notice Buys the tokens with WETH. Use the external pricefeed for pricing.
        @dev Buys the `numToken` tokens for all the msg.value Ether, before `blockTimeDeadline`

        @param token The address of ERC20 token to be bought
        @param numEth The amount of WETH to spend. Needs to be pre-approved for the VanillaRouter.
        @param numToken The amount of ERC20 tokens to be bought
        @param blockTimeDeadline The block timestamp when this buy-transaction expires
     */
    function buy(
        address token,
        uint256 numEth,
        uint256 numToken,
        uint256 blockTimeDeadline
    ) external beforeDeadline(blockTimeDeadline) {
        // execute swap using WETH-balance of the caller
        _executeBuy(msg.sender, msg.sender, token, numEth, numToken);
    }

    function _executeBuy(
        address owner,
        address currentWETHHolder,
        address token,
        uint256 numEthSold,
        uint256 numToken
    ) internal {
        // verify the one-trade-per-block-per-token rule and protect against reentrancy
        PriceData storage prices = tokenPriceData[owner][token];
        require(
            block.number > prices.latestBlock,
            _ERROR_TOO_MANY_TRADES_PER_BLOCK
        );
        prices.latestBlock = block.number;

        // do the swap and update price data
        (uint256 tokens, uint256 newReserve) =
            _buyInUniswap(token, numEthSold, numToken, currentWETHHolder);
        prices.ethSum = prices.ethSum.add(numEthSold);
        prices.tokenSum = prices.tokenSum.add(tokens);
        prices.weightedBlockSum = prices.weightedBlockSum.add(
            block.number.mul(tokens)
        );
        emit TokensPurchased(msg.sender, token, numEthSold, tokens, newReserve);
    }

    /**
        @dev Receives the ether only from WETH contract during withdraw()
     */
    receive() external payable {
        // make sure that router accepts ETH only from WETH contract
        assert(msg.sender == _wethAddr);
    }

    /**
        @notice Sells the tokens the caller owns. Use the external pricefeed for pricing.
        @dev Sells the `numToken` tokens msg.sender owns, for `numEth` ether, before `blockTimeDeadline`

        @param token The address of ERC20 token to be sold
        @param numToken The amount of ERC20 tokens to be sold
        @param numEthLimit The minimum amount of ether to be received for exchange (the limit order)
        @param blockTimeDeadline The block timestamp when this sell-transaction expires
     */
    function sell(
        address token,
        uint256 numToken,
        uint256 numEthLimit,
        uint256 blockTimeDeadline
    ) external beforeDeadline(blockTimeDeadline) {
        // execute the swap by transferring WETH directly to caller
        _executeSell(msg.sender, msg.sender, token, numToken, numEthLimit);
    }

    /**
        @notice Sells the tokens the caller owns. Use the external pricefeed for pricing.
        @dev Sells the `numToken` tokens msg.sender owns, for `numEth` ether, before `blockTimeDeadline`

        @param token The address of ERC20 token to be sold
        @param numToken The amount of ERC20 tokens to be sold
        @param numEthLimit The minimum amount of ether to be received for exchange (the limit order)
        @param blockTimeDeadline The block timestamp when this sell-transaction expires
     */
    function sellAndWithdraw(
        address token,
        uint256 numToken,
        uint256 numEthLimit,
        uint256 blockTimeDeadline
    ) external beforeDeadline(blockTimeDeadline) {
        // execute the swap by transferring WETH to this contract first
        uint256 numEth =
            _executeSell(
                msg.sender,
                address(this),
                token,
                numToken,
                numEthLimit
            );

        IWETH iweth = IWETH(_wethAddr);
        iweth.withdraw(numEth);

        (bool etherTransferSuccessful, ) =
            msg.sender.call{value: numEth}(new bytes(0));
        require(etherTransferSuccessful, _ERROR_TRANSFER_FAILED);
    }

    function _executeSell(
        address owner,
        address recipient,
        address token,
        uint256 numTokensSold,
        uint256 numEthLimit
    ) internal returns (uint256) {
        // verify the one-trade-per-block-per-token rule and protect against reentrancy
        PriceData storage prices = tokenPriceData[owner][token];
        require(
            block.number > prices.latestBlock,
            _ERROR_TOO_MANY_TRADES_PER_BLOCK
        );
        prices.latestBlock = block.number;

        // do the swap, calculate the profit and update price data
        (uint256 numEth, uint128 reserve) =
            _sellInUniswap(token, numTokensSold, numEthLimit, recipient);

        uint256 profitablePrice =
            numTokensSold.mul(prices.ethSum).div(prices.tokenSum);
        uint256 avgBlock = prices.weightedBlockSum.div(prices.tokenSum);
        uint256 newTokenSum = prices.tokenSum.sub(numTokensSold);
        uint256 profit =
            numEth > profitablePrice ? numEth.sub(profitablePrice) : 0;

        prices.ethSum = _proportionOf(
            prices.ethSum,
            newTokenSum,
            prices.tokenSum
        );
        prices.weightedBlockSum = _proportionOf(
            prices.weightedBlockSum,
            newTokenSum,
            prices.tokenSum
        );
        prices.tokenSum = newTokenSum;

        uint256 reward = 0;
        if (isTokenRewarded(token)) {
            // calculate the reward, and mint tokens
            reward = _calculateReward(
                epoch,
                avgBlock,
                block.number,
                profit,
                reserve,
                reserveLimit
            );
            if (reward > 0) {
                vnlContract.mint(msg.sender, reward);
            }
        }

        emit TokensSold(
            msg.sender,
            token,
            numTokensSold,
            numEth,
            profit,
            reward,
            reserve
        );
        return numEth;
    }

    /**
        @notice Estimates the reward.
        @dev Estimates the reward for given `owner` when selling `numTokensSold``token`s for `numEth` Ether. Also returns the individual components of the reward formula.
        @return profitablePrice The expected amount of Ether for this trade. Profit of this trade can be calculated with `numEth`-`profitablePrice`.
        @return avgBlock The volume-weighted average block for the `owner` and `token`
        @return htrs The Holding/Trading Ratio, Squared- estimate for this trade, percentage value range in fixed point range 0-100.0000.
        @return vpc The Value-Protection Coefficient- estimate for this trade, percentage value range in fixed point range 0-100.0000.
        @return reward The token reward estimate for this trade.
     */
    function estimateReward(
        address owner,
        address token,
        uint256 numEth,
        uint256 numTokensSold
    )
        external
        view
        returns (
            uint256 profitablePrice,
            uint256 avgBlock,
            uint256 htrs,
            uint256 vpc,
            uint256 reward
        )
    {
        PriceData storage prices = tokenPriceData[owner][token];
        require(prices.tokenSum > 0, _ERROR_NO_TOKEN_OWNERSHIP);
        profitablePrice = numTokensSold.mul(prices.ethSum).div(prices.tokenSum);
        avgBlock = prices.weightedBlockSum.div(prices.tokenSum);
        if (numEth > profitablePrice) {
            uint256 profit = numEth.sub(profitablePrice);
            uint128 wethReserve = wethReserves[token];
            htrs = _estimateHTRS(avgBlock);
            vpc = _estimateVPC(profit, wethReserve);
            reward = _calculateReward(
                epoch,
                avgBlock,
                block.number,
                profit,
                wethReserve,
                reserveLimit
            );
        } else {
            htrs = 0;
            vpc = 0;
            reward = 0;
        }
    }

    function _estimateHTRS(uint256 avgBlock) internal view returns (uint256) {
        // H     = "Holding/Trading Ratio, Squared" (HTRS)
        //       = ((Bmax-Bavg)/(Bmax-Bmin))²
        //       = (((Bmax-Bmin)-(Bavg-Bmin))/(Bmax-Bmin))²
        //       = (Bhold/Btrade)² (= 0 if Bmax = Bavg, NaN if Bmax = Bmin)
        if (avgBlock == block.number || block.number == epoch) return 0;

        uint256 bhold = block.number - avgBlock;
        uint256 btrade = block.number - epoch;

        return bhold.mul(bhold).mul(1_000_000).div(btrade.mul(btrade));
    }

    function _estimateVPC(uint256 profit, uint256 reserve)
        internal
        view
        returns (uint256)
    {
        // VPC = 1-max((P + L)/W, 1) (= 0 if P+L > W)
        //     = (W - P - L ) / W
        if (profit + reserveLimit > reserve) return 0;

        return (reserve - profit - reserveLimit).mul(1_000_000).div(reserve);
    }

    function _calculateReward(
        uint256 epoch_,
        uint256 avgBlock,
        uint256 currentBlock,
        uint256 profit,
        uint128 wethReserve,
        uint128 reserveLimit_
    ) internal pure returns (uint256) {
        /*
        Reward formula:
            P     = absolute profit in Ether = `profit`
            Bmax  = block.number when trade is happening = `block.number`
            Bavg  = volume-weighted average block.number of purchase = `avgBlock`
            Bmin  = "epoch", the block.number when contract was deployed = `epoch_`
            Bhold = Bmax-Bavg = number of blocks the trade has been held (instead of traded)
            Btrade= Bmax-Bmin = max possible trading time in blocks
            H     = "Holding/Trading Ratio, Squared" (HTRS)
                  = ((Bmax-Bavg)/(Bmax-Bmin))²
                  = (((Bmax-Bmin)-(Bavg-Bmin))/(Bmax-Bmin))²
                  = (Bhold/Btrade)² (= 0 if Bmax = Bavg, NaN if Bmax = Bmin)
            L     = WETH reserve limit for any traded token = `_reserveLimit`
            W     = internally tracked WETH reserve size for when selling a token = `wethReserve`
            V     = value protection coefficient
                  = 1-min((P + L)/W, 1) (= 0 if P+L > W)
            R     = minted rewards
                  = P*V*H
                  = if   (P = 0 || P + L > W || Bmax = Bavg || BMax = Bmin)
                         0
                    else P * (1-(P + L)/W) * (Bhold/Btrade)²
                       = (P * (W - P - L) * Bhold²) / W / Btrade²
        */

        if (profit == 0) return 0;
        if (profit + reserveLimit_ > wethReserve) return 0;
        if (currentBlock == avgBlock) return 0;
        if (currentBlock == epoch_) return 0;

        // these cannot underflow thanks to previous checks
        uint256 rpl = wethReserve - profit - reserveLimit_;
        uint256 bhold = currentBlock - avgBlock;
        uint256 btrade = currentBlock - epoch_;

        uint256 nominator = profit.mul(rpl).mul(bhold.mul(bhold));
        // no division by zero possible, both wethReserve and btrade² are always > 0
        return nominator / wethReserve / (btrade.mul(btrade));
    }

    function _proportionOf(
        uint256 total,
        uint256 numerator,
        uint256 denominator
    ) internal pure returns (uint256) {
        // percentage = (numerator/denominator)
        // proportion = total * percentage
        return total.mul(numerator).div(denominator);
    }
}

File 2 of 12 : Context.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <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 GSN 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 payable) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

File 3 of 12 : SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

File 4 of 12 : ERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "../../GSN/Context.sol";
import "./IERC20.sol";
import "../../math/SafeMath.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.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin guidelines: functions revert instead
 * of 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 {
    using SafeMath for uint256;

    mapping (address => uint256) private _balances;

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

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;
    uint8 private _decimals;

    /**
     * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
     * a default value of 18.
     *
     * To select a different value for {decimals}, use {_setupDecimals}.
     *
     * All three of these values are immutable: they can only be set once during
     * construction.
     */
    constructor (string memory name_, string memory symbol_) public {
        _name = name_;
        _symbol = symbol_;
        _decimals = 18;
    }

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

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view 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 value {ERC20} uses, unless {_setupDecimals} is
     * called.
     *
     * 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 returns (uint8) {
        return _decimals;
    }

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

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

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `recipient` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(_msgSender(), recipient, 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}.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        _approve(_msgSender(), 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}.
     *
     * Requirements:
     *
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     * - the caller must have allowance for ``sender``'s tokens of at least
     * `amount`.
     */
    function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(sender, recipient, amount);
        _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
        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) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(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) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
        return true;
    }

    /**
     * @dev Moves tokens `amount` from `sender` to `recipient`.
     *
     * This is 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:
     *
     * - `sender` cannot be the zero address.
     * - `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     */
    function _transfer(address sender, address recipient, uint256 amount) internal virtual {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(sender, recipient, amount);

        _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, 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:
     *
     * - `to` 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 = _totalSupply.add(amount);
        _balances[account] = _balances[account].add(amount);
        emit Transfer(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);

        _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
        _totalSupply = _totalSupply.sub(amount);
        emit Transfer(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 Sets {decimals} to a value other than the default one of 18.
     *
     * WARNING: This function should only be called from the constructor. Most
     * applications that interact with token contracts will not expect
     * {decimals} to ever change, and may work incorrectly if it does.
     */
    function _setupDecimals(uint8 decimals_) internal {
        _decimals = decimals_;
    }

    /**
     * @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 to 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 { }
}

File 5 of 12 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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 `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, 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 `sender` to `recipient` 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 sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @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);
}

File 6 of 12 : TransferHelper.sol
pragma solidity >=0.6.0;

// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library TransferHelper {
    function safeApprove(address token, address to, uint value) internal {
        // bytes4(keccak256(bytes('approve(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED');
    }

    function safeTransfer(address token, address to, uint value) internal {
        // bytes4(keccak256(bytes('transfer(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED');
    }

    function safeTransferFrom(address token, address from, address to, uint value) internal {
        // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED');
    }

    function safeTransferETH(address to, uint value) internal {
        (bool success,) = to.call{value:value}(new bytes(0));
        require(success, 'TransferHelper: ETH_TRANSFER_FAILED');
    }
}

File 7 of 12 : 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 8 of 12 : 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 9 of 12 : 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 10 of 12 : 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 11 of 12 : UniswapTrader.sol
// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity ^0.6.8;

import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol";
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol";
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import "@uniswap/lib/contracts/libraries/TransferHelper.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";

/**
    @title The Uniswap-enabled base contract for Vanilla.
*/
contract UniswapTrader {
    using SafeMath for uint256;

    string private constant _ERROR_SLIPPAGE_LIMIT_EXCEEDED = "a1";
    string private constant _INVALID_UNISWAP_PAIR = "a2";

    address internal immutable _uniswapFactoryAddr;
    address internal immutable _wethAddr;

    // internally tracked reserves for price manipulation protection for each token (Uniswap uses uint112 so uint128 is plenty)
    mapping(address => uint128) public wethReserves;

    /**
        @notice Deploys the contract and initializes Uniswap contract references and internal WETH-reserve for safe tokens.
        @dev using UniswapRouter to ensure that Vanilla uses the same WETH contract
        @param routerAddress The address of UniswapRouter contract
        @param limit The initial reserve value for tokens in the safelist
        @param safeList The list of "safe" tokens to trade
     */
    constructor(
        address routerAddress,
        uint128 limit,
        address[] memory safeList
    ) public {
        // fetch addresses via router to guarantee correctness
        IUniswapV2Router02 router = IUniswapV2Router02(routerAddress);
        address wethAddr = router.WETH();
        IUniswapV2Factory factory = IUniswapV2Factory(router.factory());
        for (uint256 i = 0; i < safeList.length; i++) {
            address token = safeList[i];
            // verify that WETH-token pair exists in Uniswap
            // (order isn't significant, UniswapV2Factory.createPair populates the mapping in reverse direction too)
            address pair = factory.getPair(token, wethAddr);
            require(pair != address(0), _INVALID_UNISWAP_PAIR);

            // we initialize the fixed list of rewardedTokens with the reserveLimit-value that they'll match the invariant
            // "every rewardedToken will have wethReserves[rewardedToken] > 0"
            // (this way we don't need to store separate lists for both wethReserve-tracking and tokens eligible for the rewards)
            wethReserves[token] = limit;
        }
        _wethAddr = wethAddr;
        _uniswapFactoryAddr = address(factory);
    }

    /**
        @notice Checks if the given ERC-20 token will be eligible for rewards (i.e. a safelisted token)
        @param token The ERC-20 token address
     */
    function isTokenRewarded(address token) public view returns (bool) {
        return wethReserves[token] > 0;
    }

    function _pairInfo(
        address factory,
        address token,
        address weth
    ) internal pure returns (address pair, bool tokenFirst) {
        // as order of tokens is important in Uniswap pairs, we record this information here and pass it on to caller
        // for gas optimization
        tokenFirst = token < weth;

        // adapted from UniswapV2Library.sol, calculates the CREATE2 address for a pair without making any external calls to factory contract
        pair = address(
            uint256(
                keccak256(
                    abi.encodePacked(
                        hex"ff",
                        factory,
                        keccak256(
                            tokenFirst
                                ? abi.encodePacked(token, weth)
                                : abi.encodePacked(weth, token)
                        ),
                        hex"96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f"
                    )
                )
            )
        );
    }

    function _amountToSwap(
        uint256 tokensIn,
        uint256 reservesIn,
        uint256 reservesOut
    ) internal pure returns (uint256 tokensOut) {
        uint256 inMinusFee = tokensIn.mul(997); // in * (100% - 0.3%)
        tokensOut = reservesOut.mul(inMinusFee).div(
            reservesIn.mul(1000).add(inMinusFee)
        );
    }

    function _updateReservesOnBuy(address token, uint112 wethReserve)
        private
        returns (uint128 reserve)
    {
        // when buying, update internal reserve only if Uniswap reserve is greater
        reserve = wethReserves[token];
        if (reserve == 0) {
            // trading a non-safelisted token, so do not update internal reserves
            return reserve;
        }
        if (wethReserve > reserve) {
            wethReserves[token] = wethReserve;
            reserve = wethReserve;
        }
    }

    function _buyInUniswap(
        address token_,
        uint256 eth,
        uint256 amount_,
        address tokenOwner_
    ) internal returns (uint256 numToken, uint128 reserve) {
        (address pairAddress, bool tokenFirst) =
            _pairInfo(_uniswapFactoryAddr, token_, _wethAddr);
        IUniswapV2Pair pair = IUniswapV2Pair(pairAddress);

        address tokenCustody = address(this);
        uint256 balance = IERC20(token_).balanceOf(tokenCustody);
        IERC20(_wethAddr).transferFrom(tokenOwner_, pairAddress, eth);
        if (tokenFirst) {
            (uint112 tokenReserve, uint112 wethReserve, ) = pair.getReserves();
            pair.swap(
                _amountToSwap(eth, wethReserve, tokenReserve),
                uint256(0),
                tokenCustody,
                new bytes(0)
            );
            reserve = _updateReservesOnBuy(token_, wethReserve);
        } else {
            (uint112 wethReserve, uint112 tokenReserve, ) = pair.getReserves();
            pair.swap(
                uint256(0),
                _amountToSwap(eth, wethReserve, tokenReserve),
                tokenCustody,
                new bytes(0)
            );
            reserve = _updateReservesOnBuy(token_, wethReserve);
        }
        // finally check how the custody balance has changed after swap
        numToken = IERC20(token_).balanceOf(tokenCustody) - balance;
        // revert if the price diff between trade-time and execution-time was too large
        require(numToken >= amount_, _ERROR_SLIPPAGE_LIMIT_EXCEEDED);
    }

    function _updateReservesOnSell(address token, uint112 wethReserve)
        private
        returns (uint128 reserve)
    {
        // when selling, update internal reserve only if the Uniswap reserve is smaller
        reserve = wethReserves[token];
        if (reserve == 0) {
            // trading a non-safelisted token, so do not update internal reserves
            return reserve;
        }
        if (wethReserve < reserve) {
            wethReserves[token] = wethReserve;
            reserve = wethReserve;
        }
    }

    function _sellInUniswap(
        address token_,
        uint256 amount_,
        uint256 eth_,
        address tokenReceiver_
    ) internal returns (uint256 numEth, uint128 reserve) {
        (address pairAddress, bool tokenFirst) =
            _pairInfo(_uniswapFactoryAddr, token_, _wethAddr);
        IUniswapV2Pair pair = IUniswapV2Pair(pairAddress);
        uint256 balance = IERC20(_wethAddr).balanceOf(tokenReceiver_);

        // Use TransferHelper because we have no idea here how token.transfer() has been implemented
        TransferHelper.safeTransfer(token_, pairAddress, amount_);
        if (tokenFirst) {
            (uint112 tokenReserve, uint112 wethReserve, ) = pair.getReserves();
            pair.swap(
                uint256(0),
                _amountToSwap(amount_, tokenReserve, wethReserve),
                tokenReceiver_,
                new bytes(0)
            );
            reserve = _updateReservesOnSell(token_, wethReserve);
        } else {
            (uint112 wethReserve, uint112 tokenReserve, ) = pair.getReserves();
            pair.swap(
                _amountToSwap(amount_, tokenReserve, wethReserve),
                uint256(0),
                tokenReceiver_,
                new bytes(0)
            );
            reserve = _updateReservesOnSell(token_, wethReserve);
        }
        // finally check how the receivers balance has changed after swap
        numEth = IERC20(_wethAddr).balanceOf(tokenReceiver_) - balance;
        // revert if the price diff between trade-time and execution-time was too large
        require(numEth >= eth_, _ERROR_SLIPPAGE_LIMIT_EXCEEDED);
    }
}

File 12 of 12 : VanillaGovernanceToken.sol
// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity ^0.6.8;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

/**
 @title Governance Token for Vanilla Finance.
 */
contract VanillaGovernanceToken is ERC20("Vanilla", "VNL") {
    string private constant _ERROR_ACCESS_DENIED = "c1";
    address private immutable _owner;

    /**
        @notice Deploys the token and sets the caller as an owner.
     */
    constructor() public {
        _owner = msg.sender;
        // set the decimals explicitly to 12, for (theoretical maximum of) VNL reward of a 1ETH of profit
        // should be displayed as 1000000VNL (18-6 = 12 decimals).
        _setupDecimals(12);
    }

    modifier onlyOwner() {
        require(_owner == msg.sender, _ERROR_ACCESS_DENIED);
        _;
    }

    /**
        @notice Mints the tokens. Used only by the VanillaRouter-contract.

        @param to The recipient address of the minted tokens
        @param tradeReward The amount of tokens to be minted
     */
    function mint(address to, uint256 tradeReward) external onlyOwner {
        _mint(to, tradeReward);
    }
}

Settings
{
  "evmVersion": "istanbul",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "remappings": [],
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"uniswapRouter","type":"address"},{"internalType":"uint128","name":"limit","type":"uint128"},{"internalType":"address[]","name":"safeList","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"eth","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reserve","type":"uint256"}],"name":"TokensPurchased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"seller","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"eth","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"profit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reserve","type":"uint256"}],"name":"TokensSold","type":"event"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"numEth","type":"uint256"},{"internalType":"uint256","name":"numToken","type":"uint256"},{"internalType":"uint256","name":"blockTimeDeadline","type":"uint256"}],"name":"buy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"numToken","type":"uint256"},{"internalType":"uint256","name":"blockTimeDeadline","type":"uint256"}],"name":"depositAndBuy","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"epoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"numEth","type":"uint256"},{"internalType":"uint256","name":"numTokensSold","type":"uint256"}],"name":"estimateReward","outputs":[{"internalType":"uint256","name":"profitablePrice","type":"uint256"},{"internalType":"uint256","name":"avgBlock","type":"uint256"},{"internalType":"uint256","name":"htrs","type":"uint256"},{"internalType":"uint256","name":"vpc","type":"uint256"},{"internalType":"uint256","name":"reward","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"isTokenRewarded","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"reserveLimit","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"numToken","type":"uint256"},{"internalType":"uint256","name":"numEthLimit","type":"uint256"},{"internalType":"uint256","name":"blockTimeDeadline","type":"uint256"}],"name":"sell","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"numToken","type":"uint256"},{"internalType":"uint256","name":"numEthLimit","type":"uint256"},{"internalType":"uint256","name":"blockTimeDeadline","type":"uint256"}],"name":"sellAndWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"tokenPriceData","outputs":[{"internalType":"uint256","name":"ethSum","type":"uint256"},{"internalType":"uint256","name":"tokenSum","type":"uint256"},{"internalType":"uint256","name":"weightedBlockSum","type":"uint256"},{"internalType":"uint256","name":"latestBlock","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vnlContract","outputs":[{"internalType":"contract VanillaGovernanceToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"wethReserves","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

6101206040523480156200001257600080fd5b50604051620034d2380380620034d2833981810160405260608110156200003857600080fd5b815160208301516040808501805191519395929483019291846401000000008211156200006457600080fd5b9083019060208201858111156200007a57600080fd5b82518660208202830111640100000000821117156200009857600080fd5b82525081516020918201928201910280838360005b83811015620000c7578181015183820152602001620000ad565b5050505090500160405250505082828260008390506000816001600160a01b031663ad5c46486040518163ffffffff1660e01b815260040160206040518083038186803b1580156200011857600080fd5b505afa1580156200012d573d6000803e3d6000fd5b505050506040513d60208110156200014457600080fd5b50516040805163c45a015560e01b815290519192506000916001600160a01b0385169163c45a0155916004808301926020929190829003018186803b1580156200018d57600080fd5b505afa158015620001a2573d6000803e3d6000fd5b505050506040513d6020811015620001b957600080fd5b5051905060005b845181101562000371576000858281518110620001d957fe5b602002602001015190506000836001600160a01b031663e6a4390583876040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b03168152602001826001600160a01b03166001600160a01b031681526020019250505060206040518083038186803b1580156200025657600080fd5b505afa1580156200026b573d6000803e3d6000fd5b505050506040513d60208110156200028257600080fd5b5051604080518082019091526002815261309960f11b60208201529091506001600160a01b038216620003365760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015620002fa578181015183820152602001620002e0565b50505050905090810190601f168015620003285780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50506001600160a01b0316600090815260208190526040902080546001600160801b0319166001600160801b038816179055600101620001c0565b506001600160601b0319606092831b811660a052911b1660805250506040516200039e92509050620004cb565b604051809103906000f080158015620003bb573d6000803e3d6000fd5b5060601b6001600160601b03191660e0524360c052604080518082019091526002815261623560f01b60208201526001600160801b038316620004415760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315620002fa578181015183820152602001620002e0565b50600081511160405180604001604052806002815260200161311b60f11b81525090620004b15760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315620002fa578181015183820152602001620002e0565b505060801b6001600160801b0319166101005250620004d9565b610d58806200277a83390190565b60805160601c60a05160601c60c05160e05160601c6101005160801c612201620005796000398061069752806108545280610da7528061105c52806110a5525080610a645280610dfa52508061082f528061089c5280610d825280610fc25280610ff852508060b052806104f752806109db52806111d352806112ac52806117d152806118025280611be35250806111b152806117af52506122016000f3fe6080604052600436106100a05760003560e01c8063900cf0cf11610064578063900cf0cf1461026e57806392cdbac514610295578063b53880a6146102da578063ba322a9214610321578063cab8924914610353578063e6ea96f814610384576100d9565b80631622dbe4146100de578063193b33a11461012357806321e7345e1461016857806338eea386146101995780637c30be4e146101fa576100d9565b366100d957336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146100d757fe5b005b600080fd5b3480156100ea57600080fd5b506100d76004803603608081101561010157600080fd5b506001600160a01b0381351690602081013590604081013590606001356103b7565b34801561012f57600080fd5b506100d76004803603608081101561014657600080fd5b506001600160a01b038135169060208101359060408101359060600135610475565b34801561017457600080fd5b5061017d610695565b604080516001600160801b039092168252519081900360200190f35b3480156101a557600080fd5b506101d4600480360360408110156101bc57600080fd5b506001600160a01b03813581169160200135166106b9565b604080519485526020850193909352838301919091526060830152519081900360800190f35b34801561020657600080fd5b506102436004803603608081101561021d57600080fd5b506001600160a01b038135811691602081013590911690604081013590606001356106e9565b6040805195865260208601949094528484019290925260608401526080830152519081900360a00190f35b34801561027a57600080fd5b5061028361089a565b60408051918252519081900360200190f35b3480156102a157600080fd5b506100d7600480360360808110156102b857600080fd5b506001600160a01b0381351690602081013590604081013590606001356108be565b3480156102e657600080fd5b5061030d600480360360208110156102fd57600080fd5b50356001600160a01b0316610940565b604080519115158252519081900360200190f35b6100d76004803603606081101561033757600080fd5b506001600160a01b03813516906020810135906040013561096a565b34801561035f57600080fd5b50610368610a62565b604080516001600160a01b039092168252519081900360200190f35b34801561039057600080fd5b5061017d600480360360208110156103a757600080fd5b50356001600160a01b0316610a86565b804281101560405180604001604052806002815260200161623160f01b815250906104605760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561042557818101518382015260200161040d565b50505050905090810190601f1680156104525780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5061046e3333878787610aa1565b5050505050565b804281101560405180604001604052806002815260200161623160f01b815250906104e15760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561042557818101518382015260200161040d565b5060006104f13330888888610c08565b905060007f00000000000000000000000000000000000000000000000000000000000000009050806001600160a01b0316632e1a7d4d836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561055e57600080fd5b505af1158015610572573d6000803e3d6000fd5b505060408051600080825260208201928390528151909450339350869290819081908082805b602083106105b75780518252601f199092019160209182019101610598565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114610619576040519150601f19603f3d011682016040523d82523d6000602084013e61061e565b606091505b505090508060405180604001604052806002815260200161311960f11b8152509061068a5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561042557818101518382015260200161040d565b505050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60016020818152600093845260408085209091529183529120805491810154600282015460039092015490919084565b6001600160a01b03808516600090815260016020818152604080842094881684529381528383209182015484518086019095526002855261188d60f21b91850191909152919283928392839283926107825760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561042557818101518382015260200161040d565b50600181015481546107ac91906107a0908a9063ffffffff610ecf16565b9063ffffffff610f3116565b95506107c981600101548260020154610f3190919063ffffffff16565b9450858811156108815760006107e5898863ffffffff610f7316565b6001600160a01b038b166000908152602081905260409020549091506001600160801b031661081387610fb5565b955061082882826001600160801b0316611057565b94506108787f0000000000000000000000000000000000000000000000000000000000000000884385857f00000000000000000000000000000000000000000000000000000000000000006110d8565b9350505061088e565b6000935060009250600091505b50945094509450945094565b7f000000000000000000000000000000000000000000000000000000000000000081565b804281101560405180604001604052806002815260200161623160f01b8152509061092a5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561042557818101518382015260200161040d565b506109383333878787610c08565b505050505050565b6001600160a01b0381166000908152602081905260409020546001600160801b031615155b919050565b804281101560405180604001604052806002815260200161623160f01b815250906109d65760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561042557818101518382015260200161040d565b5060007f000000000000000000000000000000000000000000000000000000000000000090506000349050816001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015610a3c57600080fd5b505af1158015610a50573d6000803e3d6000fd5b50505050506109383330888489610aa1565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000602081905290815260409020546001600160801b031681565b6001600160a01b038086166000908152600160209081526040808320938716835292815290829020600381015483518085019094526002845261623360f01b9284019290925291904311610b365760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561042557818101518382015260200161040d565b50436003820155600080610b4c8686868a6111a6565b84549193506001600160801b03169150610b6c908663ffffffff61174a16565b83556001830154610b83908363ffffffff61174a16565b6001840155610bac610b9b438463ffffffff610ecf16565b60028501549063ffffffff61174a16565b6002840155604080518681526020810184905280820183905290516001600160a01b0388169133917f377aadedb6b2a771959584d10a6a36eccb5f56b4eb3a48525f76108d2660d8d49181900360600190a35050505050505050565b6001600160a01b0380861660009081526001602090815260408083209387168352928152828220600381015484518086019095526002855261623360f01b928501929092529192904311610c9d5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561042557818101518382015260200161040d565b50436003820155600080610cb38787878b6117a4565b915091506000610cd884600101546107a086600001548a610ecf90919063ffffffff16565b90506000610cf785600101548660020154610f3190919063ffffffff16565b90506000610d12898760010154610f7390919063ffffffff16565b90506000838611610d24576000610d34565b610d34868563ffffffff610f7316565b9050610d498760000154838960010154611cfe565b875560028701546001880154610d6191908490611cfe565b6002880155600187018290556000610d788c610940565b15610e5a57610dcb7f00000000000000000000000000000000000000000000000000000000000000008543858a7f00000000000000000000000000000000000000000000000000000000000000006110d8565b90508015610e5a57604080516340c10f1960e01b81523360048201526024810183905290516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916340c10f1991604480830192600092919082900301818387803b158015610e4157600080fd5b505af1158015610e55573d6000803e3d6000fd5b505050505b604080518c815260208101899052808201849052606081018390526001600160801b038816608082015290516001600160a01b038e169133917f7bb7d75a26cf0ec5e66d271f759924252ed21586b985a2dbfa2e8bdaf249df499181900360a00190a350949c9b505050505050505050505050565b600082610ede57506000610f2b565b82820282848281610eeb57fe5b0414610f285760405162461bcd60e51b81526004018080602001828103825260218152602001806121ab6021913960400191505060405180910390fd5b90505b92915050565b6000610f2883836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611d14565b6000610f2883836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611d79565b600043821480610fe457507f000000000000000000000000000000000000000000000000000000000000000043145b15610ff157506000610965565b43828103907f0000000000000000000000000000000000000000000000000000000000000000900361104f61102c828063ffffffff610ecf16565b6107a0620f4240611043868063ffffffff610ecf16565b9063ffffffff610ecf16565b949350505050565b6000817f00000000000000000000000000000000000000000000000000000000000000006001600160801b03168401111561109457506000610f2b565b610f28826107a06001600160801b037f00000000000000000000000000000000000000000000000000000000000000001686830303620f424063ffffffff610ecf16565b6000836110e75750600061119c565b826001600160801b0316826001600160801b03168501111561110b5750600061119c565b8585141561111b5750600061119c565b8685141561112b5750600061119c565b6001600160801b03808316908416859003038686038887036000611168611158848063ffffffff610ecf16565b6110438a8763ffffffff610ecf16565b905061117a828063ffffffff610ecf16565b876001600160801b0316828161118c57fe5b048161119457fe5b049450505050505b9695505050505050565b6000806000806111f77f0000000000000000000000000000000000000000000000000000000000000000897f0000000000000000000000000000000000000000000000000000000000000000611dd3565b604080516370a0823160e01b815230600482018190529151939550919350849290916000916001600160a01b038d16916370a08231916024808301926020929190829003018186803b15801561124c57600080fd5b505afa158015611260573d6000803e3d6000fd5b505050506040513d602081101561127657600080fd5b5051604080516323b872dd60e01b81526001600160a01b038b811660048301528881166024830152604482018e905291519293507f0000000000000000000000000000000000000000000000000000000000000000909116916323b872dd916064808201926020929091908290030181600087803b1580156112f757600080fd5b505af115801561130b573d6000803e3d6000fd5b505050506040513d602081101561132157600080fd5b505083156114b657600080846001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561136557600080fd5b505afa158015611379573d6000803e3d6000fd5b505050506040513d606081101561138f57600080fd5b50805160209091015190925090506001600160a01b03851663022c0d9f6113c38e6001600160701b03808616908716611ef0565b60408051600080825260208201928390526001600160e01b031960e086901b16835260248201848152604483018290526001600160a01b038b166064840152608060848401908152835160a4850181905292948c949360c4850191908083838a5b8381101561143c578181015183820152602001611424565b50505050905090810190601f1680156114695780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b15801561148b57600080fd5b505af115801561149f573d6000803e3d6000fd5b505050506114ad8d82611f45565b9750505061164b565b600080846001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b1580156114f257600080fd5b505afa158015611506573d6000803e3d6000fd5b505050506040513d606081101561151c57600080fd5b50805160209091015190925090506001600160a01b03851663022c0d9f60006115528f6001600160701b03808816908716611ef0565b604080516000808252602082019092528991506040518563ffffffff1660e01b815260040180858152602001848152602001836001600160a01b03166001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b838110156115d55781810151838201526020016115bd565b50505050905090810190601f1680156116025780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b15801561162457600080fd5b505af1158015611638573d6000803e3d6000fd5b505050506116468d83611f45565b975050505b808b6001600160a01b03166370a08231846040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156116a257600080fd5b505afa1580156116b6573d6000803e3d6000fd5b505050506040513d60208110156116cc57600080fd5b5051604080518082019091526002815261613160f01b602082015291900397508988101561173b5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561042557818101518382015260200161040d565b50505050505094509492505050565b600082820183811015610f28576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000806000806117f57f0000000000000000000000000000000000000000000000000000000000000000897f0000000000000000000000000000000000000000000000000000000000000000611dd3565b91509150600082905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370a08231886040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561187657600080fd5b505afa15801561188a573d6000803e3d6000fd5b505050506040513d60208110156118a057600080fd5b505190506118af8a858b611fc6565b8215611a4e57600080836001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b1580156118f157600080fd5b505afa158015611905573d6000803e3d6000fd5b505050506040513d606081101561191b57600080fd5b50805160209091015190925090506001600160a01b03841663022c0d9f60006119518e6001600160701b03808816908716611ef0565b604080516000808252602082019092528e91506040518563ffffffff1660e01b815260040180858152602001848152602001836001600160a01b03166001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b838110156119d45781810151838201526020016119bc565b50505050905090810190601f168015611a015780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015611a2357600080fd5b505af1158015611a37573d6000803e3d6000fd5b50505050611a458c82612129565b96505050611be0565b600080836001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015611a8a57600080fd5b505afa158015611a9e573d6000803e3d6000fd5b505050506040513d6060811015611ab457600080fd5b50805160209091015190925090506001600160a01b03841663022c0d9f611ae88d6001600160701b03808616908716611ef0565b604080516000808252602082019092528d906040518563ffffffff1660e01b815260040180858152602001848152602001836001600160a01b03166001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611b6a578181015183820152602001611b52565b50505050905090810190601f168015611b975780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015611bb957600080fd5b505af1158015611bcd573d6000803e3d6000fd5b50505050611bdb8c83612129565b965050505b807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370a08231896040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015611c5757600080fd5b505afa158015611c6b573d6000803e3d6000fd5b505050506040513d6020811015611c8157600080fd5b5051604080518082019091526002815261613160f01b6020820152919003965088871015611cf05760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561042557818101518382015260200161040d565b505050505094509492505050565b600061104f826107a0868663ffffffff610ecf16565b60008183611d635760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561042557818101518382015260200161040d565b506000838581611d6f57fe5b0495945050505050565b60008184841115611dcb5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561042557818101518382015260200161040d565b505050900390565b60006001600160a01b03808316908416108481611e2857604080516bffffffffffffffffffffffff19606087811b8216602084015288901b166034820152815160288183030181526048909101909152611e62565b604080516bffffffffffffffffffffffff19606088811b8216602084015287901b1660348201528151602881830301815260489091019091525b8051906020012060405160200180806001600160f81b0319815250600101836001600160a01b03166001600160a01b031660601b8152601401828152602001807f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f815250602001925050506040516020818303038152906040528051906020012060001c9150935093915050565b600080611f05856103e563ffffffff610ecf16565b9050611f3c611f2c82611f20876103e863ffffffff610ecf16565b9063ffffffff61174a16565b6107a0858463ffffffff610ecf16565b95945050505050565b6001600160a01b0382166000908152602081905260409020546001600160801b031680611f7157610f2b565b806001600160801b0316826001600160701b03161115610f2b57506001600160a01b038216600090815260208190526040902080546001600160801b0319166001600160701b03831690811790915592915050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b178152925182516000946060949389169392918291908083835b602083106120435780518252601f199092019160209182019101612024565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146120a5576040519150601f19603f3d011682016040523d82523d6000602084013e6120aa565b606091505b50915091508180156120d85750805115806120d857508080602001905160208110156120d557600080fd5b50515b61046e576040805162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c454400604482015290519081900360640190fd5b6001600160a01b0382166000908152602081905260409020546001600160801b03168061215557610f2b565b806001600160801b0316826001600160701b03161015610f2b57506001600160a01b038216600090815260208190526040902080546001600160801b0319166001600160701b0383169081179091559291505056fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a264697066735822122002bd85187d22d72faad5afec3256b57d31a36dc664f806d22331654b7ec857ec64736f6c6343000608003360a060405234801561001057600080fd5b506040518060400160405280600781526020016656616e696c6c6160c81b8152506040518060400160405280600381526020016215939360ea1b81525081600390805190602001906100639291906100bc565b5080516100779060049060208401906100bc565b50506005805460ff19166012179055503360601b6080526100a1600c6001600160e01b036100a616565b610157565b6005805460ff191660ff92909216919091179055565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100fd57805160ff191683800117855561012a565b8280016001018555821561012a579182015b8281111561012a57825182559160200191906001019061010f565b5061013692915061013a565b5090565b61015491905b808211156101365760008155600101610140565b90565b60805160601c610be4610174600039806104b05250610be46000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c806340c10f191161007157806340c10f191461021057806370a082311461023e57806395d89b4114610264578063a457c2d71461026c578063a9059cbb14610298578063dd62ed3e146102c4576100b4565b806306fdde03146100b9578063095ea7b31461013657806318160ddd1461017657806323b872dd14610190578063313ce567146101c657806339509351146101e4575b600080fd5b6100c16102f2565b6040805160208082528351818301528351919283929083019185019080838360005b838110156100fb5781810151838201526020016100e3565b50505050905090810190601f1680156101285780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101626004803603604081101561014c57600080fd5b506001600160a01b038135169060200135610388565b604080519115158252519081900360200190f35b61017e6103a5565b60408051918252519081900360200190f35b610162600480360360608110156101a657600080fd5b506001600160a01b038135811691602081013590911690604001356103ab565b6101ce610438565b6040805160ff9092168252519081900360200190f35b610162600480360360408110156101fa57600080fd5b506001600160a01b038135169060200135610441565b61023c6004803603604081101561022657600080fd5b506001600160a01b038135169060200135610495565b005b61017e6004803603602081101561025457600080fd5b50356001600160a01b0316610571565b6100c161058c565b6101626004803603604081101561028257600080fd5b506001600160a01b0381351690602001356105ed565b610162600480360360408110156102ae57600080fd5b506001600160a01b03813516906020013561065b565b61017e600480360360408110156102da57600080fd5b506001600160a01b038135811691602001351661066f565b60038054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561037e5780601f106103535761010080835404028352916020019161037e565b820191906000526020600020905b81548152906001019060200180831161036157829003601f168201915b5050505050905090565b600061039c61039561069a565b848461069e565b50600192915050565b60025490565b60006103b884848461078a565b61042e846103c461069a565b61042985604051806060016040528060288152602001610b19602891396001600160a01b038a1660009081526001602052604081209061040261069a565b6001600160a01b03168152602081019190915260400160002054919063ffffffff6108f116565b61069e565b5060019392505050565b60055460ff1690565b600061039c61044e61069a565b84610429856001600061045f61069a565b6001600160a01b03908116825260208083019390935260409182016000908120918c16815292529020549063ffffffff61094b16565b604080518082019091526002815261633160f01b60208201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633146105625760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561052757818101518382015260200161050f565b50505050905090810190601f1680156105545780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5061056d82826109ac565b5050565b6001600160a01b031660009081526020819052604090205490565b60048054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561037e5780601f106103535761010080835404028352916020019161037e565b600061039c6105fa61069a565b8461042985604051806060016040528060258152602001610b8a602591396001600061062461069a565b6001600160a01b03908116825260208083019390935260409182016000908120918d1681529252902054919063ffffffff6108f116565b600061039c61066861069a565b848461078a565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b3390565b6001600160a01b0383166106e35760405162461bcd60e51b8152600401808060200182810382526024815260200180610b666024913960400191505060405180910390fd5b6001600160a01b0382166107285760405162461bcd60e51b8152600401808060200182810382526022815260200180610ad16022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6001600160a01b0383166107cf5760405162461bcd60e51b8152600401808060200182810382526025815260200180610b416025913960400191505060405180910390fd5b6001600160a01b0382166108145760405162461bcd60e51b8152600401808060200182810382526023815260200180610aae6023913960400191505060405180910390fd5b61081f838383610aa8565b61086281604051806060016040528060268152602001610af3602691396001600160a01b038616600090815260208190526040902054919063ffffffff6108f116565b6001600160a01b038085166000908152602081905260408082209390935590841681522054610897908263ffffffff61094b16565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600081848411156109435760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561052757818101518382015260200161050f565b505050900390565b6000828201838110156109a5576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b6001600160a01b038216610a07576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b610a1360008383610aa8565b600254610a26908263ffffffff61094b16565b6002556001600160a01b038216600090815260208190526040902054610a52908263ffffffff61094b16565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b50505056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737345524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa2646970667358221220ef0d9ad3bc1881fc99e9c8fdbc89f7e907e753946da600fd8247660aeebec2df64736f6c634300060800330000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d00000000000000000000000000000000000000000000001b1ae4d6e2ef5000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000007fc66500c84a76ad7e9c93437bfc5ac33e2ddae9000000000000000000000000ff20817765cb7f73d4bde2e66e067e58d11095c2000000000000000000000000d46ba6d942050d489dbd938a2c909a5d5039a161000000000000000000000000a117000000f279d81a1d3cc75430faa017fa5a2e0000000000000000000000001337def18c680af1f9f45cbcab6309562975b1dd0000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef000000000000000000000000c00e94cb662c3520282e6f5717214004a7f26888000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd520000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000001494ca1f11d487c2bbe4543e90080aeba4ba3c2b0000000000000000000000006810e776880c02933d47db1b9fc05908e5386b96000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca0000000000000000000000009f8f72aa9304c8b593d555f12ef6589cc3a579a2000000000000000000000000d26114cd6ee289accf82350c8d8487fedb8a0c07000000000000000000000000408e41876cccdc0f92210600ef50372656052a38000000000000000000000000d291e7a03283640fdc51b121ac401383a46cc62300000000000000000000000073968b9a57c6e53d41345fd57a6e6ae27d6cdb2f000000000000000000000000b753428af26e81097e7fd17f40c88aaa3e04902c000000000000000000000000c011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f000000000000000000000000e53ec727dbdeb9e2d5456c3be40cff031ab40a550000000000000000000000006b3595068778dd592e39a122f4f5a5cf09c90fe20000000000000000000000004c19596f5aaff459fa38b0f7ed92f11ae65437840000000000000000000000000000000000085d4780b73119b644ae5ecd22b37600000000000000000000000004fa0d235c4abf4bcf4787af4cf447de572ef8280000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f984000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000001b40183efb4dd766f11bda7a7c3ad8982e9984210000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c5990000000000000000000000000bc529c00c6401aef6d220be8c6ea1667f6ad93e

Deployed Bytecode

0x6080604052600436106100a05760003560e01c8063900cf0cf11610064578063900cf0cf1461026e57806392cdbac514610295578063b53880a6146102da578063ba322a9214610321578063cab8924914610353578063e6ea96f814610384576100d9565b80631622dbe4146100de578063193b33a11461012357806321e7345e1461016857806338eea386146101995780637c30be4e146101fa576100d9565b366100d957336001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216146100d757fe5b005b600080fd5b3480156100ea57600080fd5b506100d76004803603608081101561010157600080fd5b506001600160a01b0381351690602081013590604081013590606001356103b7565b34801561012f57600080fd5b506100d76004803603608081101561014657600080fd5b506001600160a01b038135169060208101359060408101359060600135610475565b34801561017457600080fd5b5061017d610695565b604080516001600160801b039092168252519081900360200190f35b3480156101a557600080fd5b506101d4600480360360408110156101bc57600080fd5b506001600160a01b03813581169160200135166106b9565b604080519485526020850193909352838301919091526060830152519081900360800190f35b34801561020657600080fd5b506102436004803603608081101561021d57600080fd5b506001600160a01b038135811691602081013590911690604081013590606001356106e9565b6040805195865260208601949094528484019290925260608401526080830152519081900360a00190f35b34801561027a57600080fd5b5061028361089a565b60408051918252519081900360200190f35b3480156102a157600080fd5b506100d7600480360360808110156102b857600080fd5b506001600160a01b0381351690602081013590604081013590606001356108be565b3480156102e657600080fd5b5061030d600480360360208110156102fd57600080fd5b50356001600160a01b0316610940565b604080519115158252519081900360200190f35b6100d76004803603606081101561033757600080fd5b506001600160a01b03813516906020810135906040013561096a565b34801561035f57600080fd5b50610368610a62565b604080516001600160a01b039092168252519081900360200190f35b34801561039057600080fd5b5061017d600480360360208110156103a757600080fd5b50356001600160a01b0316610a86565b804281101560405180604001604052806002815260200161623160f01b815250906104605760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561042557818101518382015260200161040d565b50505050905090810190601f1680156104525780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5061046e3333878787610aa1565b5050505050565b804281101560405180604001604052806002815260200161623160f01b815250906104e15760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561042557818101518382015260200161040d565b5060006104f13330888888610c08565b905060007f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29050806001600160a01b0316632e1a7d4d836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561055e57600080fd5b505af1158015610572573d6000803e3d6000fd5b505060408051600080825260208201928390528151909450339350869290819081908082805b602083106105b75780518252601f199092019160209182019101610598565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114610619576040519150601f19603f3d011682016040523d82523d6000602084013e61061e565b606091505b505090508060405180604001604052806002815260200161311960f11b8152509061068a5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561042557818101518382015260200161040d565b505050505050505050565b7f00000000000000000000000000000000000000000000001b1ae4d6e2ef50000081565b60016020818152600093845260408085209091529183529120805491810154600282015460039092015490919084565b6001600160a01b03808516600090815260016020818152604080842094881684529381528383209182015484518086019095526002855261188d60f21b91850191909152919283928392839283926107825760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561042557818101518382015260200161040d565b50600181015481546107ac91906107a0908a9063ffffffff610ecf16565b9063ffffffff610f3116565b95506107c981600101548260020154610f3190919063ffffffff16565b9450858811156108815760006107e5898863ffffffff610f7316565b6001600160a01b038b166000908152602081905260409020549091506001600160801b031661081387610fb5565b955061082882826001600160801b0316611057565b94506108787f0000000000000000000000000000000000000000000000000000000000b92950884385857f00000000000000000000000000000000000000000000001b1ae4d6e2ef5000006110d8565b9350505061088e565b6000935060009250600091505b50945094509450945094565b7f0000000000000000000000000000000000000000000000000000000000b9295081565b804281101560405180604001604052806002815260200161623160f01b8152509061092a5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561042557818101518382015260200161040d565b506109383333878787610c08565b505050505050565b6001600160a01b0381166000908152602081905260409020546001600160801b031615155b919050565b804281101560405180604001604052806002815260200161623160f01b815250906109d65760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561042557818101518382015260200161040d565b5060007f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290506000349050816001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015610a3c57600080fd5b505af1158015610a50573d6000803e3d6000fd5b50505050506109383330888489610aa1565b7f0000000000000000000000001017b147b05942ead495e2ad6d606ef3c94b8fd081565b6000602081905290815260409020546001600160801b031681565b6001600160a01b038086166000908152600160209081526040808320938716835292815290829020600381015483518085019094526002845261623360f01b9284019290925291904311610b365760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561042557818101518382015260200161040d565b50436003820155600080610b4c8686868a6111a6565b84549193506001600160801b03169150610b6c908663ffffffff61174a16565b83556001830154610b83908363ffffffff61174a16565b6001840155610bac610b9b438463ffffffff610ecf16565b60028501549063ffffffff61174a16565b6002840155604080518681526020810184905280820183905290516001600160a01b0388169133917f377aadedb6b2a771959584d10a6a36eccb5f56b4eb3a48525f76108d2660d8d49181900360600190a35050505050505050565b6001600160a01b0380861660009081526001602090815260408083209387168352928152828220600381015484518086019095526002855261623360f01b928501929092529192904311610c9d5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561042557818101518382015260200161040d565b50436003820155600080610cb38787878b6117a4565b915091506000610cd884600101546107a086600001548a610ecf90919063ffffffff16565b90506000610cf785600101548660020154610f3190919063ffffffff16565b90506000610d12898760010154610f7390919063ffffffff16565b90506000838611610d24576000610d34565b610d34868563ffffffff610f7316565b9050610d498760000154838960010154611cfe565b875560028701546001880154610d6191908490611cfe565b6002880155600187018290556000610d788c610940565b15610e5a57610dcb7f0000000000000000000000000000000000000000000000000000000000b929508543858a7f00000000000000000000000000000000000000000000001b1ae4d6e2ef5000006110d8565b90508015610e5a57604080516340c10f1960e01b81523360048201526024810183905290516001600160a01b037f0000000000000000000000001017b147b05942ead495e2ad6d606ef3c94b8fd016916340c10f1991604480830192600092919082900301818387803b158015610e4157600080fd5b505af1158015610e55573d6000803e3d6000fd5b505050505b604080518c815260208101899052808201849052606081018390526001600160801b038816608082015290516001600160a01b038e169133917f7bb7d75a26cf0ec5e66d271f759924252ed21586b985a2dbfa2e8bdaf249df499181900360a00190a350949c9b505050505050505050505050565b600082610ede57506000610f2b565b82820282848281610eeb57fe5b0414610f285760405162461bcd60e51b81526004018080602001828103825260218152602001806121ab6021913960400191505060405180910390fd5b90505b92915050565b6000610f2883836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611d14565b6000610f2883836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611d79565b600043821480610fe457507f0000000000000000000000000000000000000000000000000000000000b9295043145b15610ff157506000610965565b43828103907f0000000000000000000000000000000000000000000000000000000000b92950900361104f61102c828063ffffffff610ecf16565b6107a0620f4240611043868063ffffffff610ecf16565b9063ffffffff610ecf16565b949350505050565b6000817f00000000000000000000000000000000000000000000001b1ae4d6e2ef5000006001600160801b03168401111561109457506000610f2b565b610f28826107a06001600160801b037f00000000000000000000000000000000000000000000001b1ae4d6e2ef5000001686830303620f424063ffffffff610ecf16565b6000836110e75750600061119c565b826001600160801b0316826001600160801b03168501111561110b5750600061119c565b8585141561111b5750600061119c565b8685141561112b5750600061119c565b6001600160801b03808316908416859003038686038887036000611168611158848063ffffffff610ecf16565b6110438a8763ffffffff610ecf16565b905061117a828063ffffffff610ecf16565b876001600160801b0316828161118c57fe5b048161119457fe5b049450505050505b9695505050505050565b6000806000806111f77f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f897f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2611dd3565b604080516370a0823160e01b815230600482018190529151939550919350849290916000916001600160a01b038d16916370a08231916024808301926020929190829003018186803b15801561124c57600080fd5b505afa158015611260573d6000803e3d6000fd5b505050506040513d602081101561127657600080fd5b5051604080516323b872dd60e01b81526001600160a01b038b811660048301528881166024830152604482018e905291519293507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2909116916323b872dd916064808201926020929091908290030181600087803b1580156112f757600080fd5b505af115801561130b573d6000803e3d6000fd5b505050506040513d602081101561132157600080fd5b505083156114b657600080846001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561136557600080fd5b505afa158015611379573d6000803e3d6000fd5b505050506040513d606081101561138f57600080fd5b50805160209091015190925090506001600160a01b03851663022c0d9f6113c38e6001600160701b03808616908716611ef0565b60408051600080825260208201928390526001600160e01b031960e086901b16835260248201848152604483018290526001600160a01b038b166064840152608060848401908152835160a4850181905292948c949360c4850191908083838a5b8381101561143c578181015183820152602001611424565b50505050905090810190601f1680156114695780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b15801561148b57600080fd5b505af115801561149f573d6000803e3d6000fd5b505050506114ad8d82611f45565b9750505061164b565b600080846001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b1580156114f257600080fd5b505afa158015611506573d6000803e3d6000fd5b505050506040513d606081101561151c57600080fd5b50805160209091015190925090506001600160a01b03851663022c0d9f60006115528f6001600160701b03808816908716611ef0565b604080516000808252602082019092528991506040518563ffffffff1660e01b815260040180858152602001848152602001836001600160a01b03166001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b838110156115d55781810151838201526020016115bd565b50505050905090810190601f1680156116025780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b15801561162457600080fd5b505af1158015611638573d6000803e3d6000fd5b505050506116468d83611f45565b975050505b808b6001600160a01b03166370a08231846040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156116a257600080fd5b505afa1580156116b6573d6000803e3d6000fd5b505050506040513d60208110156116cc57600080fd5b5051604080518082019091526002815261613160f01b602082015291900397508988101561173b5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561042557818101518382015260200161040d565b50505050505094509492505050565b600082820183811015610f28576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000806000806117f57f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f897f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2611dd3565b91509150600082905060007f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03166370a08231886040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561187657600080fd5b505afa15801561188a573d6000803e3d6000fd5b505050506040513d60208110156118a057600080fd5b505190506118af8a858b611fc6565b8215611a4e57600080836001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b1580156118f157600080fd5b505afa158015611905573d6000803e3d6000fd5b505050506040513d606081101561191b57600080fd5b50805160209091015190925090506001600160a01b03841663022c0d9f60006119518e6001600160701b03808816908716611ef0565b604080516000808252602082019092528e91506040518563ffffffff1660e01b815260040180858152602001848152602001836001600160a01b03166001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b838110156119d45781810151838201526020016119bc565b50505050905090810190601f168015611a015780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015611a2357600080fd5b505af1158015611a37573d6000803e3d6000fd5b50505050611a458c82612129565b96505050611be0565b600080836001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015611a8a57600080fd5b505afa158015611a9e573d6000803e3d6000fd5b505050506040513d6060811015611ab457600080fd5b50805160209091015190925090506001600160a01b03841663022c0d9f611ae88d6001600160701b03808616908716611ef0565b604080516000808252602082019092528d906040518563ffffffff1660e01b815260040180858152602001848152602001836001600160a01b03166001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611b6a578181015183820152602001611b52565b50505050905090810190601f168015611b975780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015611bb957600080fd5b505af1158015611bcd573d6000803e3d6000fd5b50505050611bdb8c83612129565b965050505b807f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03166370a08231896040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015611c5757600080fd5b505afa158015611c6b573d6000803e3d6000fd5b505050506040513d6020811015611c8157600080fd5b5051604080518082019091526002815261613160f01b6020820152919003965088871015611cf05760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561042557818101518382015260200161040d565b505050505094509492505050565b600061104f826107a0868663ffffffff610ecf16565b60008183611d635760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561042557818101518382015260200161040d565b506000838581611d6f57fe5b0495945050505050565b60008184841115611dcb5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561042557818101518382015260200161040d565b505050900390565b60006001600160a01b03808316908416108481611e2857604080516bffffffffffffffffffffffff19606087811b8216602084015288901b166034820152815160288183030181526048909101909152611e62565b604080516bffffffffffffffffffffffff19606088811b8216602084015287901b1660348201528151602881830301815260489091019091525b8051906020012060405160200180806001600160f81b0319815250600101836001600160a01b03166001600160a01b031660601b8152601401828152602001807f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f815250602001925050506040516020818303038152906040528051906020012060001c9150935093915050565b600080611f05856103e563ffffffff610ecf16565b9050611f3c611f2c82611f20876103e863ffffffff610ecf16565b9063ffffffff61174a16565b6107a0858463ffffffff610ecf16565b95945050505050565b6001600160a01b0382166000908152602081905260409020546001600160801b031680611f7157610f2b565b806001600160801b0316826001600160701b03161115610f2b57506001600160a01b038216600090815260208190526040902080546001600160801b0319166001600160701b03831690811790915592915050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b178152925182516000946060949389169392918291908083835b602083106120435780518252601f199092019160209182019101612024565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146120a5576040519150601f19603f3d011682016040523d82523d6000602084013e6120aa565b606091505b50915091508180156120d85750805115806120d857508080602001905160208110156120d557600080fd5b50515b61046e576040805162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c454400604482015290519081900360640190fd5b6001600160a01b0382166000908152602081905260409020546001600160801b03168061215557610f2b565b806001600160801b0316826001600160701b03161015610f2b57506001600160a01b038216600090815260208190526040902080546001600160801b0319166001600160701b0383169081179091559291505056fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a264697066735822122002bd85187d22d72faad5afec3256b57d31a36dc664f806d22331654b7ec857ec64736f6c63430006080033

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

0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d00000000000000000000000000000000000000000000001b1ae4d6e2ef5000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000007fc66500c84a76ad7e9c93437bfc5ac33e2ddae9000000000000000000000000ff20817765cb7f73d4bde2e66e067e58d11095c2000000000000000000000000d46ba6d942050d489dbd938a2c909a5d5039a161000000000000000000000000a117000000f279d81a1d3cc75430faa017fa5a2e0000000000000000000000001337def18c680af1f9f45cbcab6309562975b1dd0000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef000000000000000000000000c00e94cb662c3520282e6f5717214004a7f26888000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd520000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000001494ca1f11d487c2bbe4543e90080aeba4ba3c2b0000000000000000000000006810e776880c02933d47db1b9fc05908e5386b96000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca0000000000000000000000009f8f72aa9304c8b593d555f12ef6589cc3a579a2000000000000000000000000d26114cd6ee289accf82350c8d8487fedb8a0c07000000000000000000000000408e41876cccdc0f92210600ef50372656052a38000000000000000000000000d291e7a03283640fdc51b121ac401383a46cc62300000000000000000000000073968b9a57c6e53d41345fd57a6e6ae27d6cdb2f000000000000000000000000b753428af26e81097e7fd17f40c88aaa3e04902c000000000000000000000000c011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f000000000000000000000000e53ec727dbdeb9e2d5456c3be40cff031ab40a550000000000000000000000006b3595068778dd592e39a122f4f5a5cf09c90fe20000000000000000000000004c19596f5aaff459fa38b0f7ed92f11ae65437840000000000000000000000000000000000085d4780b73119b644ae5ecd22b37600000000000000000000000004fa0d235c4abf4bcf4787af4cf447de572ef8280000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f984000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000001b40183efb4dd766f11bda7a7c3ad8982e9984210000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c5990000000000000000000000000bc529c00c6401aef6d220be8c6ea1667f6ad93e

-----Decoded View---------------
Arg [0] : uniswapRouter (address): 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D
Arg [1] : limit (uint128): 500000000000000000000
Arg [2] : safeList (address[]): 0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9,0xfF20817765cB7f73d4bde2e66e067E58D11095C2,0xD46bA6D942050d489DBd938a2C909A5d5039A161,0xa117000000f279D81A1D3cc75430fAA017FA5A2e,0x1337DEF18C680aF1f9f45cBcab6309562975b1dD,0x0D8775F648430679A709E98d2b0Cb6250d2887EF,0xc00e94Cb662C3520282E6f5717214004A7f26888,0xD533a949740bb3306d119CC777fa900bA034cd52,0x6B175474E89094C44Da98b954EedeAC495271d0F,0x1494CA1F11D487c2bBe4543E90080AeBa4BA3C2b,0x6810e776880C02933D47DB1b9fc05908e5386b96,0x514910771AF9Ca656af840dff83E8264EcF986CA,0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2,0xd26114cd6EE289AccF82350c8d8487fedB8A0C07,0x408e41876cCCDC0F92210600ef50372656052a38,0xD291E7a03283640FDc51b121aC401383A46cC623,0x73968b9a57c6E53d41345FD57a6E6ae27d6CDB2F,0xb753428af26E81097e7fD17f40c88aaA3E04902c,0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F,0xe53EC727dbDEB9E2d5456c3be40cFF031AB40A55,0x6B3595068778DD592e39A122f4f5a5cF09C90fE2,0x4C19596f5aAfF459fA38B0f7eD92F11AE6543784,0x0000000000085d4780B73119b644AE5ecd22b376,0x04Fa0d235C4abf4BcF4787aF4CF447DE572eF828,0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984,0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48,0xdAC17F958D2ee523a2206206994597C13D831ec7,0x1b40183EFB4Dd766f11bDa7A7c3AD8982e998421,0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599,0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e

-----Encoded View---------------
34 Constructor Arguments found :
Arg [0] : 0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d
Arg [1] : 00000000000000000000000000000000000000000000001b1ae4d6e2ef500000
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [3] : 000000000000000000000000000000000000000000000000000000000000001e
Arg [4] : 0000000000000000000000007fc66500c84a76ad7e9c93437bfc5ac33e2ddae9
Arg [5] : 000000000000000000000000ff20817765cb7f73d4bde2e66e067e58d11095c2
Arg [6] : 000000000000000000000000d46ba6d942050d489dbd938a2c909a5d5039a161
Arg [7] : 000000000000000000000000a117000000f279d81a1d3cc75430faa017fa5a2e
Arg [8] : 0000000000000000000000001337def18c680af1f9f45cbcab6309562975b1dd
Arg [9] : 0000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef
Arg [10] : 000000000000000000000000c00e94cb662c3520282e6f5717214004a7f26888
Arg [11] : 000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd52
Arg [12] : 0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f
Arg [13] : 0000000000000000000000001494ca1f11d487c2bbe4543e90080aeba4ba3c2b
Arg [14] : 0000000000000000000000006810e776880c02933d47db1b9fc05908e5386b96
Arg [15] : 000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca
Arg [16] : 0000000000000000000000009f8f72aa9304c8b593d555f12ef6589cc3a579a2
Arg [17] : 000000000000000000000000d26114cd6ee289accf82350c8d8487fedb8a0c07
Arg [18] : 000000000000000000000000408e41876cccdc0f92210600ef50372656052a38
Arg [19] : 000000000000000000000000d291e7a03283640fdc51b121ac401383a46cc623
Arg [20] : 00000000000000000000000073968b9a57c6e53d41345fd57a6e6ae27d6cdb2f
Arg [21] : 000000000000000000000000b753428af26e81097e7fd17f40c88aaa3e04902c
Arg [22] : 000000000000000000000000c011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f
Arg [23] : 000000000000000000000000e53ec727dbdeb9e2d5456c3be40cff031ab40a55
Arg [24] : 0000000000000000000000006b3595068778dd592e39a122f4f5a5cf09c90fe2
Arg [25] : 0000000000000000000000004c19596f5aaff459fa38b0f7ed92f11ae6543784
Arg [26] : 0000000000000000000000000000000000085d4780b73119b644ae5ecd22b376
Arg [27] : 00000000000000000000000004fa0d235c4abf4bcf4787af4cf447de572ef828
Arg [28] : 0000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f984
Arg [29] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [30] : 000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7
Arg [31] : 0000000000000000000000001b40183efb4dd766f11bda7a7c3ad8982e998421
Arg [32] : 0000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599
Arg [33] : 0000000000000000000000000bc529c00c6401aef6d220be8c6ea1667f6ad93e


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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