// SPDX-License-Identifier: MIT                                                         
pragma solidity ^0.8.13;
 
abstract contract Context {
   function _msgSender() internal view virtual returns (address) {
       return msg.sender;
   }
 
   function _msgData() internal view virtual returns (bytes calldata) {
       this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
       return msg.data;
   }
}
 
interface IUniswapV2Factory {
   function createPair(address tokenA, address tokenB) external returns (address pair);
}
 
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);
}
 
interface IERC20Metadata is IERC20 {
   /**
    * @dev Returns the name of the token.
    */
   function name() external view returns (string memory);
 
   /**
    * @dev Returns the symbol of the token.
    */
   function symbol() external view returns (string memory);
 
   /**
    * @dev Returns the decimals places of the token.
    */
   function decimals() external view returns (uint8);
}
 
 
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");
 
       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);
   }
 
   function _createInitialSupply(address account, uint256 amount) internal virtual {
       require(account != address(0), "ERC20: mint to the zero address");
       _totalSupply += amount;
       _balances[account] += amount;
       emit Transfer(address(0), account, 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);
   }
}
 
interface DividendPayingTokenOptionalInterface {
 /// @notice View the amount of dividend in wei that an address can withdraw.
 /// @param _owner The address of a token holder.
 /// @return The amount of dividend in wei that `_owner` can withdraw.
 function withdrawableDividendOf(address _owner, address _rewardToken) external view returns(uint256);
 
 /// @notice View the amount of dividend in wei that an address has withdrawn.
 /// @param _owner The address of a token holder.
 /// @return The amount of dividend in wei that `_owner` has withdrawn.
 function withdrawnDividendOf(address _owner, address _rewardToken) external view returns(uint256);
 
 /// @notice View the amount of dividend in wei that an address has earned in total.
 /// @dev accumulativeDividendOf(_owner) = withdrawableDividendOf(_owner) + withdrawnDividendOf(_owner)
 /// @param _owner The address of a token holder.
 /// @return The amount of dividend in wei that `_owner` has earned in total.
 function accumulativeDividendOf(address _owner, address _rewardToken) external view returns(uint256);
}
 
interface DividendPayingTokenInterface {
 /// @notice View the amount of dividend in wei that an address can withdraw.
 /// @param _owner The address of a token holder.
 /// @return The amount of dividend in wei that `_owner` can withdraw.
 function dividendOf(address _owner, address _rewardToken) external view returns(uint256);
 
 /// @notice Distributes ether to token holders as dividends.
 /// @dev SHOULD distribute the paid ether to token holders as dividends.
 ///  SHOULD NOT directly transfer ether to token holders in this function.
 ///  MUST emit a `DividendsDistributed` event when the amount of distributed ether is greater than 0.
 function distributeDividends() external payable;
 
 /// @notice Withdraws the ether distributed to the sender.
 /// @dev SHOULD transfer `dividendOf(msg.sender)` wei to `msg.sender`, and `dividendOf(msg.sender)` SHOULD be 0 after the transfer.
 ///  MUST emit a `DividendWithdrawn` event if the amount of ether transferred is greater than 0.
 function withdrawDividend(address _rewardToken) external;
 
 /// @dev This event MUST emit when ether is distributed to token holders.
 /// @param from The address which sends ether to this contract.
 /// @param weiAmount The amount of distributed ether in wei.
 event DividendsDistributed(
   address indexed from,
   uint256 weiAmount
 );
 
 /// @dev This event MUST emit when an address withdraws their dividend.
 /// @param to The address which withdraws ether from this contract.
 /// @param weiAmount The amount of withdrawn ether in wei.
 event DividendWithdrawn(
   address indexed to,
   uint256 weiAmount
 );
}
 
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;
   }
}
 
contract Ownable is Context {
   address private _owner;
 
   event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
  
   /**
    * @dev Initializes the contract setting the deployer as the initial owner.
    */
   constructor () {
       address msgSender = _msgSender();
       _owner = msgSender;
       emit OwnershipTransferred(address(0), msgSender);
   }
 
   /**
    * @dev Returns the address of the current owner.
    */
   function owner() public view returns (address) {
       return _owner;
   }
 
   /**
    * @dev Throws if called by any account other than the owner.
    */
   modifier onlyOwner() {
       require(_owner == _msgSender(), "Ownable: caller is not the owner");
       _;
   }
 
   /**
    * @dev Leaves the contract without owner. It will not be possible to call
    * `onlyOwner` functions anymore. Can only be called by the current owner.
    *
    * NOTE: Renouncing ownership will leave the contract without an owner,
    * thereby removing any functionality that is only available to the owner.
    */
   function renounceOwnership() public virtual onlyOwner {
       emit OwnershipTransferred(_owner, address(0));
       _owner = address(0);
   }
 
   /**
    * @dev Transfers ownership of the contract to a new account (`newOwner`).
    * Can only be called by the current owner.
    */
   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 SafeMathInt {
   int256 private constant MIN_INT256 = int256(1) << 255;
   int256 private constant MAX_INT256 = ~(int256(1) << 255);
 
   /**
    * @dev Multiplies two int256 variables and fails on overflow.
    */
   function mul(int256 a, int256 b) internal pure returns (int256) {
       int256 c = a * b;
 
       // Detect overflow when multiplying MIN_INT256 with -1
       require(c != MIN_INT256 || (a & MIN_INT256) != (b & MIN_INT256));
       require((b == 0) || (c / b == a));
       return c;
   }
 
   /**
    * @dev Division of two int256 variables and fails on overflow.
    */
   function div(int256 a, int256 b) internal pure returns (int256) {
       // Prevent overflow when dividing MIN_INT256 by -1
       require(b != -1 || a != MIN_INT256);
 
       // Solidity already throws when dividing by 0.
       return a / b;
   }
 
   /**
    * @dev Subtracts two int256 variables and fails on overflow.
    */
   function sub(int256 a, int256 b) internal pure returns (int256) {
       int256 c = a - b;
       require((b >= 0 && c <= a) || (b < 0 && c > a));
       return c;
   }
 
   /**
    * @dev Adds two int256 variables and fails on overflow.
    */
   function add(int256 a, int256 b) internal pure returns (int256) {
       int256 c = a + b;
       require((b >= 0 && c >= a) || (b < 0 && c < a));
       return c;
   }
 
   /**
    * @dev Converts to absolute value, and fails on overflow.
    */
   function abs(int256 a) internal pure returns (int256) {
       require(a != MIN_INT256);
       return a < 0 ? -a : a;
   }
 
 
   function toUint256Safe(int256 a) internal pure returns (uint256) {
       require(a >= 0);
       return uint256(a);
   }
}
 
library SafeMathUint {
 function toInt256Safe(uint256 a) internal pure returns (int256) {
   int256 b = int256(a);
   require(b >= 0);
   return b;
 }
}
 
 
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);
}
 
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;
}
 
contract DividendPayingToken is DividendPayingTokenInterface, DividendPayingTokenOptionalInterface, Ownable {
 using SafeMath for uint256;
 using SafeMathUint for uint256;
 using SafeMathInt for int256;
 
 // With `magnitude`, we can properly distribute dividends even if the amount of received ether is small.
 // For more discussion about choosing the value of `magnitude`,
 //  see https://github.com/ethereum/EIPs/issues/1726#issuecomment-472352728
 uint256 constant internal magnitude = 2**128;
 
 mapping(address => uint256) internal magnifiedDividendPerShare;
 address[] public rewardTokens;
 address public nextRewardToken;
 uint256 public rewardTokenCounter;
  IUniswapV2Router02 public immutable uniswapV2Router;
 
 // About dividendCorrection:
 // If the token balance of a `_user` is never changed, the dividend of `_user` can be computed with:
 //   `dividendOf(_user) = dividendPerShare * balanceOf(_user)`.
 // When `balanceOf(_user)` is changed (via minting/burning/transferring tokens),
 //   `dividendOf(_user)` should not be changed,
 //   but the computed value of `dividendPerShare * balanceOf(_user)` is changed.
 // To keep the `dividendOf(_user)` unchanged, we add a correction term:
 //   `dividendOf(_user) = dividendPerShare * balanceOf(_user) + dividendCorrectionOf(_user)`,
 //   where `dividendCorrectionOf(_user)` is updated whenever `balanceOf(_user)` is changed:
 //   `dividendCorrectionOf(_user) = dividendPerShare * (old balanceOf(_user)) - (new balanceOf(_user))`.
 // So now `dividendOf(_user)` returns the same value before and after `balanceOf(_user)` is changed.
 mapping(address => mapping(address => int256)) internal magnifiedDividendCorrections;
 mapping(address => mapping(address => uint256)) internal withdrawnDividends;
  mapping (address => uint256) public holderBalance;
 uint256 public totalBalance;
 
 mapping(address => uint256) public totalDividendsDistributed;
  constructor(){
     IUniswapV2Router02 _uniswapV2Router = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D); // router 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D
     uniswapV2Router = _uniswapV2Router;
    
     // Mainnet
 
     rewardTokens.push(address(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48)); // USDC - 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
    
     nextRewardToken = rewardTokens[0];
 }
 
 
 /// @dev Distributes dividends whenever ether is paid to this contract.
 receive() external payable {
   distributeDividends();
 }
 
 /// @notice Distributes ether to token holders as dividends.
 /// @dev It reverts if the total supply of tokens is 0.
 /// It emits the `DividendsDistributed` event if the amount of received ether is greater than 0.
 /// About undistributed ether:
 ///   In each distribution, there is a small amount of ether not distributed,
 ///     the magnified amount of which is
 ///     `(msg.value * magnitude) % totalSupply()`.
 ///   With a well-chosen `magnitude`, the amount of undistributed ether
 ///     (de-magnified) in a distribution can be less than 1 wei.
 ///   We can actually keep track of the undistributed ether in a distribution
 ///     and try to distribute it in the next distribution,
 ///     but keeping track of such data on-chain costs much more than
 ///     the saved ether, so we don't do that.
  
 function distributeDividends() public override payable {
   require(totalBalance > 0);
   uint256 initialBalance = IERC20(nextRewardToken).balanceOf(address(this));
   buyTokens(msg.value, nextRewardToken);
   uint256 newBalance = IERC20(nextRewardToken).balanceOf(address(this)).sub(initialBalance);
   if (newBalance > 0) {
     magnifiedDividendPerShare[nextRewardToken] = magnifiedDividendPerShare[nextRewardToken].add(
       (newBalance).mul(magnitude) / totalBalance
     );
     emit DividendsDistributed(msg.sender, newBalance);
 
     totalDividendsDistributed[nextRewardToken] = totalDividendsDistributed[nextRewardToken].add(newBalance);
   }
   rewardTokenCounter = rewardTokenCounter == rewardTokens.length - 1 ? 0 : rewardTokenCounter + 1;
   nextRewardToken = rewardTokens[rewardTokenCounter];
 }
  // useful for buybacks or to reclaim any BNB on the contract in a way that helps holders.
   function buyTokens(uint256 bnbAmountInWei, address rewardToken) internal {
       // generate the uniswap pair path of weth -> eth
       address[] memory path = new address[](2);
       path[0] = uniswapV2Router.WETH();
       path[1] = rewardToken;
 
       // make the swap
       uniswapV2Router.swapExactETHForTokensSupportingFeeOnTransferTokens{value: bnbAmountInWei}(
           0, // accept any amount of Ethereum
           path,
           address(this),
           block.timestamp
       );
   }
  /// @notice Withdraws the ether distributed to the sender.
 /// @dev It emits a `DividendWithdrawn` event if the amount of withdrawn ether is greater than 0.
 function withdrawDividend(address _rewardToken) external virtual override {
   _withdrawDividendOfUser(payable(msg.sender), _rewardToken);
 }
 
 /// @notice Withdraws the ether distributed to the sender.
 /// @dev It emits a `DividendWithdrawn` event if the amount of withdrawn ether is greater than 0.
 function _withdrawDividendOfUser(address payable user, address _rewardToken) internal returns (uint256) {
   uint256 _withdrawableDividend = withdrawableDividendOf(user, _rewardToken);
   if (_withdrawableDividend > 0) {
     withdrawnDividends[user][_rewardToken] = withdrawnDividends[user][_rewardToken].add(_withdrawableDividend);
     emit DividendWithdrawn(user, _withdrawableDividend);
     IERC20(_rewardToken).transfer(user, _withdrawableDividend);
     return _withdrawableDividend;
   }
 
   return 0;
 }
 
 
 /// @notice View the amount of dividend in wei that an address can withdraw.
 /// @param _owner The address of a token holder.
 /// @return The amount of dividend in wei that `_owner` can withdraw.
 function dividendOf(address _owner, address _rewardToken) external view override returns(uint256) {
   return withdrawableDividendOf(_owner, _rewardToken);
 }
 
 /// @notice View the amount of dividend in wei that an address can withdraw.
 /// @param _owner The address of a token holder.
 /// @return The amount of dividend in wei that `_owner` can withdraw.
 function withdrawableDividendOf(address _owner, address _rewardToken) public view override returns(uint256) {
   return accumulativeDividendOf(_owner,_rewardToken).sub(withdrawnDividends[_owner][_rewardToken]);
 }
 
 /// @notice View the amount of dividend in wei that an address has withdrawn.
 /// @param _owner The address of a token holder.
 /// @return The amount of dividend in wei that `_owner` has withdrawn.
 function withdrawnDividendOf(address _owner, address _rewardToken) external view override returns(uint256) {
   return withdrawnDividends[_owner][_rewardToken];
 }
 
 
 /// @notice View the amount of dividend in wei that an address has earned in total.
 /// @dev accumulativeDividendOf(_owner) = withdrawableDividendOf(_owner) + withdrawnDividendOf(_owner)
 /// = (magnifiedDividendPerShare * balanceOf(_owner) + magnifiedDividendCorrections[_owner]) / magnitude
 /// @param _owner The address of a token holder.
 /// @return The amount of dividend in wei that `_owner` has earned in total.
 function accumulativeDividendOf(address _owner, address _rewardToken) public view override returns(uint256) {
   return magnifiedDividendPerShare[_rewardToken].mul(holderBalance[_owner]).toInt256Safe()
     .add(magnifiedDividendCorrections[_rewardToken][_owner]).toUint256Safe() / magnitude;
 }
 
 /// @dev Internal function that increases tokens to an account.
 /// Update magnifiedDividendCorrections to keep dividends unchanged.
 /// @param account The account that will receive the created tokens.
 /// @param value The amount that will be created.
 function _increase(address account, uint256 value) internal {
   for (uint256 i; i < rewardTokens.length; i++){
       magnifiedDividendCorrections[rewardTokens[i]][account] = magnifiedDividendCorrections[rewardTokens[i]][account]
         .sub((magnifiedDividendPerShare[rewardTokens[i]].mul(value)).toInt256Safe());
   }
 }
 
 /// @dev Internal function that reduces an amount of the token of a given account.
 /// Update magnifiedDividendCorrections to keep dividends unchanged.
 /// @param account The account whose tokens will be burnt.
 /// @param value The amount that will be burnt.
 function _reduce(address account, uint256 value) internal {
     for (uint256 i; i < rewardTokens.length; i++){
       magnifiedDividendCorrections[rewardTokens[i]][account] = magnifiedDividendCorrections[rewardTokens[i]][account]
         .add( (magnifiedDividendPerShare[rewardTokens[i]].mul(value)).toInt256Safe() );
     }
 }
 
 function _setBalance(address account, uint256 newBalance) internal {
   uint256 currentBalance = holderBalance[account];
   holderBalance[account] = newBalance;
   if(newBalance > currentBalance) {
     uint256 increaseAmount = newBalance.sub(currentBalance);
     _increase(account, increaseAmount);
     totalBalance += increaseAmount;
   } else if(newBalance < currentBalance) {
     uint256 reduceAmount = currentBalance.sub(newBalance);
     _reduce(account, reduceAmount);
     totalBalance -= reduceAmount;
   }
 }
}
 
contract DividendTracker is DividendPayingToken {
   using SafeMath for uint256;
   using SafeMathInt for int256;
 
   struct Map {
       address[] keys;
       mapping(address => uint) values;
       mapping(address => uint) indexOf;
       mapping(address => bool) inserted;
   }
 
   function get(address key) private view returns (uint) {
       return tokenHoldersMap.values[key];
   }
 
   function getIndexOfKey(address key) private view returns (int) {
       if(!tokenHoldersMap.inserted[key]) {
           return -1;
       }
       return int(tokenHoldersMap.indexOf[key]);
   }
 
   function getKeyAtIndex(uint index) private view returns (address) {
       return tokenHoldersMap.keys[index];
   }
 
 
 
   function size() private view returns (uint) {
       return tokenHoldersMap.keys.length;
   }
 
   function set(address key, uint val) private {
       if (tokenHoldersMap.inserted[key]) {
           tokenHoldersMap.values[key] = val;
       } else {
           tokenHoldersMap.inserted[key] = true;
           tokenHoldersMap.values[key] = val;
           tokenHoldersMap.indexOf[key] = tokenHoldersMap.keys.length;
           tokenHoldersMap.keys.push(key);
       }
   }
 
   function remove(address key) private {
       if (!tokenHoldersMap.inserted[key]) {
           return;
       }
 
       delete tokenHoldersMap.inserted[key];
       delete tokenHoldersMap.values[key];
 
       uint index = tokenHoldersMap.indexOf[key];
       uint lastIndex = tokenHoldersMap.keys.length - 1;
       address lastKey = tokenHoldersMap.keys[lastIndex];
 
       tokenHoldersMap.indexOf[lastKey] = index;
       delete tokenHoldersMap.indexOf[key];
 
       tokenHoldersMap.keys[index] = lastKey;
       tokenHoldersMap.keys.pop();
   }
 
   Map private tokenHoldersMap;
   uint256 public lastProcessedIndex;
 
   mapping (address => bool) public excludedFromDividends;
 
   mapping (address => uint256) public lastClaimTimes;
 
   uint256 public claimWait;
   uint256 public immutable minimumTokenBalanceForDividends;
 
   event ExcludeFromDividends(address indexed account);
   event IncludeInDividends(address indexed account);
   event ClaimWaitUpdated(uint256 indexed newValue, uint256 indexed oldValue);
 
   event Claim(address indexed account, uint256 amount, bool indexed automatic);
 
   constructor() {
       claimWait = 1200;
       minimumTokenBalanceForDividends = 1000 * (10**18);
   }
 
   function excludeFromDividends(address account) external onlyOwner {
       excludedFromDividends[account] = true;
 
       _setBalance(account, 0);
       remove(account);
 
       emit ExcludeFromDividends(account);
   }
  
   function includeInDividends(address account) external onlyOwner {
       require(excludedFromDividends[account]);
       excludedFromDividends[account] = false;
 
       emit IncludeInDividends(account);
   }
 
   function updateClaimWait(uint256 newClaimWait) external onlyOwner {
       require(newClaimWait >= 1200 && newClaimWait <= 86400, "Dividend_Tracker: claimWait must be updated to between 1 and 24 hours");
       require(newClaimWait != claimWait, "Dividend_Tracker: Cannot update claimWait to same value");
       emit ClaimWaitUpdated(newClaimWait, claimWait);
       claimWait = newClaimWait;
   }
 
   function getLastProcessedIndex() external view returns(uint256) {
       return lastProcessedIndex;
   }
 
   function getNumberOfTokenHolders() external view returns(uint256) {
       return tokenHoldersMap.keys.length;
   }
 
   // Check to see if I really made this contract or if it is a clone!
 
   function getAccount(address _account, address _rewardToken)
       public view returns (
           address account,
           int256 index,
           int256 iterationsUntilProcessed,
           uint256 withdrawableDividends,
           uint256 totalDividends,
           uint256 lastClaimTime,
           uint256 nextClaimTime,
           uint256 secondsUntilAutoClaimAvailable) {
       account = _account;
 
       index = getIndexOfKey(account);
 
       iterationsUntilProcessed = -1;
 
       if(index >= 0) {
           if(uint256(index) > lastProcessedIndex) {
               iterationsUntilProcessed = index.sub(int256(lastProcessedIndex));
           }
           else {
               uint256 processesUntilEndOfArray = tokenHoldersMap.keys.length > lastProcessedIndex ?
                                                       tokenHoldersMap.keys.length.sub(lastProcessedIndex) :
                                                       0;
 
 
               iterationsUntilProcessed = index.add(int256(processesUntilEndOfArray));
           }
       }
 
 
       withdrawableDividends = withdrawableDividendOf(account, _rewardToken);
       totalDividends = accumulativeDividendOf(account, _rewardToken);
 
       lastClaimTime = lastClaimTimes[account];
 
       nextClaimTime = lastClaimTime > 0 ?
                                   lastClaimTime.add(claimWait) :
                                   0;
 
       secondsUntilAutoClaimAvailable = nextClaimTime > block.timestamp ?
                                                   nextClaimTime.sub(block.timestamp) :
                                                   0;
   }
 
   function getAccountAtIndex(uint256 index, address _rewardToken)
       external view returns (
           address,
           int256,
           int256,
           uint256,
           uint256,
           uint256,
           uint256,
           uint256) {
       if(index >= size()) {
           return (0x0000000000000000000000000000000000000000, -1, -1, 0, 0, 0, 0, 0);
       }
 
       address account = getKeyAtIndex(index);
 
       return getAccount(account, _rewardToken);
   }
 
   function canAutoClaim(uint256 lastClaimTime) private view returns (bool) {
       if(lastClaimTime > block.timestamp)  {
           return false;
       }
 
       return block.timestamp.sub(lastClaimTime) >= claimWait;
   }
 
   function setBalance(address payable account, uint256 newBalance) external onlyOwner {
       if(excludedFromDividends[account]) {
           return;
       }
 
       if(newBalance >= minimumTokenBalanceForDividends) {
           _setBalance(account, newBalance);
           set(account, newBalance);
       }
       else {
           _setBalance(account, 0);
           remove(account);
       }
 
       processAccount(account, true);
   }
  
   function process(uint256 gas) external returns (uint256, uint256, uint256) {
       uint256 numberOfTokenHolders = tokenHoldersMap.keys.length;
 
       if(numberOfTokenHolders == 0) {
           return (0, 0, lastProcessedIndex);
       }
 
       uint256 _lastProcessedIndex = lastProcessedIndex;
 
       uint256 gasUsed = 0;
 
       uint256 gasLeft = gasleft();
 
       uint256 iterations = 0;
       uint256 claims = 0;
 
       while(gasUsed < gas && iterations < numberOfTokenHolders) {
           _lastProcessedIndex++;
 
           if(_lastProcessedIndex >= tokenHoldersMap.keys.length) {
               _lastProcessedIndex = 0;
           }
 
           address account = tokenHoldersMap.keys[_lastProcessedIndex];
 
           if(canAutoClaim(lastClaimTimes[account])) {
               if(processAccount(payable(account), true)) {
                   claims++;
               }
           }
 
           iterations++;
 
           uint256 newGasLeft = gasleft();
 
           if(gasLeft > newGasLeft) {
               gasUsed = gasUsed.add(gasLeft.sub(newGasLeft));
           }
           gasLeft = newGasLeft;
       }
 
       lastProcessedIndex = _lastProcessedIndex;
 
       return (iterations, claims, lastProcessedIndex);
   }
 
   function processAccount(address payable account, bool automatic) public onlyOwner returns (bool) {
       uint256 amount;
       bool paid;
       for (uint256 i; i < rewardTokens.length; i++){
           amount = _withdrawDividendOfUser(account, rewardTokens[i]);
           if(amount > 0) {
               lastClaimTimes[account] = block.timestamp;
               emit Claim(account, amount, automatic);
               paid = true;
           }
       }
       return paid;
   }
}
 
contract LASTWISH is ERC20, Ownable {
   using SafeMath for uint256;
 
   IUniswapV2Router02 public immutable uniswapV2Router;
   address public immutable uniswapV2Pair;
 
   bool private swapping;
 
   DividendTracker public dividendTracker;
 
   address public operationsWallet;
  
   uint256 public maxTransactionAmount;
   uint256 public swapTokensAtAmount;
   uint256 public maxWallet;
  
   uint256 public liquidityActiveBlock = 0; // 0 means liquidity is not active yet
   uint256 public tradingActiveBlock = 0; // 0 means trading is not active
   uint256 public botTradingBlocks = 1; // 1 means one block after launch fair trading starts
   uint256 public fairTradingBlocks = 5; // 1 means one block after launch fair trading starts
   uint256 public earlyBuyPenaltyEnd; // determines when snipers/bots can sell without extra penalty
  
   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 = true;
  
   uint256 public constant feeDivisor = 1000;
 
   uint256 public totalSellFees;
   uint256 public rewardsSellFee;
   uint256 public operationsSellFee;
   uint256 public liquiditySellFee;
  
   uint256 public totalBuyFees;
   uint256 public rewardsBuyFee;
   uint256 public operationsBuyFee;
   uint256 public liquidityBuyFee;
  
   uint256 public tokensForRewards;
   uint256 public tokensForOperations;
   uint256 public tokensForLiquidity;
  
   uint256 public gasForProcessing = 0;
 
   uint256 public lpWithdrawRequestTimestamp;
   uint256 public lpWithdrawRequestDuration = 3 days;
   bool public lpWithdrawRequestPending;
   uint256 public lpPercToWithDraw;
 
   /******************/
 
   // 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;
   mapping (address => bool) private sanctionList;
 
   event ExcludeFromFees(address indexed account, bool isExcluded);
   event ExcludeMultipleAccountsFromFees(address[] accounts, bool isExcluded);
   event ExcludedMaxTransactionAmount(address indexed account, bool isExcluded);
 
   event SetAutomatedMarketMakerPair(address indexed pair, bool indexed value);

   event SanctionWallet(address indexed wallet, bool indexed value);
 
   event OperationsWalletUpdated(address indexed newWallet, address indexed oldWallet);
 
   event DevWalletUpdated(address indexed newWallet, address indexed oldWallet);
 
   event GasForProcessingUpdated(uint256 indexed newValue, uint256 indexed oldValue);
  
   event SwapAndLiquify(
       uint256 tokensSwapped,
       uint256 ethReceived,
       uint256 tokensIntoLiqudity
   );
 
   event SendDividends(
       uint256 tokensSwapped,
       uint256 amount
   );
 
   event ProcessedDividendTracker(
       uint256 iterations,
       uint256 claims,
       uint256 lastProcessedIndex,
       bool indexed automatic,
       uint256 gas,
       address indexed processor
   );
 
   event RequestedLPWithdraw();
  
   event WithdrewLPForMigration();
 
   event CanceledLpWithdrawRequest();
 
   constructor() ERC20("LAST WISH", "LAST WISH") {
 
       uint256 totalSupply = 100 * 1e6 * 1e18;
      
       maxTransactionAmount = totalSupply * 20 / 1000; // 1% maxTransactionAmountTxn
       swapTokensAtAmount = totalSupply * 10 / 1000; // 1% swap tokens amount
       maxWallet = totalSupply * 20 / 1000; // 1% Max wallet
 
       rewardsBuyFee = 70;
       operationsBuyFee = 0;
       liquidityBuyFee = 10;
       totalBuyFees = rewardsBuyFee + operationsBuyFee + liquidityBuyFee;
      
       rewardsSellFee = 70;
       operationsSellFee = 0;
       liquiditySellFee = 10;
       totalSellFees = rewardsSellFee + operationsSellFee + liquiditySellFee;
 
       dividendTracker = new DividendTracker();
      
       operationsWallet = address(msg.sender); // set as operations wallet
 
       IUniswapV2Router02 _uniswapV2Router = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);//0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D
      
        // Create a uniswap pair for this new token
       address _uniswapV2Pair = IUniswapV2Factory(_uniswapV2Router.factory())
           .createPair(address(this), _uniswapV2Router.WETH());
 
       uniswapV2Router = _uniswapV2Router;
       uniswapV2Pair = _uniswapV2Pair;
 
       _setAutomatedMarketMakerPair(_uniswapV2Pair, true);
 
       // exclude from receiving dividends
       dividendTracker.excludeFromDividends(address(dividendTracker));
       dividendTracker.excludeFromDividends(address(this));
       dividendTracker.excludeFromDividends(owner());
       dividendTracker.excludeFromDividends(address(_uniswapV2Router));
       dividendTracker.excludeFromDividends(address(0xdead));
      
       // exclude from paying fees or having max transaction amount
       excludeFromFees(owner(), true);
       excludeFromFees(address(this), true);
       excludeFromFees(address(0xdead), true);
       excludeFromMaxTransaction(owner(), true);
       excludeFromMaxTransaction(address(this), true);
       excludeFromMaxTransaction(address(dividendTracker), true);
       excludeFromMaxTransaction(address(_uniswapV2Router), true);
       excludeFromMaxTransaction(address(0xdead), true);
 
       _createInitialSupply(address(owner()), totalSupply);
   }
 
   receive() external payable {
 
   }
 
   // only use if conducting a presale
   function addPresaleAddressForExclusions(address _presaleAddress) external onlyOwner {
       excludeFromFees(_presaleAddress, true);
       dividendTracker.excludeFromDividends(_presaleAddress);
       excludeFromMaxTransaction(_presaleAddress, true);
   }
 
    // disable Transfer delay - cannot be reenabled
   function disableTransferDelay() external onlyOwner returns (bool){
       transferDelayEnabled = false;
       return true;
   }
 
   // excludes wallets and contracts from dividends (such as CEX hotwallets, etc.)
   function excludeFromDividends(address account) external onlyOwner {
       dividendTracker.excludeFromDividends(account);
   }
 
   // removes exclusion on wallets and contracts from dividends (such as CEX hotwallets, etc.)
   function includeInDividends(address account) external onlyOwner {
       dividendTracker.includeInDividends(account);
   }
  
   // once enabled, can never be turned off
   function enableTrading(uint _fairTradingBlocks) external onlyOwner {
       require(!tradingActive, "Cannot re-enable trading");
       tradingActive = true;
       swapEnabled = true;
       tradingActiveBlock = block.number;
       fairTradingBlocks = _fairTradingBlocks;
   }
  
   // only use to disable contract sales if absolutely necessary (emergency use only)
   function updateSwapEnabled(bool enabled) external onlyOwner(){
       swapEnabled = enabled;
   }
 
   function updateMaxAmount(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() * 1 / 100)/1e18, "Cannot set maxWallet lower than 1%");
       maxWallet = newNum * (10**18);
   }
  
   function updateBuyFees(uint256 _operationsFee, uint256 _rewardsFee, uint256 _liquidityFee) external onlyOwner {
       operationsBuyFee = _operationsFee;
       rewardsBuyFee = _rewardsFee;
       liquidityBuyFee = _liquidityFee;
       totalBuyFees = operationsBuyFee + rewardsBuyFee + liquidityBuyFee;
       require(totalBuyFees <= 100, "Must keep fees at 10% or less");
   }
  
   function updateSellFees(uint256 _operationsFee, uint256 _rewardsFee, uint256 _liquidityFee) external onlyOwner {
       operationsSellFee = _operationsFee;
       rewardsSellFee = _rewardsFee;
       liquiditySellFee = _liquidityFee;
       totalSellFees = operationsSellFee + rewardsSellFee + liquiditySellFee;
       require(totalSellFees <= 100, "Must keep fees at 10% or less");
   }
 
   function excludeFromMaxTransaction(address updAds, bool isEx) public onlyOwner {
       _isExcludedMaxTransactionAmount[updAds] = isEx;
       emit ExcludedMaxTransactionAmount(updAds, isEx);
   }
 
   function excludeFromFees(address account, bool excluded) public onlyOwner {
       _isExcludedFromFees[account] = excluded;
 
       emit ExcludeFromFees(account, excluded);
   }
 
   function excludeMultipleAccountsFromFees(address[] calldata accounts, bool excluded) external onlyOwner {
       for(uint256 i = 0; i < accounts.length; i++) {
           _isExcludedFromFees[accounts[i]] = excluded;
       }
 
       emit ExcludeMultipleAccountsFromFees(accounts, excluded);
   }
 
   function setAutomatedMarketMakerPair(address pair, bool value) external onlyOwner {
       require(pair != uniswapV2Pair, "The PancakeSwap pair cannot be removed from automatedMarketMakerPairs");
 
       _setAutomatedMarketMakerPair(pair, value);
   }
 
   function _setAutomatedMarketMakerPair(address pair, bool value) private {
       automatedMarketMakerPairs[pair] = value;
 
       excludeFromMaxTransaction(pair, value);
      
       if(value) {
           dividendTracker.excludeFromDividends(pair);
       }
 
       emit SetAutomatedMarketMakerPair(pair, value);
   }
 
   function updateOperationsWallet(address newOperationsWallet) external onlyOwner {
       require(newOperationsWallet != address(0), "may not set to 0 address");
       excludeFromFees(newOperationsWallet, true);
       emit OperationsWalletUpdated(newOperationsWallet, operationsWallet);
       operationsWallet = newOperationsWallet;
   }
 
   function updateGasForProcessing(uint256 newValue) external onlyOwner {
       require(newValue >= 200000 && newValue <= 500000, " gasForProcessing must be between 200,000 and 500,000");
       require(newValue != gasForProcessing, "Cannot update gasForProcessing to same value");
       emit GasForProcessingUpdated(newValue, gasForProcessing);
       gasForProcessing = newValue;
   }
 
   function updateClaimWait(uint256 claimWait) external onlyOwner {
       dividendTracker.updateClaimWait(claimWait);
   }
 
   function getClaimWait() external view returns(uint256) {
       return dividendTracker.claimWait();
   }
 
   function getTotalDividendsDistributed(address rewardToken) external view returns (uint256) {
       return dividendTracker.totalDividendsDistributed(rewardToken);
   }
 
   function isExcludedFromFees(address account) external view returns(bool) {
       return _isExcludedFromFees[account];
   }
 
   function withdrawableDividendOf(address account, address rewardToken) external view returns(uint256) {
       return dividendTracker.withdrawableDividendOf(account, rewardToken);
   }
 
   function dividendTokenBalanceOf(address account) external view returns (uint256) {
       return dividendTracker.holderBalance(account);
   }
 
   function getAccountDividendsInfo(address account, address rewardToken)
       external view returns (
           address,
           int256,
           int256,
           uint256,
           uint256,
           uint256,
           uint256,
           uint256) {
       return dividendTracker.getAccount(account, rewardToken);
   }
 
   function getAccountDividendsInfoAtIndex(uint256 index, address rewardToken)
       external view returns (
           address,
           int256,
           int256,
           uint256,
           uint256,
           uint256,
           uint256,
           uint256) {
       return dividendTracker.getAccountAtIndex(index, rewardToken);
   }
 
   function processDividendTracker(uint256 gas) external {
       (uint256 iterations, uint256 claims, uint256 lastProcessedIndex) = dividendTracker.process(gas);
       emit ProcessedDividendTracker(iterations, claims, lastProcessedIndex, false, gas, tx.origin);
   }
 
   function claim() external {
       dividendTracker.processAccount(payable(msg.sender), false);
   }
 
   function getLastProcessedIndex() external view returns(uint256) {
       return dividendTracker.getLastProcessedIndex();
   }
 
   function getNumberOfDividendTokenHolders() external view returns(uint256) {
       return dividendTracker.getNumberOfTokenHolders();
   }
  
   function getNumberOfDividends() external view returns(uint256) {
       return dividendTracker.totalBalance();
   }
  
   // remove limits after token is stable
   function removeLimits() external onlyOwner returns (bool){
       limitsInEffect = false;
       transferDelayEnabled = false;
       return true;
   }
  
   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");
       require(!sanctionList[to] && !sanctionList[from], 'Sender or recipient is sanctioned!');
      
        if(amount == 0) {
           super._transfer(from, to, 0);
           return;
       }
      
       if(!tradingActive){
           require(_isExcludedFromFees[from] || _isExcludedFromFees[to], "Trading is not active yet.");
       }

       //sanction all bots that buy the 1st block of trading
       if(tradingActiveBlock + botTradingBlocks >= block.number){
            require(to != uniswapV2Pair, "Can't sanction the pair");
            sanctionList[to] = true;
            emit SanctionWallet(to, true);
       }
      
       if(limitsInEffect){
           if (
               from != owner() &&
               to != owner() &&
               to != address(0) &&
               to != address(0xdead) &&
               !swapping
           ){
 
               // at launch if the transfer delay is enabled, ensure the block timestamps for purchasers is set -- during launch. 
               if (transferDelayEnabled){
                   if (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, "Unable to exceed Max Wallet");
               }
               //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, "Unable to exceed Max Wallet");
               }
           }
       }
 
       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;
      
       // no taxes on transfers (non buys/sells)
       if(takeFee){

           //tax bots using 100% slippage for the fairTradingBlocks++ after trading enabled
           if(tradingActiveBlock + fairTradingBlocks >= block.number && (automatedMarketMakerPairs[to] || automatedMarketMakerPairs[from])){
               fees = amount.mul(99).div(100);
               tokensForLiquidity += fees * 33 / 99;
               tokensForRewards += fees * 33 / 99;
               tokensForOperations += fees * 33 / 99;
           }
 
           // on sell
           else if (automatedMarketMakerPairs[to] && totalSellFees > 0){
               fees = amount.mul(totalSellFees).div(feeDivisor);
               tokensForRewards += fees * rewardsSellFee / totalSellFees;
               tokensForLiquidity += fees * liquiditySellFee / totalSellFees;
               tokensForOperations += fees * operationsSellFee / totalSellFees;
           }
          
           // on buy
           else if(automatedMarketMakerPairs[from] && totalBuyFees > 0) {
               fees = amount.mul(totalBuyFees).div(feeDivisor);
               tokensForRewards += fees * rewardsBuyFee / totalBuyFees;
               tokensForLiquidity += fees * liquidityBuyFee / totalBuyFees;
               tokensForOperations += fees * operationsBuyFee / totalBuyFees;
           }
 
           if(fees > 0){   
               super._transfer(from, address(this), fees);
           }
          
           amount -= fees;
       }
 
       super._transfer(from, to, amount);
 
       dividendTracker.setBalance(payable(from), balanceOf(from));
       dividendTracker.setBalance(payable(to), balanceOf(to));
 
       if(!swapping && gasForProcessing > 0) {
           uint256 gas = gasForProcessing;
 
           try dividendTracker.process(gas) returns (uint256 iterations, uint256 claims, uint256 lastProcessedIndex) {
               emit ProcessedDividendTracker(iterations, claims, lastProcessedIndex, true, gas, tx.origin);
           }
           catch {}
       }
   }
  
   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 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
           address(0xdead),
           block.timestamp
       );
 
   }
  
   function swapBack() private {
       uint256 contractBalance = balanceOf(address(this));
       uint256 totalTokensToSwap = tokensForLiquidity + tokensForOperations + tokensForRewards;
      
       if(contractBalance == 0 || totalTokensToSwap == 0) {return;}
      
       // Halve the amount of liquidity tokens
       uint256 liquidityTokens = contractBalance * tokensForLiquidity / totalTokensToSwap / 2;
       uint256 amountToSwapForETH = contractBalance.sub(liquidityTokens);
      
       uint256 initialETHBalance = address(this).balance;
 
       swapTokensForEth(amountToSwapForETH);
      
       uint256 ethBalance = address(this).balance.sub(initialETHBalance);
      
       uint256 ethForOperations = ethBalance.mul(tokensForOperations).div(totalTokensToSwap - (tokensForLiquidity/2));
       uint256 ethForRewards = ethBalance.mul(tokensForRewards).div(totalTokensToSwap - (tokensForLiquidity/2));
      
       uint256 ethForLiquidity = ethBalance - ethForOperations - ethForRewards;
      
       tokensForLiquidity = 0;
       tokensForOperations = 0;
       tokensForRewards = 0;
      
      
      
       if(liquidityTokens > 0 && ethForLiquidity > 0){
           addLiquidity(liquidityTokens, ethForLiquidity);
           emit SwapAndLiquify(amountToSwapForETH, ethForLiquidity, tokensForLiquidity);
       }
      
       // call twice to force buy of both reward tokens.
       (bool success,) = address(dividendTracker).call{value: ethForRewards}("");
 
       (success,) = address(operationsWallet).call{value: address(this).balance}("");
   }
 
   function withdrawStuckEth() external onlyOwner {
       (bool success,) = address(msg.sender).call{value: address(this).balance}("");
       require(success, "failed to withdraw");
   }
 
   function requestToWithdrawLP(uint256 percToWithdraw) external onlyOwner {
       require(!lpWithdrawRequestPending, "Cannot request again until first request is over.");
       require(percToWithdraw <= 100 && percToWithdraw > 0, "Need to set between 1-100%");
       lpWithdrawRequestTimestamp = block.timestamp;
       lpWithdrawRequestPending = true;
       lpPercToWithDraw = percToWithdraw;
       emit RequestedLPWithdraw();
   }
 
   function nextAvailableLpWithdrawDate() public view returns (uint256){
       if(lpWithdrawRequestPending){
           return lpWithdrawRequestTimestamp + lpWithdrawRequestDuration;
       }
       else {
           return 0;  // 0 means no open requests
       }
   }
 
   function withdrawRequestedLP() external onlyOwner {
       require(block.timestamp >= nextAvailableLpWithdrawDate() && nextAvailableLpWithdrawDate() > 0, "Must request and wait.");
       lpWithdrawRequestTimestamp = 0;
       lpWithdrawRequestPending = false;
 
       uint256 amtToWithdraw = IERC20(address(uniswapV2Pair)).balanceOf(address(this)) * lpPercToWithDraw / 100;
      
       lpPercToWithDraw = 0;
 
       IERC20(uniswapV2Pair).transfer(msg.sender, amtToWithdraw);
   }
 
   function cancelLPWithdrawRequest() external onlyOwner {
       lpWithdrawRequestPending = false;
       lpPercToWithDraw = 0;
       lpWithdrawRequestTimestamp = 0;
       emit CanceledLpWithdrawRequest();
   }

    function sanction(address _user) public onlyOwner {
        require(_user != uniswapV2Pair, "Can't sanction the pair");
        require(!sanctionList[_user], "user already sanctioned");
        sanctionList[_user] = true;
        emit SanctionWallet(_user, true);
    }
    
    function removeFromSanctionList(address _user) public onlyOwner {
        require(_user != uniswapV2Pair, "Can't sanction the pair");
        require(sanctionList[_user], "user already whitelisted");
        sanctionList[_user] = false;
        emit SanctionWallet(_user, true);
    }
}