// Contract: LASTWISH
// Target function: function accumulativeDividendOf(address _owner, address _rewardToken) public view override returns(uint256)
`
    * 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];
 }