// File: miyagi.sol



// SPDX-License-Identifier: Unlicensed

// Website:
// https://aiarena.io/

// Youtube:
// https://www.youtube.com/channel/UCmWmRPFkICTZfdopcRNXj-g

/** imports **/
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol";    
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";    


pragma solidity 0.8.14;  

abstract contract Context {
      function _msgSender() internal view virtual returns (address) {
            return msg.sender;  
      }
}

interface IERC20 {
      function totalSupply() external view returns (uint256);  
      function balanceOf(address account) external view returns (uint256);  
      function transfer(address recipient, uint256 amount) external returns (bool);  
      function allowance(address owner, address spender) external view returns (uint256);  
      function approve(address spender, uint256 amount) external returns (bool);  
      function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);  
      event Transfer(address indexed from, address indexed to, uint256 value);  
      event Approval(address indexed owner, address indexed spender, uint256 value);  
}

library SafeMath {
      function add(uint256 a, uint256 b) internal pure returns (uint256) {
            uint256 c = a + b;  
            require(c >= a, "SafeMath: addition overflow!");  
            return c;  
      }

      function sub(uint256 a, uint256 b) internal pure returns (uint256) {
            return sub(a, b, "SafeMath: subtraction overflow!");  
      }

      function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            require(b <= a, errorMessage);  
            uint256 c = a - b;  
            return c;  
      }

      function mul(uint256 a, uint256 b) internal pure returns (uint256) {
            if (a == 0) {
                  return 0;  
            }
            uint256 c = a * b;  
            require(c / a == b, "SafeMath: multiplication overflow!");  
            return c;  
      }

      function div(uint256 a, uint256 b) internal pure returns (uint256) {
            return div(a, b, "SafeMath: division by zero!");  
      }

      function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            require(b > 0, errorMessage);  
            uint256 c = a / b;  
            return c;  
      }

}

contract Ownable is Context {
      address private _owner;  
      address private _previousOwner;  
      event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);  

      constructor () {
            address msgSender = _msgSender();  
            _owner = msgSender;  
            emit OwnershipTransferred(address(0), msgSender);  
      }

      function owner() public view returns (address) {
            return _owner;  
      }

      modifier onlyOwner() {
            require(_owner == _msgSender(), "Ownable: caller is not the owner!");  
            _;  
      }

      function renounceOwnership() public virtual onlyOwner {
            emit OwnershipTransferred(_owner, address(0));  
            _owner = address(0);  
      }

}

contract AIARENA is Context, IERC20, Ownable {
      using SafeMath for uint256;  

      uint256 private _feeAddr01;  
      uint256 private _feeAddr02;  
      uint256 private _taxOnLaunch;  
      uint256 private _postLaunchTax;  
      uint256 private _reduceTaxesCountdown;  
      address payable private _feeAddressWallet;  

      mapping (address => uint256) private _rOwned;  
      mapping (address => uint256) private _tOwned;  
      mapping (address => mapping (address => uint256)) private _allowances;  
      mapping (address => bool) private _isExcludedFromFee;  
      mapping (address => uint) private cooldown;  

      uint256 private constant MAX = ~uint256(0);  
      uint256 private constant _tTotal = 1_000_000_000 * 10**8;  
      uint256 private _rTotal = (MAX - (MAX % _tTotal));  
      uint256 private _tFeeTotal;  

      string private constant _name = "AI Arena";  
      string private constant _symbol = "AIA";  
      uint8 private constant _decimals = 8;  

      IUniswapV2Router02 private uniswapV2Router;  
      address private uniswapV2Pair;  
      bool private tradingOpen;  
      bool private inSwap = false;  
      bool private swapEnabled = false;  
      bool private cooldownEnabled = false;  
      uint256 public _maxTxAmount = (_tTotal * 10) / 1000;   // -- 2%
      uint256 public _maxWalletSize = (_tTotal * 20) / 1000;   // -- 2%
      event MaxTxAmountUpdated(uint _maxTxAmount);  
      modifier lockTheSwap {
            inSwap = true;  
            _;  
            inSwap = false;  
      }

      constructor () {

            _taxOnLaunch=4;  
            _postLaunchTax=2;  
            _reduceTaxesCountdown=60;  
            _feeAddressWallet = payable(_msgSender());  
            _rOwned[_msgSender()] = _rTotal;  
            _isExcludedFromFee[owner()] = true;  
            _isExcludedFromFee[address(this)] = true;  
            _isExcludedFromFee[_feeAddressWallet] = true;  
            
            emit Transfer(address(0), _msgSender(), _tTotal);  
      }

      function name() public pure returns (string memory) {
            return _name;  
      }

      function symbol() public pure returns (string memory) {
            return _symbol;  
      }

      function decimals() public pure returns (uint8) {
            return _decimals;  
      }

      function totalSupply() public pure override returns (uint256) {
            return _tTotal;  
      }

      function balanceOf(address account) public view override returns (uint256) {
            return tokenFromReflection(_rOwned[account]);  
      }

      function transfer(address recipient, uint256 amount) public override returns (bool) {
            _transfer(_msgSender(), recipient, amount);  
            return true;  
      }

      function allowance(address owner, address spender) public view override returns (uint256) {
            return _allowances[owner][spender];  
      }

      function approve(address spender, uint256 amount) public override returns (bool) {
            _approve(_msgSender(), spender, amount);  
            return true;  
      }

      function transferFrom(address sender, address recipient, uint256 amount) public override returns (bool) {
            _transfer(sender, recipient, amount);  
            _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));  
            return true;  
      }

      function setCooldownEnabled(bool onoff) external onlyOwner() {
            cooldownEnabled = onoff;  
      }

      function tokenFromReflection(uint256 rAmount) private view returns(uint256) {
            require(rAmount <= _rTotal, "Amount must be less than total reflections!");  
            uint256 currentRate =  _getRate();  
            return rAmount.div(currentRate);  
      }

      function _approve(address owner, address spender, uint256 amount) private {
            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);  
      }

      function _transfer(address from, address to, uint256 amount) private {
            require(from != address(0), "ERC20: transfer from the zero address!");  
            require(to != address(0), "ERC20: transfer to the zero address!");  
            require(amount > 0, "Transfer amount must be greater than zero!");  


            if (from != owner() && to != owner()) {
                  _feeAddr01 = 0;  
                  _feeAddr02 = (_reduceTaxesCountdown==0)?_postLaunchTax:_taxOnLaunch;  
                  if (from == uniswapV2Pair && to != address(uniswapV2Router) && ! _isExcludedFromFee[to] && cooldownEnabled) {
                        // Cooldown 
                        require(amount <= _maxTxAmount, "Exceeds the _maxTxAmount!");  
                        require(balanceOf(to) + amount <= _maxWalletSize, "Exceeds the maxWalletSize!");  
                        if(_reduceTaxesCountdown>0){_reduceTaxesCountdown--;  }
                  }


                  uint256 contractTokenBalance = balanceOf(address(this));  
                  if (!inSwap && from != uniswapV2Pair && swapEnabled && contractTokenBalance>0 && _reduceTaxesCountdown<5) {
                        swapTokensForEth(contractTokenBalance);  
                        uint256 contractETHBalance = address(this).balance;  
                        if(contractETHBalance > 0) {
                              sendETHToFee(address(this).balance);  
                        }
                  }
            }else{
              _feeAddr01 = 0;  
              _feeAddr02 = 0;  
            }

            _tokenTransfer(from,to,amount);  
      }

      function swapTokensForEth(uint256 tokenAmount) private lockTheSwap {
            address[] memory path = new address[](2);  
            path[0] = address(this);  
            path[1] = uniswapV2Router.WETH();  
            _approve(address(this), address(uniswapV2Router), tokenAmount);  
            uniswapV2Router.swapExactTokensForETHSupportingFeeOnTransferTokens(
                  tokenAmount,
                  0,
                  path,
                  address(this),
                  block.timestamp
            );  
      }


      function removeSwapLimits() external onlyOwner{
            _maxTxAmount = _tTotal;  
            _maxWalletSize = _tTotal;  
      }

      function sendETHToFee(uint256 amount) private {
            _feeAddressWallet.transfer(amount);  
      }

      function openTrading() external onlyOwner() {
            require(!tradingOpen,"trading is already open!");  
            IUniswapV2Router02 _uniswapV2Router = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);  
            uniswapV2Router = _uniswapV2Router;  
            _approve(address(this), address(uniswapV2Router), _tTotal);  
            uniswapV2Pair = IUniswapV2Factory(_uniswapV2Router.factory()).createPair(address(this), _uniswapV2Router.WETH());  
            uniswapV2Router.addLiquidityETH{value: address(this).balance}(address(this),balanceOf(address(this)),0,0,owner(),block.timestamp);  
            swapEnabled = true;  
            cooldownEnabled = true;  

            tradingOpen = true;  
            IERC20(uniswapV2Pair).approve(address(uniswapV2Router), type(uint).max);  
      }

      function _tokenTransfer(address sender, address recipient, uint256 amount) private {
            _transferStandard(sender, recipient, amount);  
      }

      function _transferStandard(address sender, address recipient, uint256 tAmount) private {
            (uint256 rAmount, uint256 rTransferAmount, uint256 rFee, uint256 tTransferAmount, uint256 tFee, uint256 tTeam) = _getValues(tAmount);  
            _rOwned[sender] = _rOwned[sender].sub(rAmount);  
            _rOwned[recipient] = _rOwned[recipient].add(rTransferAmount);  
            _feeTeam(tTeam);  
            _feeReflect(rFee, tFee);  
            emit Transfer(sender, recipient, tTransferAmount);  
      }

      function _feeTeam(uint256 tTeam) private {
            uint256 currentRate =  _getRate();  
            uint256 rTeam = tTeam.mul(currentRate);  
            _rOwned[address(this)] = _rOwned[address(this)].add(rTeam);  
      }

      function _feeReflect(uint256 rFee, uint256 tFee) private {
            _rTotal = _rTotal.sub(rFee);  
            _tFeeTotal = _tFeeTotal.add(tFee);  
      }

      receive() external payable {}

      function manualSwap() external {
            require(_msgSender() == _feeAddressWallet);  
            uint256 contractBalance = balanceOf(address(this));  
            swapTokensForEth(contractBalance);  
      }

      function manualSend() external {
            require(_msgSender() == _feeAddressWallet);  
            uint256 contractETHBalance = address(this).balance;  
            sendETHToFee(contractETHBalance);  
      }


      function _getValues(uint256 tAmount) private view returns (uint256, uint256, uint256, uint256, uint256, uint256) {
            (uint256 tTransferAmount, uint256 tFee, uint256 tTeam) = _getTValues(tAmount, _feeAddr01, _feeAddr02);  
            uint256 currentRate =  _getRate();  
            (uint256 rAmount, uint256 rTransferAmount, uint256 rFee) = _getRValues(tAmount, tFee, tTeam, currentRate);  
            return (rAmount, rTransferAmount, rFee, tTransferAmount, tFee, tTeam);  
      }

      function _getTValues(uint256 tAmount, uint256 taxFee, uint256 TeamFee) private pure returns (uint256, uint256, uint256) {
            uint256 tFee = tAmount.mul(taxFee).div(100);  
            uint256 tTeam = tAmount.mul(TeamFee).div(100);  
            uint256 tTransferAmount = tAmount.sub(tFee).sub(tTeam);  
            return (tTransferAmount, tFee, tTeam);  
      }

      function _getRValues(uint256 tAmount, uint256 tFee, uint256 tTeam, uint256 currentRate) private pure returns (uint256, uint256, uint256) {
            uint256 rAmount = tAmount.mul(currentRate);  
            uint256 rFee = tFee.mul(currentRate);  
            uint256 rTeam = tTeam.mul(currentRate);  
            uint256 rTransferAmount = rAmount.sub(rFee).sub(rTeam);  
            return (rAmount, rTransferAmount, rFee);  
      }

	function _getRate() private view returns(uint256) {
            (uint256 rSupply, uint256 tSupply) = _getCurrentSupply();  
            return rSupply.div(tSupply);  
      }

      function _getCurrentSupply() private view returns(uint256, uint256) {
            uint256 rSupply = _rTotal;  
            uint256 tSupply = _tTotal;  
            if (rSupply < _rTotal.div(_tTotal)) return (_rTotal, _tTotal);  
            return (rSupply, tSupply);  
      }
}
// File: @uniswap/v2-periphery/contracts/interfaces/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: @uniswap/v2-core/contracts/interfaces/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: @uniswap/v2-periphery/contracts/interfaces/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);
}