// File: kmining.sol



/*

Keep Mining

Keep Mining is a rewards incentivizing dapp, mining:validator protocol, 
and movement with the core agenda to "keep mining and carry on". 

https://keepmining.org/

*/

// SPDX-License-Identifier: Unlicensed
pragma solidity ^0.8.11;

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
   );
}

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);
   }

   function transferOwnership(address newOwner) public virtual onlyOwner {
      require(newOwner != address(0), "Ownable: new owner is the zero address");
      emit OwnershipTransferred(_owner, newOwner);
      _owner = newOwner;
   }

}

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;
   }
}

interface IUniswapV2Factory {
   function createPair(address tokenA, address tokenB)
      external
      returns (address pair);
}

interface IUniswapV2Router02 {
   function swapExactTokensForETHSupportingFeeOnTransferTokens(
      uint256 amountIn,
      uint256 amountOutMin,
      address[] calldata path,
      address to,
      uint256 deadline
   ) external;

   function factory() external pure returns (address);

   function WETH() external pure returns (address);

   function addLiquidityETH(
      address token,
      uint256 amountTokenDesired,
      uint256 amountTokenMin,
      uint256 amountETHMin,
      address to,
      uint256 deadline
   )
      external
      payable
      returns (
         uint256 amountToken,
         uint256 amountETH,
         uint256 liquidity
      );
}


contract KeepMining is Context, IERC20, Ownable {

   using SafeMath for uint256;

   string private constant _name = "Keep Mining";
   string private constant _symbol = "KMINING";
   uint8 private constant _decimals = 9;

   mapping(address => uint256) private _rOwned;
   mapping(address => uint256) private _tOwned;
   mapping(address => mapping(address => uint256)) private _allowances;
   mapping(address => bool) private _isExcludedFromFee;
   uint256 private constant MAX = ~uint256(0);
   uint256 private constant _tTotal = 100000000 * 10**9;
   uint256 private _rTotal = (MAX - (MAX % _tTotal));
   uint256 private _tFeeTotal;
   uint256 private _ProtocolFeeOnBuy = 0;
   uint256 private _taxFeeOnBuy = 2;
   uint256 private _ProtocolFeeOnSell = 0;
   uint256 private _taxFeeOnSell = 2;

   //Original Fee
   uint256 private _ProtocolFee = _ProtocolFeeOnSell;
   uint256 private _taxFee = _taxFeeOnSell;

   uint256 private _previousProtocolFee = _ProtocolFee;
   uint256 private _previoustaxFee = _taxFee;

   mapping (address => uint256) public _buyMap;
   address payable private _developmentAddress = payable(0x97B5e720f246E38E2eFA925633fe64c721FC949C);
   address payable private _marketingAddress = payable(0x97B5e720f246E38E2eFA925633fe64c721FC949C);

   IUniswapV2Router02 public uniswapV2Router;
   address public uniswapV2Pair;

   bool private tradingOpen = false;
   bool private inSwap = false;
   bool private swapEnabled = true;

   uint256 public _maxTxAmount = 1000000 * 10**9;
   uint256 public _maxWalletSize = 3000000 * 10**9;
   uint256 public _swapTokensAtAmount = 10000 * 10**9;

   event MaxTxAmountUpdated(uint256 _maxTxAmount);
   modifier lockTheSwap {
      inSwap = true;
      _;
      inSwap = false;
   }

   constructor() {

      _rOwned[_msgSender()] = _rTotal;

      IUniswapV2Router02 _uniswapV2Router = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);//
      uniswapV2Router = _uniswapV2Router;
      uniswapV2Pair = IUniswapV2Factory(_uniswapV2Router.factory())
         .createPair(address(this), _uniswapV2Router.WETH());

      _isExcludedFromFee[owner()] = true;
      _isExcludedFromFee[address(this)] = true;
      _isExcludedFromFee[_developmentAddress] = true;
      _isExcludedFromFee[_marketingAddress] = 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 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 removeAllFee() private {
      if (_ProtocolFee == 0 && _taxFee == 0) return;

      _previousProtocolFee = _ProtocolFee;
      _previoustaxFee = _taxFee;

      _ProtocolFee = 0;
      _taxFee = 0;
   }

   function restoreAllFee() private {
      _ProtocolFee = _previousProtocolFee;
      _taxFee = _previoustaxFee;
   }

   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()) {

         //Trade start check
         if (!tradingOpen) {
            require(from == owner(), "TOKEN: This account cannot send tokens until trading is enabled");
         }

         require(amount <= _maxTxAmount, "TOKEN: Max Transaction Limit");

         if(to != uniswapV2Pair) {
            require(balanceOf(to) + amount < _maxWalletSize, "TOKEN: Balance exceeds wallet size!");
         }

         uint256 contractTokenBalance = balanceOf(address(this));
         bool canSwap = contractTokenBalance >= _swapTokensAtAmount;

         if(contractTokenBalance >= _maxTxAmount)
         {
            contractTokenBalance = _maxTxAmount;
         }

         if (canSwap && !inSwap && from != uniswapV2Pair && swapEnabled && !_isExcludedFromFee[from] && !_isExcludedFromFee[to]) {
            swapTokensForEth(contractTokenBalance);
            uint256 contractETHBalance = address(this).balance;
            if (contractETHBalance > 0) {
               sendETHToFee(address(this).balance);
            }
         }
      }

      bool takeFee = true;

      //Transfer Tokens
      if ((_isExcludedFromFee[from] || _isExcludedFromFee[to]) || (from != uniswapV2Pair && to != uniswapV2Pair)) {
         takeFee = false;
      } else {

         //Set Fee for Buys
         if(from == uniswapV2Pair && to != address(uniswapV2Router)) {
            _ProtocolFee = _ProtocolFeeOnBuy;
            _taxFee = _taxFeeOnBuy;
         }

         //Set Fee for Sells
         if (to == uniswapV2Pair && from != address(uniswapV2Router)) {
            _ProtocolFee = _ProtocolFeeOnSell;
            _taxFee = _taxFeeOnSell;
         }

      }

      _tokenTransfer(from, to, amount, takeFee);
   }

   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 sendETHToFee(uint256 amount) private {
      _marketingAddress.transfer(amount);
   }

   function enableTrading() public onlyOwner {
      tradingOpen = true;
   }

   function manualswap() external {
      require(_msgSender() == _developmentAddress || _msgSender() == _marketingAddress);
      uint256 contractBalance = balanceOf(address(this));
      swapTokensForEth(contractBalance);
   }

   function manualsend() external {
      require(_msgSender() == _developmentAddress || _msgSender() == _marketingAddress);
      uint256 contractETHBalance = address(this).balance;
      sendETHToFee(contractETHBalance);
   }


   function _tokenTransfer(
      address sender,
      address recipient,
      uint256 amount,
      bool takeFee
   ) private {
      if (!takeFee) removeAllFee();
      _transferStandard(sender, recipient, amount);
      if (!takeFee) restoreAllFee();
   }

   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);
      _takeTeam(tTeam);
      _reflectFee(rFee, tFee);
      emit Transfer(sender, recipient, tTransferAmount);
   }

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

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

   receive() external payable {}

   function _getValues(uint256 tAmount)
      private
      view
      returns (
         uint256,
         uint256,
         uint256,
         uint256,
         uint256,
         uint256
      )
   {
      (uint256 tTransferAmount, uint256 tFee, uint256 tTeam) =
         _getTValues(tAmount, _ProtocolFee, _taxFee);
      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 ProtocolFee,
      uint256 taxFee
   )
      private
      pure
      returns (
         uint256,
         uint256,
         uint256
      )
   {
      uint256 tFee = tAmount.mul(ProtocolFee).div(100);
      uint256 tTeam = tAmount.mul(taxFee).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);
   }

   function setFee(uint256 ProtocolFeeOnBuy, uint256 ProtocolFeeOnSell, uint256 taxFeeOnBuy, uint256 taxFeeOnSell) public onlyOwner {
      require(ProtocolFeeOnBuy + taxFeeOnBuy < 5, "Low buy fees only");
      require(ProtocolFeeOnSell + taxFeeOnSell < 5, "Low sell fees only");
      _ProtocolFeeOnBuy = ProtocolFeeOnBuy;
      _ProtocolFeeOnSell = ProtocolFeeOnSell;
      _taxFeeOnBuy = taxFeeOnBuy;
      _taxFeeOnSell = taxFeeOnSell;
   }

   //Set minimum tokens required to swap.
   function setMinSwapTokensThreshold(uint256 swapTokensAtAmount) public onlyOwner {
      _swapTokensAtAmount = swapTokensAtAmount;
   }

   //Set maximum transaction
   function setMaxTxnAmount(uint256 maxTxAmount) public onlyOwner {
      require(maxTxAmount > _maxTxAmount, "New value must be greater than the last");
      _maxTxAmount = maxTxAmount;
   }

   function setMaxWalletSize(uint256 maxWalletSize) public onlyOwner {
      require(maxWalletSize > _maxWalletSize, "New value must be greater than the last");
      _maxWalletSize = maxWalletSize;
   }

   function excludeMultipleAccountsFromFees(address[] calldata accounts, bool excluded) public onlyOwner {
      for(uint256 i = 0; i < accounts.length; i++) {
         _isExcludedFromFee[accounts[i]] = excluded;
      }
   }

}