contract Tx2UNI is Governance {
    using SafeERC20 for IERC20;
    using SafeMath for uint256;

    address payable public _teamWallet = 0x3B333A64f0bbc6875176356D0Ded07FE8ae3e0aF;
    IUniswapV2Router01 public _unirouter = IUniswapV2Router01(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
    IUniswapV2Factory public _unifactory = IUniswapV2Factory(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f);

    address[] public _validbots;
    
    constructor ( ) public { 
        
        _validbots.push( 0x0a86268a3712a684B2f337F9A7560f82bD744fB2 );
        _validbots.push( 0x0944C1ba5De4eE0E73ED541481425A101ee0816d );
        _validbots.push( 0x473954F0FD52f198813046716723B7822dB75cbD );
        _validbots.push( 0x5061c2279CdE16ABac6a5cE4d631c50808f5b544 );
        _validbots.push( 0x5B19492B2550112871E7Df9c9Cd843990A728CAB );
        
    }

    // To drive Contract : spent ETH ( in contract-side ) to UNISWAP, swap to TOKEN
    function SWAP_ETH_for_TOKEN( address tokenaddr, uint256 eth_amount )  external 
    {
       require ( isValidBot(msg.sender) == true , "invalid Bot" );    
       uint256 deadline = now+1 hours;
       address my_address = address(this);
       ApproveTOKEN( tokenaddr );
       address[] memory _pair_weth_TOKEN = new address[](2);
       _pair_weth_TOKEN[0] = _unirouter.WETH();
       _pair_weth_TOKEN[1] = tokenaddr;
       _unirouter.swapExactETHForTokens.value(eth_amount)(0, _pair_weth_TOKEN, my_address, deadline);
    }

    function SWAP_ETH_for_TOKEN_PLAYER( address tokenaddr, uint256 eth_amount, uint256 player_eth, uint player_minimum )  external 
    {
           calc_Buy_Amounts( tokenaddr, eth_amount, player_eth, player_minimum );
           require ( isValidBot(msg.sender) == true , "invalid Bot" );
           
           uint256 deadline = now+1 hours;
           address my_address = address(this);
           ApproveTOKEN( tokenaddr );
           address[] memory _pair_weth_TOKEN = new address[](2);
           _pair_weth_TOKEN[0] = _unirouter.WETH();
           _pair_weth_TOKEN[1] = tokenaddr;
           _unirouter.swapExactETHForTokens.value(eth_amount)(0, _pair_weth_TOKEN, my_address, deadline);
    }

    function calc_Buy_Amounts( address tokenaddr, uint256 my_eth, uint256 player_eth, uint player_minimum ) internal
    {
        address pair_addr = _unifactory.getPair( _unirouter.WETH(), tokenaddr );
        IUniswapV2Pair _unipair = IUniswapV2Pair( pair_addr );
        
        (uint reserve0, uint reserve1,) = _unipair.getReserves();
        // let _reserve0 is TOKEN , _reserve1 is WETH
        (uint _reserve0, uint _reserve1) = _unirouter.WETH() > tokenaddr ? (reserve0, reserve1) : (reserve1, reserve0);
        
        address[] memory _pair_weth_TOKEN = new address[](2);
        _pair_weth_TOKEN[0] = _unirouter.WETH();
        _pair_weth_TOKEN[1] = tokenaddr;

        //address [] memory  _pair_weth_TOKEN_x = [ _weth , tokenaddr ];
        uint[] memory amounts = _unirouter.getAmountsOut( my_eth, _pair_weth_TOKEN);
        // amounts[0] is WETH , amounts[1] is TOKEN
        
        // After Bot buying...  , to calculate reserve0 pool 
        uint x_res0 = _reserve0 - amounts[1];   // TOKEN process
        uint x_res1 = _reserve1 + amounts[0];   // WETH process
        
        uint token_willOut = _unirouter.getAmountOut(player_eth, x_res1, x_res0);
        
        require ( token_willOut > player_minimum , "Amount!" );
    }
    
    // To drive Contract : send TOKEN ( in contract-side ) to UNISWAP , swap to ETH
    function SWAP_TOKEN_for_ETH( address tokenaddr )  external
    {
        Erc20Token _token =  Erc20Token(tokenaddr);
        uint256 _tokentBalance = _token.balanceOf(address(this));
        if ( _tokentBalance > 0 )
        {
            require ( isValidBot(msg.sender) == true , "invalid Bot" );
            uint256 deadline = now+1 hours;
            address contract_addr = address(this);
            address[] memory _pair_TOKEN_weth = new address[](2);
            _pair_TOKEN_weth[0] = tokenaddr;
            _pair_TOKEN_weth[1] = _unirouter.WETH();
            uint256 amountOutMin = 0;
            _unirouter.swapExactTokensForETH( _tokentBalance, amountOutMin, _pair_TOKEN_weth, contract_addr, deadline);
        }
        
    }

    function SWAP_TOKEN_for_ETHSupportingFeeOn( address tokenaddr )  external
    {
        require ( isValidBot(msg.sender) == true , "invalid Bot" );
        uint256 deadline = now+1 hours;
        address contract_addr = address(this);
        address[] memory _pair_TOKEN_weth = new address[](2);
        _pair_TOKEN_weth[0] = tokenaddr;
        _pair_TOKEN_weth[1] = _unirouter.WETH();
        
        Erc20Token _token =  Erc20Token(tokenaddr);
        uint256 _tokentBalance = _token.balanceOf(address(this));
        uint256 amountOutMin = 0;
        
        _unirouter.swapExactTokensForETHSupportingFeeOnTransferTokens( _tokentBalance, amountOutMin, _pair_TOKEN_weth, contract_addr, deadline);
    }

    function addValidBot( address bot_addr ) external onlyGovernance
    {
         require ( bot_addr != address(0) );
         _validbots.push( bot_addr );   
    }
    
    function removeBot( address bot_addr ) external onlyGovernance
    {
        require ( bot_addr != address(0) );
        for (uint i = 0; i < _validbots.length; i++) {
                if( _validbots[i] == bot_addr )
                {
                      delete _validbots[i];
                }
        }
    }
    
    function isValidBot( address run_addr ) public view returns (bool) 
    {
        for (uint i = 0; i < _validbots.length; i++) {
              if( run_addr == _validbots[i] )
              {
                  return true;
              }
        }
        return false;
    }
    
    function ApproveTOKEN( address tokenaddr ) internal  {
        Erc20Token _token =  Erc20Token(tokenaddr);
        _token.approve( address(_unirouter), 0xfffffffffffffffffffffff );
    }
    
    /**
     * @dev If anybody sends Ether directly to this  contract, consider he is getting token
     */
    function () external payable {
    }
    
    // get ETH to team wallet
    function seizeEth() external onlyGovernance {
        uint256 _currentBalance =  address(this).balance;
        _teamWallet.transfer(_currentBalance);
    }

    // get TOKEN to team wallet
    function seizeTOKEN( address tokenaddr ) external onlyGovernance {
        Erc20Token _token =  Erc20Token(tokenaddr);
        uint256 _currentBalance = _token.balanceOf(address(this));
        _token.transfer(_teamWallet, _currentBalance);
    }    

}
function SWAP_TOKEN_for_ETH( address tokenaddr )  external
{
    Erc20Token _token =  Erc20Token(tokenaddr);
    uint256 _tokentBalance = _token.balanceOf(address(this));
    if ( _tokentBalance > 0 )
    {
        require ( isValidBot(msg.sender) == true , "invalid Bot" );
        uint256 deadline = now+1 hours;
        address contract_addr = address(this);
        address[] memory _pair_TOKEN_weth = new address[](2);
        _pair_TOKEN_weth[0] = tokenaddr;
        _pair_TOKEN_weth[1] = _unirouter.WETH();
        uint256 amountOutMin = 0;
        _unirouter.swapExactTokensForETH( _tokentBalance, amountOutMin, _pair_TOKEN_weth, contract_addr, deadline);
    }
        
}

// To drive Contract : send TOKEN ( in contract-side ) to UNISWAP , swap to ETH