/*

XINU - The first meme coin to deploy on Xchange (Ethereum)

-A black labrador service dog for the X7 Finance's ecosystem. 

-Every dog learns tricks, our favourite trick is burying (burning) the "quints", the X7100 series of consellation tokens that act as the backstop to the lending pool.

-A meme with a dream, to contribute to the X7 Ecosystem in the best way possible, raising the floor!

WOOF WOOF

Twitter: @XINUxchange
Telegram: @XINUxchange


*/
// SPDX-License-Identifier: MIT
pragma solidity ^ 0.8.15;
pragma experimental ABIEncoderV2;

////// lib/openzeppelin-contracts/contracts/utils/Context.sol
// OpenZeppelin Contracts v4.4.0 (utils/Context.sol)

/* pragma solidity ^0.8.15; */

abstract contract Context {
  function _msgSender() internal view virtual returns(address) {
    return msg.sender;
  }

  function _msgData() internal view virtual returns(bytes calldata) {
    return msg.data;
  }
}

////// lib/openzeppelin-contracts/contracts/access/Ownable.sol
// OpenZeppelin Contracts v4.4.0 (access/Ownable.sol)

/* pragma solidity ^0.8.15; */

/* import "../utils/Context.sol"; */

abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

  constructor() {
    _transferOwnership(_msgSender());
  }

  function owner() public view virtual returns(address) {
    return _owner;
  }

    modifier onlyOwner() {
    require(owner() == _msgSender(), "Ownable: caller is not the owner");
    _;
  }

  function renounceOwnership() public virtual onlyOwner {
    _transferOwnership(address(0));
  }

  function transferOwnership(address newOwner) public virtual onlyOwner {
    require(newOwner != address(0), "Ownable: new owner is the zero address");
    _transferOwnership(newOwner);
  }

  function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
    _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
  }
}

////// lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol
// OpenZeppelin Contracts v4.4.0 (token/ERC20/IERC20.sol)

/* pragma solidity ^0.8.15; */

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);
}

////// lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol
// OpenZeppelin Contracts v4.4.0 (token/ERC20/extensions/IERC20Metadata.sol)

/* pragma solidity ^0.8.15; */

/* import "../IERC20.sol"; */

interface IERC20Metadata is IERC20 {

  function name() external view returns(string memory);

  function symbol() external view returns(string memory);

  function decimals() external view returns(uint8);
}

////// lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol
// OpenZeppelin Contracts v4.4.0 (token/ERC20/ERC20.sol)

/* pragma solidity ^0.8.15; */

/* import "./IERC20.sol"; */
/* import "./extensions/IERC20Metadata.sol"; */
/* import "../../utils/Context.sol"; */

contract ERC20 is Context, IERC20, IERC20Metadata {
  mapping(address => uint256) private _balances;

  mapping(address => mapping(address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

  constructor(string memory name_, string memory symbol_) {
    _name = name_;
    _symbol = symbol_;
  }

  function name() public view virtual override returns(string memory) {
    return _name;
  }

  function symbol() public view virtual override returns(string memory) {
    return _symbol;
  }

  function decimals() public view virtual override returns(uint8) {
    return 18;
  }

  function totalSupply() public view virtual override returns(uint256) {
    return _totalSupply;
  }

  function balanceOf(address account) public view virtual override returns(uint256) {
    return _balances[account];
  }

  function transfer(address recipient, uint256 amount) public virtual override returns(bool) {
    _transfer(_msgSender(), recipient, amount);
    return true;
  }

  function allowance(address owner, address spender) public view virtual override returns(uint256) {
    return _allowances[owner][spender];
  }

  function approve(address spender, uint256 amount) public virtual override returns(bool) {
    _approve(_msgSender(), spender, amount);
    return true;
  }

  function transferFrom(
    address sender,
    address recipient,
    uint256 amount
  ) public virtual override returns(bool) {
    _transfer(sender, recipient, amount);

        uint256 currentAllowance = _allowances[sender][_msgSender()];
    require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
        unchecked {
      _approve(sender, _msgSender(), currentAllowance - amount);
    }

    return true;
  }

  function increaseAllowance(address spender, uint256 addedValue) public virtual returns(bool) {
    _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);
    return true;
  }

  function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns(bool) {
        uint256 currentAllowance = _allowances[_msgSender()][spender];
    require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
      _approve(_msgSender(), spender, currentAllowance - subtractedValue);
    }

    return true;
  }

  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);

        uint256 senderBalance = _balances[sender];
    require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
      _balances[sender] = senderBalance - amount;
    }
    _balances[recipient] += amount;

        emit Transfer(sender, recipient, amount);

    _afterTokenTransfer(sender, recipient, amount);
  }

  function _mint(address account, uint256 amount) internal virtual {
    require(account != address(0), "ERC20: mint to the zero address");

    _beforeTokenTransfer(address(0), account, amount);

    _totalSupply += amount;
    _balances[account] += amount;
        emit Transfer(address(0), account, amount);

    _afterTokenTransfer(address(0), account, amount);
  }

  function _burn(address account, uint256 amount) internal virtual {
    require(account != address(0), "ERC20: burn from the zero address");

    _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
    require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
      _balances[account] = accountBalance - amount;
    }
    _totalSupply -= amount;

        emit Transfer(account, address(0), amount);

    _afterTokenTransfer(account, address(0), amount);
  }

  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);
  }

  function _beforeTokenTransfer(
    address from,
    address to,
    uint256 amount
  ) internal virtual { }

  function _afterTokenTransfer(
    address from,
    address to,
    uint256 amount
  ) internal virtual { }
}

////// lib/openzeppelin-contracts/contracts/utils/math/SafeMath.sol
// OpenZeppelin Contracts v4.4.0 (utils/math/SafeMath.sol)

/* pragma solidity ^0.8.15; */

library SafeMath {

  function tryAdd(uint256 a, uint256 b) internal pure returns(bool, uint256) {
        unchecked {
            uint256 c = a + b;
      if (c < a) return (false, 0);
      return (true, c);
    }
  }

  function trySub(uint256 a, uint256 b) internal pure returns(bool, uint256) {
        unchecked {
      if (b > a) return (false, 0);
      return (true, a - b);
    }
  }

  function tryMul(uint256 a, uint256 b) internal pure returns(bool, uint256) {
        unchecked {
      // 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 (true, 0);
            uint256 c = a * b;
      if (c / a != b) return (false, 0);
      return (true, c);
    }
  }

  function tryDiv(uint256 a, uint256 b) internal pure returns(bool, uint256) {
        unchecked {
      if (b == 0) return (false, 0);
      return (true, a / b);
    }
  }

  function tryMod(uint256 a, uint256 b) internal pure returns(bool, uint256) {
        unchecked {
      if (b == 0) return (false, 0);
      return (true, a % b);
    }
  }

  function add(uint256 a, uint256 b) internal pure returns(uint256) {
    return a + b;
  }

  function sub(uint256 a, uint256 b) internal pure returns(uint256) {
    return a - b;
  }

  function mul(uint256 a, uint256 b) internal pure returns(uint256) {
    return a * b;
  }

  function div(uint256 a, uint256 b) internal pure returns(uint256) {
    return a / b;
  }

  function mod(uint256 a, uint256 b) internal pure returns(uint256) {
    return a % b;
  }

  function sub(
    uint256 a,
    uint256 b,
    string memory errorMessage
  ) internal pure returns(uint256) {
        unchecked {
      require(b <= a, errorMessage);
      return a - b;
    }
  }

  function div(
    uint256 a,
    uint256 b,
    string memory errorMessage
  ) internal pure returns(uint256) {
        unchecked {
      require(b > 0, errorMessage);
      return a / b;
    }
  }

  function mod(
    uint256 a,
    uint256 b,
    string memory errorMessage
  ) internal pure returns(uint256) {
        unchecked {
      require(b > 0, errorMessage);
      return a % b;
    }
  }
}

/* pragma solidity 0.8.15; */
/* pragma experimental ABIEncoderV2; */

interface IUniswapV2Factory {
    event PairCreated(
  address indexed token0,
  address indexed token1,
  address pair,
  uint256
);

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(uint256) external view returns(address pair);

function allPairsLength() external view returns(uint256);

function createPair(address tokenA, address tokenB)
external
returns(address pair);

function setFeeTo(address) external;

function setFeeToSetter(address) external;
}

/* pragma solidity 0.8.15; */
/* pragma experimental ABIEncoderV2; */

interface IUniswapV2Pair {
    event Approval(
  address indexed owner,
  address indexed spender,
  uint256 value
);
    event Transfer(address indexed from, address indexed to, uint256 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(uint256);

function balanceOf(address owner) external view returns(uint256);

function allowance(address owner, address spender)
external
view
returns(uint256);

function approve(address spender, uint256 value) external returns(bool);

function transfer(address to, uint256 value) external returns(bool);

function transferFrom(
  address from,
  address to,
  uint256 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(uint256);

function permit(
  address owner,
  address spender,
  uint256 value,
  uint256 deadline,
  uint8 v,
  bytes32 r,
  bytes32 s
) external;

    event Mint(address indexed sender, uint256 amount0, uint256 amount1);
    event Burn(
  address indexed sender,
  uint256 amount0,
  uint256 amount1,
  address indexed to
);
    event Swap(
  address indexed sender,
  uint256 amount0In,
  uint256 amount1In,
  uint256 amount0Out,
  uint256 amount1Out,
  address indexed to
);
    event Sync(uint112 reserve0, uint112 reserve1);

function MINIMUM_LIQUIDITY() external pure returns(uint256);

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(uint256);

function price1CumulativeLast() external view returns(uint256);

function kLast() external view returns(uint256);

function mint(address to) external returns(uint256 liquidity);

function burn(address to)
external
returns(uint256 amount0, uint256 amount1);

function swap(
  uint256 amount0Out,
  uint256 amount1Out,
  address to,
  bytes calldata data
) external;

function skim(address to) external;

function sync() external;

function initialize(address, address) external;
}

/* pragma solidity 0.8.15; */
/* pragma experimental ABIEncoderV2; */

interface IUniswapV2Router02 {
    function factory() external pure returns(address);

function WETH() external pure returns(address);

function addLiquidity(
  address tokenA,
  address tokenB,
  uint256 amountADesired,
  uint256 amountBDesired,
  uint256 amountAMin,
  uint256 amountBMin,
  address to,
  uint256 deadline
)
external
returns(
  uint256 amountA,
  uint256 amountB,
  uint256 liquidity
);

function addLiquidityETH(
  address token,
  uint256 amountTokenDesired,
  uint256 amountTokenMin,
  uint256 amountETHMin,
  address to,
  uint256 deadline
)
external
payable
returns(
  uint256 amountToken,
  uint256 amountETH,
  uint256 liquidity
);

function swapExactTokensForTokensSupportingFeeOnTransferTokens(
  uint256 amountIn,
  uint256 amountOutMin,
  address[] calldata path,
  address to,
  uint256 deadline
) external;

function swapExactETHForTokensSupportingFeeOnTransferTokens(
  uint256 amountOutMin,
  address[] calldata path,
  address to,
  uint256 deadline
) external payable;

function swapExactTokensForETHSupportingFeeOnTransferTokens(
  uint256 amountIn,
  uint256 amountOutMin,
  address[] calldata path,
  address to,
  uint256 deadline
) external;
}

/* pragma solidity >=0.8.15; */

/* import {IUniswapV2Router02} from "./IUniswapV2Router02.sol"; */
/* import {IUniswapV2Factory} from "./IUniswapV2Factory.sol"; */
/* import {IUniswapV2Pair} from "./IUniswapV2Pair.sol"; */
/* import {IERC20} from "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; */
/* import {ERC20} from "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; */
/* import {Ownable} from "lib/openzeppelin-contracts/contracts/access/Ownable.sol"; */
/* import {SafeMath} from "lib/openzeppelin-contracts/contracts/utils/math/SafeMath.sol"; */

contract XINU is ERC20, Ownable {
    using SafeMath for uint256;

    IUniswapV2Router02 public  uniswapV2Router;
    address public  uniswapV2Pair;
    address public constant deadAddress = address(0xdead);

    address public x7101 = address(0x7101a9392EAc53B01e7c07ca3baCa945A56EE105);
    address public x7102 = address(0x7102DC82EF61bfB0410B1b1bF8EA74575bf0A105);
    address public x7103 = address(0x7103eBdbF1f89be2d53EFF9B3CF996C9E775c105);
    address public x7104 = address(0x7104D1f179Cc9cc7fb5c79Be6Da846E3FBC4C105);
    address public x7105 = address(0x7105FAA4a26eD1c67B8B2b41BEc98F06Ee21D105);

    bool private swapping;

    address public marketingWallet;
    address public devWallet;

    uint256 public maxTransactionAmount;
    uint256 public swapTokensAtAmount;
    uint256 public maxWallet;

    bool public limitsInEffect = true;
    bool public tradingActive = false;
    bool public swapEnabled = false;

  // Anti-bot and anti-whale mappings and variables
  mapping(address => uint256) private _holderLastTransferTimestamp; // to hold last Transfers temporarily during launch
    bool public transferDelayEnabled = false;

    uint256 public buyTotalFees;
	uint256 public buyMarketingFee;
    uint256 public buyBurnFee;
    uint256 public buyDevFee;

    uint256 public sellTotalFees;
    uint256 public sellMarketingFee;
    uint256 public sellBurnFee;
    uint256 public sellDevFee;

    uint256 public tokensForMarketing;
    uint256 public tokensForBurn;
    uint256 public tokensForDev;

  /******************/

  // exlcude from fees and max transaction amount
  mapping(address => bool) private _isExcludedFromFees;
  mapping(address => bool) public _isExcludedMaxTransactionAmount;

  // store addresses that a automatic market maker pairs. Any transfer *to* these addresses
  // could be subject to a maximum transfer amount
  mapping(address => bool) public automatedMarketMakerPairs;

    event UpdateUniswapV2Router(
    address indexed newAddress,
    address indexed oldAddress
  );

    event ExcludeFromFees(address indexed account, bool isExcluded);

    event SetAutomatedMarketMakerPair(address indexed pair, bool indexed value);

    event SwapAndLiquify(
    uint256 tokensSwapped,
    uint256 ethReceived,
    uint256 tokensIntoLiquidity
  );

  constructor() ERC20("XINU", "XINU") {
        IUniswapV2Router02 _uniswapV2Router = IUniswapV2Router02(
    0x7DE8063E9fB43321d2100e8Ddae5167F56A50060
  );

    excludeFromMaxTransaction(address(_uniswapV2Router), true);
    uniswapV2Router = _uniswapV2Router;

    uniswapV2Pair = IUniswapV2Factory(_uniswapV2Router.factory())
      .createPair(address(this), _uniswapV2Router.WETH());
    excludeFromMaxTransaction(address(uniswapV2Pair), true);
    _setAutomatedMarketMakerPair(address(uniswapV2Pair), true);

        uint256 _buyMarketingFee = 5;
        uint256 _buyBurnFee = 10;
        uint256 _buyDevFee = 5;

        uint256 _sellMarketingFee = 5;
        uint256 _sellBurnFee = 10;
        uint256 _sellDevFee = 5;

        uint256 totalSupply = 100000000 * 1e18;

    maxTransactionAmount = 2000000 * 1e18; // 2% from total supply maxTransactionAmountTxn
    maxWallet = 2000000 * 1e18; // 2% from total supply maxWallet
    swapTokensAtAmount = (totalSupply * 10) / 10000; // 0.1% swap wallet

    buyMarketingFee = _buyMarketingFee;
    buyBurnFee = _buyBurnFee;
    buyDevFee = _buyDevFee;
    buyTotalFees = buyMarketingFee + buyBurnFee + buyDevFee;

    sellMarketingFee = _sellMarketingFee;
    sellBurnFee = _sellBurnFee;
    sellDevFee = _sellDevFee;
    sellTotalFees = sellMarketingFee + sellBurnFee + sellDevFee;

    marketingWallet = address(0x78519E437F5b6051e5d09aAE9210c5b2e8Fe43C2); // set as marketing wallet
    devWallet = address(0x78d1676854F04F1C32A5965DAf9ff4083fE6Db5d); // set as dev wallet

    // exclude from paying fees or having max transaction amount
    excludeFromFees(owner(), true);
    excludeFromFees(address(this), true);
    excludeFromFees(address(0xdead), true);
    excludeFromFees(address(marketingWallet), true);
    excludeFromFees(address(devWallet), true);

    excludeFromMaxTransaction(owner(), true);
    excludeFromMaxTransaction(address(this), true);
    excludeFromMaxTransaction(address(0xdead), true);
    excludeFromMaxTransaction(address(marketingWallet), true);
    excludeFromMaxTransaction(address(devWallet), true);

    /*
        _mint is an internal function in ERC20.sol that is only called here,
        and CANNOT be called ever again
    */
    _mint(msg.sender, totalSupply);
  }

  receive() external payable { }

  function setRouter(address _newRouterAddress) external onlyOwner() {
    IUniswapV2Router02 _uniswapV2Router = IUniswapV2Router02(_newRouterAddress);
    uniswapV2Router = _uniswapV2Router;

  }
  function setPair(address _newPairAddress) external onlyOwner() {
      uniswapV2Pair = _newPairAddress;
  }

  // once enabled, can never be turned off
  function enableTrading() external onlyOwner {
    tradingActive = true;
    swapEnabled = true;
  }

  // remove limits after token is stable
  function removeLimits() external onlyOwner returns(bool) {
    limitsInEffect = false;
    return true;
  }

  // disable Transfer delay - cannot be reenabled
  function disableTransferDelay() external onlyOwner returns(bool) {
    transferDelayEnabled = false;
    return true;
  }

  // change the minimum amount of tokens to sell from fees
  function updateSwapTokensAtAmount(uint256 newAmount)
  external
  onlyOwner
  returns(bool)
  {
    require(
      newAmount >= (totalSupply() * 1) / 100000,
      "Swap amount cannot be lower than 0.001% total supply."
    );
    require(
      newAmount <= (totalSupply() * 5) / 1000,
      "Swap amount cannot be higher than 0.5% total supply."
    );
    swapTokensAtAmount = newAmount;
    return true;
  }

  function updateMaxTxnAmount(uint256 newNum) external onlyOwner {
    require(
      newNum >= ((totalSupply() * 1) / 1000) / 1e18,
      "Cannot set maxTransactionAmount lower than 0.1%"
    );
    maxTransactionAmount = newNum * (10 ** 18);
  }

  function updateMaxWalletAmount(uint256 newNum) external onlyOwner {
    require(
      newNum >= ((totalSupply() * 5) / 1000) / 1e18,
      "Cannot set maxWallet lower than 0.5%"
    );
    maxWallet = newNum * (10 ** 18);
  }

  function excludeFromMaxTransaction(address updAds, bool isEx)
  public
  onlyOwner
  {
    _isExcludedMaxTransactionAmount[updAds] = isEx;
  }

  // only use to disable contract sales if absolutely necessary (emergency use only)
  function updateSwapEnabled(bool enabled) external onlyOwner {
    swapEnabled = enabled;
  }

  function excludeFromFees(address account, bool excluded) public onlyOwner {
    _isExcludedFromFees[account] = excluded;
        emit ExcludeFromFees(account, excluded);
  }

  function setAutomatedMarketMakerPair(address pair, bool value)
  public
  onlyOwner
  {
    require(
      pair != uniswapV2Pair,
      "The pair cannot be removed from automatedMarketMakerPairs"
    );

    _setAutomatedMarketMakerPair(pair, value);
  }

  function _setAutomatedMarketMakerPair(address pair, bool value) private {
    automatedMarketMakerPairs[pair] = value;

        emit SetAutomatedMarketMakerPair(pair, value);
  }

  function isExcludedFromFees(address account) public view returns(bool) {
    return _isExcludedFromFees[account];
  }

  function _transfer(
    address from,
    address to,
    uint256 amount
  ) internal override {
    require(from != address(0), "ERC20: transfer from the zero address");
    require(to != address(0), "ERC20: transfer to the zero address");

    if (amount == 0) {
      super._transfer(from, to, 0);
      return;
    }

    if (limitsInEffect) {
      if (
        from != owner() &&
        to != owner() &&
        to != address(0) &&
        to != address(0xdead) &&
        !swapping
      ) {
        if (!tradingActive) {
          require(
            _isExcludedFromFees[from] || _isExcludedFromFees[to],
            "Trading is not active."
          );
        }

        // at launch if the transfer delay is enabled, ensure the block timestamps for purchasers is set -- during launch.
        if (transferDelayEnabled) {
          if (
            to != owner() &&
            to != address(uniswapV2Router) &&
            to != address(uniswapV2Pair)
          ) {
            require(
              _holderLastTransferTimestamp[tx.origin] <
              block.number,
              "_transfer:: Transfer Delay enabled.  Only one purchase per block allowed."
            );
            _holderLastTransferTimestamp[tx.origin] = block.number;
          }
        }

        //when buy
        if (
          automatedMarketMakerPairs[from] &&
          !_isExcludedMaxTransactionAmount[to]
        ) {
          require(
            amount <= maxTransactionAmount,
            "Buy transfer amount exceeds the maxTransactionAmount."
          );
          require(
            amount + balanceOf(to) <= maxWallet,
            "Max wallet exceeded"
          );
        }
        //when sell
        else if (
          automatedMarketMakerPairs[to] &&
          !_isExcludedMaxTransactionAmount[from]
        ) {
          require(
            amount <= maxTransactionAmount,
            "Sell transfer amount exceeds the maxTransactionAmount."
          );
        } else if (!_isExcludedMaxTransactionAmount[to]) {
          require(
            amount + balanceOf(to) <= maxWallet,
            "Max wallet exceeded"
          );
        }
      }
    }

        uint256 contractTokenBalance = balanceOf(address(this));

        bool canSwap = contractTokenBalance >= swapTokensAtAmount;

    if (
      canSwap &&
      swapEnabled &&
      !swapping &&
      !automatedMarketMakerPairs[from] &&
      !_isExcludedFromFees[from] &&
      !_isExcludedFromFees[to]
    ) {
      swapping = true;

      swapBack();

      swapping = false;
    }

        bool takeFee = !swapping;

    // if any account belongs to _isExcludedFromFee account then remove the fee
    if (_isExcludedFromFees[from] || _isExcludedFromFees[to]) {
      takeFee = false;
    }

        uint256 fees = 0;
    // only take fees on buys/sells, do not take on wallet transfers
    if (takeFee) {
      // on sell
      if (automatedMarketMakerPairs[to] && sellTotalFees > 0) {
        fees = amount.mul(sellTotalFees).div(100);
        tokensForBurn += (fees * sellBurnFee) / sellTotalFees;
        tokensForDev += (fees * sellDevFee) / sellTotalFees;
        tokensForMarketing += (fees * sellMarketingFee) / sellTotalFees;
      }
      // on buy
      else if (automatedMarketMakerPairs[from] && buyTotalFees > 0) {
        fees = amount.mul(buyTotalFees).div(100);
        tokensForBurn += (fees * buyBurnFee) / buyTotalFees;
        tokensForDev += (fees * buyDevFee) / buyTotalFees;
        tokensForMarketing += (fees * buyMarketingFee) / buyTotalFees;
      }

      if (fees > 0) {
        super._transfer(from, address(this), fees);
      }

      amount -= fees;
    }

    super._transfer(from, to, amount);
  }

  function swapTokensForEth(uint256 tokenAmount) private {
    // generate the uniswap pair path of token -> weth
    address[] memory path = new address[](2);
    path[0] = address(this);
    path[1] = uniswapV2Router.WETH();

    _approve(address(this), address(uniswapV2Router), tokenAmount);

    // make the swap
    uniswapV2Router.swapExactTokensForETHSupportingFeeOnTransferTokens(
      tokenAmount,
      0, // accept any amount of ETH
      path,
      address(this),
      block.timestamp
    );
  }

  function burnRandomQuint(uint256 ethAmount) private {
    // generate the uniswap pair path of token -> weth
    address[] memory path = new address[](2);
    address[] memory quints = new address[](5);
    quints[0] = x7101;
    quints[1] = x7102;
    quints[2] = x7103;
    quints[3] = x7104;
    quints[4] = x7105;

    uint256 mod = block.number % 5;

    path[0] = uniswapV2Router.WETH();
    path[1] = quints[mod];

    // make the swap
    uniswapV2Router.swapExactETHForTokensSupportingFeeOnTransferTokens{ value: ethAmount } (
      0,
      path,
      deadAddress,
      block.timestamp
    );
  }

  function addLiquidity(uint256 tokenAmount, uint256 ethAmount) private {
    // approve token transfer to cover all possible scenarios
    _approve(address(this), address(uniswapV2Router), tokenAmount);

    // add the liquidity
    uniswapV2Router.addLiquidityETH{ value: ethAmount } (
      address(this),
      tokenAmount,
      0, // slippage is unavoidable
      0, // slippage is unavoidable
      devWallet,
      block.timestamp
    );
  }

  function setFees(uint256 _buyMarketingFee, uint256 _buyBurnFee, uint256 _buyDevFee, uint256 _sellMarketingFee, uint256 _sellBurnFee, uint256 _sellDevFee) public onlyOwner {
    buyMarketingFee = _buyMarketingFee;
    buyBurnFee = _buyBurnFee;
    buyDevFee = _buyDevFee;
    buyTotalFees = buyMarketingFee + buyBurnFee + buyDevFee;

    sellMarketingFee = _sellMarketingFee;
    sellBurnFee = _sellBurnFee;
    sellDevFee = _sellDevFee;
    sellTotalFees = sellMarketingFee + sellBurnFee + sellDevFee;
  }


  function swapBack() private {
    uint256 contractBalance = balanceOf(address(this));
    uint256 totalTokensToSwap = tokensForBurn + tokensForMarketing + tokensForDev;
    bool success;

    if (contractBalance == 0 || totalTokensToSwap == 0) {
      return;
    }

    if (contractBalance > swapTokensAtAmount * 20) {
      contractBalance = swapTokensAtAmount * 20;
    }

    uint256 initialETHBalance = address(this).balance;

    swapTokensForEth(contractBalance);

    uint256 ethBalance = address(this).balance.sub(initialETHBalance);

    uint256 ethForMarketing = ethBalance.mul(tokensForMarketing).div(totalTokensToSwap);
    uint256 ethForDev = ethBalance.mul(tokensForDev).div(totalTokensToSwap);

    (success, ) = address(devWallet).call{ value: ethForDev } ("");
    (success, ) = address(marketingWallet).call{ value: ethForMarketing / 2 } ("");

    burnRandomQuint(address(this).balance);
  }

}