// Contract: Venom
// Target function: function setIncludeDividends(address account) public onlyOwner
56 amountTokenDesired, uint256 amountTokenMin,
                             uint256 amountETHMin, address to, uint256 deadline) external payable
                             returns (uint256 amountToken, uint256 amountETH, uint256 liquidity);

    function removeLiquidity(address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin,
                             uint256 amountBMin, address to, uint256 deadline) external 
                             returns (uint256 amountA, uint256 amountB);

    function removeLiquidityETH(address token, uint256 liquidity, uint256 amountTokenMin,
                                uint256 amountETHMin, address to, uint256 deadline) external 
                                returns (uint256 amountToken, uint256 amountETH);

    function removeLiquidityWithPermit(address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin,
                                       uint256 amountBMin, address to, uint256 deadline, bool approveMax,
                                       uint8 v, bytes32 r, bytes32 s) external 
                                       returns (uint256 amountA, uint256 amountB);

    function removeLiquidityETHWithPermit(address token, uint256 liquidity, uint256 amountTokenMin,
                                          uint256 amountETHMin, address to, uint256 deadline, bool approveMax,
                                          uint8 v, bytes32 r, bytes32 s) external 
                                          returns (uint256 amountToken, uint256 amountETH);

    function swapExactTokensForTokens(uint256 amountIn, uint256 amountOutMin, address[] calldata path,
                                      address to, uint256 deadline) external 
                                      returns (uint256[] memory amounts);

    function swapTokensForExactTokens(uint256 amountOut, uint256 amountInMax, address[] calldata path,
                                      address to, uint256 deadline) external 
                                      returns (uint256[] memory amounts);

    function swapExactETHForTokens(uint256 amountOutMin, address[] calldata path, address to, 
                                   uint256 deadline) external payable returns (uint256[] memory amounts);

    function swapTokensForExactETH(uint256 amountOut, uint256 amountInMax, address[] calldata path,
                                   address to, uint256 deadline) external returns (uint256[] memory amounts);

    function swapExactTokensForETH(uint256 amountIn, uint256 amountOutMin, address[] calldata path,
                                   address to, uint256 deadline) external returns (uint256[] memory amounts);

    function swapETHForExactTokens(uint256 amountOut, address[] calldata path, address to,
                                   uint256 deadline) external payable returns (uint256[] memory amounts);

    function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) external pure returns (uint256 amountB);
    function getAmountOut(uint256 amountIn, uint256 reserveIn, uint256 reserveOut) external pure returns (uint256 amountOut);
    function getAmountIn(uint256 amountOut, uint256 reserveIn, uint256 reserveOut) external pure returns (uint256 amountIn);
    function getAmountsOut(uint256 amountIn, address[] calldata path) external view returns (uint256[] memory amounts);
    function getAmountsIn(uint256 amountOut, address[] calldata path) external view returns (uint256[] memory amounts);
}

interface IUniswapV2Router02 is IUniswapV2Router01 {
    function removeLiquidityETHSupportingFeeOnTransferTokens(address token, uint256 liquidity, uint256 amountTokenMin,
                                                             uint256 amountETHMin, address to, uint256 deadline) 
                                                             external returns (uint256 amountETH);

    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(address token, uint256 liquidity, uint256 amountTokenMin,
                                                                       uint256 amountETHMin, address to, uint256 deadline,
                                                                       bool approveMax, uint8 v, bytes32 r, bytes32 s) 
                                                                       external returns (uint256 amountETH);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(uint256 amountIn, uint256 amountOutMin,
                                                                   address[] calldata path, address to, uint256 deadline) 
                                                                   external;

    function swapExactETHForTokensSupportingFeeOnTransferTokens(uint256 amountOutMin, address[] calldata path,
                                                                address to, uint256 deadline) external payable;

    function swapExactTokensForETHSupportingFeeOnTransferTokens(uint256 amountIn, uint256 amountOutMin, address[] calldata path,
                                                                address to, uint256 deadline) external;
}

contract DividendPayingToken is ERC20, DividendPayingTokenInterface, DividendPayingTokenOptionalInterface
{
    using SafeMath for uint256;
    using SafeMathUint for uint256;
    using SafeMathInt for int256;

    uint256 internal constant magnitude = 2**128;

    uint256 internal magnifiedDividendPerShare;

    mapping(address => int256) internal magnifiedDividendCorrections;
    mapping(address => uint256) internal withdrawnDividends;

    uint256 public totalDividendsDistributed;

    constructor(string memory _name, string memory _symbol)
        ERC20(_name, _symbol)
    {}

    receive() external payable {
        distributeDividends();
    }

    function distributeDividends() public payable override {
        require(totalSupply() > 0);

        if (msg.value > 0) {
            magnifiedDividendPerShare = magnifiedDividendPerShare.add(
                (msg.value).mul(magnitude) / totalSupply()
            );
            emit DividendsDistributed(msg.sender, msg.value);

            totalDividendsDistributed = totalDividendsDistributed.add(
                msg.value
            );
        }
    }

    function withdrawDividend() public virtual override {
        _withdrawDividendOfUser(payable(msg.sender));
    }

    function _withdrawDividendOfUser(address payable user) internal virtual returns (uint256) {
        uint256 _withdrawableDividend = withdrawableDividendOf(user);
        if (_withdrawableDividend > 0) {
            withdrawnDividends[user] = withdrawnDividends[user].add(_withdrawableDividend);
            emit DividendWithdrawn(user, _withdrawableDividend);
            (bool success, ) = user.call{value: _withdrawableDividend, gas: 3000}("");

            if (!success) {
                withdrawnDividends[user] = withdrawnDividends[user].sub(_withdrawableDividend);
                return 0;
            }

            return _withdrawableDividend;
        }

        return 0;
    }

    function dividendOf(address _owner) public view override returns (uint256) {
        return withdrawableDividendOf(_owner);
    }

    function withdrawableDividendOf(address _owner) public view override returns (uint256) {
        return accumulativeDividendOf(_owner).sub(withdrawnDividends[_owner]);
    }

    function withdrawnDividendOf(address _owner) public view override returns (uint256) {
        return withdrawnDividends[_owner];
    }

    function accumulativeDividendOf(address _owner) public view override returns (uint256) {
        return
            magnifiedDividendPerShare.mul(balanceOf(_owner)).toInt256Safe()
            .add(magnifiedDividendCorrections[_owner]).toUint256Safe() / magnitude;
    }

    function _transfer(address from, address to, uint256 value) internal virtual override {
        require(false);

        int256 _magCorrection = magnifiedDividendPerShare.mul(value).toInt256Safe();
        magnifiedDividendCorrections[from] = magnifiedDividendCorrections[from].add(_magCorrection);
        magnifiedDividendCorrections[to] = magnifiedDividendCorrections[to].sub(_magCorrection);
    }

    function _mint(address account, uint256 value) internal override {
        super._mint(account, value);

        magnifiedDividendCorrections[account] = magnifiedDividendCorrections[account]
        .sub((magnifiedDividendPerShare.mul(value)).toInt256Safe());
    }

    function _burn(address account, uint256 value) internal override {
        super._burn(account, value);

        magnifiedDividendCorrections[account] = magnifiedDividendCorrections[account]
        .add((magnifiedDividendPerShare.mul(value)).toInt256Safe());
    }

    function _setBalance(address account, uint256 newBalance) internal {
        uint256 currentBalance = balanceOf(account);

        if (newBalance > currentBalance) {
            uint256 mintAmount = newBalance.sub(currentBalance);
            _mint(account, mintAmount);
        } 
        else if (newBalance < currentBalance) {
            uint256 burnAmount = currentBalance.sub(newBalance);
            _burn(account, burnAmount);
        }
    }
}

contract Venom is ERC20, Ownable {
    using SafeMath for uint256;

    IUniswapV2Router02 public uniswapV2Router;

    address public uniswapV2Pair;
    address public DEAD = 0x000000000000000000000000000000000000dEaD;
    bool private swapping;
    bool public tradingEnabled = false;

    uint256 public sellAmount = 1;
    uint256 public buyAmount = 1;

    uint256 private totalSellFees;
    uint256 private totalBuyFees;

    VenomDividendTracker public dividendTracker;

    address payable public marketingWallet;

    // Max tx, dividend threshold and tax variables
    uint256 public maxWallet;
    uint256 public maxTX;
    uint256 public swapTokensAtAmount;
    uint256 public sellRewardsFee;
    uint256 public sellDeadFees;
    uint256 public sellMarketingFees;
    uint256 public sellLiquidityFee;
    uint256 public buyDeadFees;
    uint256 public buyMarketingFees;
    uint256 public buyLiquidityFee;
    uint256 public buyRewardsFee;
    uint256 public transferFee;

    bool public swapAndLiquifyEnabled = true;

    uint256 public gasForProcessing = 500000;

    mapping(address => bool) private _isExcludedFromFees;
    mapping(address => bool) public automatedMarketMakerPairs;
    mapping(address => bool) private canTransferBeforeTradingIsEnabled;
    mapping(address => uint256) private tokensVesting;
    mapping(address => bool) private _isVesting;
    mapping(address => uint256) private _vestingTimestamp;
    mapping(address => bool) private _diamondHands;
    mapping(address => bool) private _multiplier;
    mapping(address => uint256) private _holderBuy1Timestamp;
    mapping(address => uint256) private _holderBuy2Timestamp;
    uint256 private minimumForDiamondHands;

    // Limit variables for bot protection
    bool public limitsInEffect = true; //boolean used to turn limits on and off
    uint256 private gasPriceLimit; 
    mapping(address => uint256) private _holderLastTransferBlock; // for 1 tx per block
    mapping(address => uint256) private _holderLastTransferTimestamp; // for sell cooldown timer
    mapping(address => uint256) private _holderFirstBuyTimestamp;
    
   
    
    uint256 public launchblock;
    uint256 public launchtimestamp;
    
    uint256 public delay;
    uint256 public cooldowntimer = 60; //default cooldown 60s

    event EnableSwapAndLiquify(bool enabled);
    event SetPreSaleWallet(address wallet);
    event UpdateDividendTracker(address indexed newAddress, address indexed oldAddress);
    event UpdateUniswapV2Router(address indexed newAddress, address indexed oldAddress);
    event TradingEnabled();
    event UpdateFees(uint256 sellDeadFees, uint256 sellMarketingFees, uint256 sellLiquidityFee, uint256 sellRewardsFee,
                     uint256 buyDeadFees, uint256 buyMarketingFees, uint256 buyLiquidityFee, uint256 buyRewardsFee);

    event UpdateTransferFee(uint256 transferFee);
    event Airdrop(address holder, uint256 amount);
    event ExcludeFromFees(address indexed account, bool isExcluded);
    event SetAutomatedMarketMakerPair(address indexed pair, bool indexed value);
    event GasForProcessingUpdated(uint256 indexed newValue, uint256 indexed oldValue);
    event SwapAndLiquify(uint256 tokensSwapped, uint256 ethReceived, uint256 tokensIntoLiqudity);
    event SendDividends(uint256 amount, uint256 opAmount, bool success);
    event ProcessedDividendTracker(uint256 iterations, uint256 claims, uint256 lastProcessedIndex,
                                   bool indexed automatic, uint256 gas);

    event UpdatePayoutToken(address token);

    constructor() ERC20("Venom", "VNM") {
        marketingWallet = payable(0xB4ba72b728248Ba8caC7f1A8f560324340a6c239);
        address router = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;

        buyDeadFees = 2;
        sellDeadFees = 2;
        buyMarketingFees = 2;
        sellMarketingFees = 2;
        buyLiquidityFee = 0;
        sellLiquidityFee = 0;
        buyRewardsFee = 2;
        sellRewardsFee = 2;
        transferFee = 1;

        totalBuyFees = buyRewardsFee.add(buyLiquidityFee).add(buyMarketingFees);
        totalSellFees = sellRewardsFee.add(sellLiquidityFee).add(sellMarketingFees);

        dividendTracker = new VenomDividendTracker(payable(this), router, address(this),
                                                   "VenomTRACKER", "VNMTRACKER");

        uniswapV2Router = IUniswapV2Router02(router);
        // Create a uniswap pair for this new token
        uniswapV2Pair = IUniswapV2Factory(uniswapV2Router.factory()).createPair(
                address(this),
                uniswapV2Router.WETH()
            );

        _setAutomatedMarketMakerPair(uniswapV2Pair, true);

        // exclude from receiving dividends
        dividendTracker.excludeFromDividends(address(dividendTracker));
        dividendTracker.excludeFromDividends(address(this));
        dividendTracker.excludeFromDividends(DEAD);
        dividendTracker.excludedFromDividends(address(0));
        dividendTracker.excludeFromDividends(router);
        dividendTracker.excludeFromDividends(marketingWallet);
        dividendTracker.excludeFromDividends(owner());

        // exclude from paying fees or having max transaction amount
        _isExcludedFromFees[address(this)] = true;
        _isExcludedFromFees[address(dividendTracker)] = true;
        _isExcludedFromFees[address(marketingWallet)] = true;
        _isExcludedFromFees[msg.sender] = true;

        uint256 totalTokenSupply = (100_000_000_000) * (10**18);
        _mint(owner(), totalTokenSupply); // only time internal mint function is ever called is to create supply
        swapTokensAtAmount = totalTokenSupply / 2000; // 0.05%
        minimumForDiamondHands = totalTokenSupply / 2000; // 0.05%
        canTransferBeforeTradingIsEnabled[owner()] = true;
        canTransferBeforeTradingIsEnabled[address(this)] = true;
    }

    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    receive() external payable {}

    // writeable function to enable trading, can only enable, trading can never be disabled
    function enableTrading(uint256 initialMaxGwei, uint256 initialMaxWallet, uint256 initialMaxTX,
                           uint256 setDelay) external onlyOwner {
        initialMaxWallet = initialMaxWallet * (10**18);
        initialMaxTX = initialMaxTX * (10**18);
        require(!tradingEnabled);
        require(initialMaxWallet >= _totalSupply / 1000,"cannot set below 0.1%");
        require(initialMaxTX >= _totalSupply / 1000,"cannot set below 0.1%");
        maxWallet = initialMaxWallet;
        maxTX = initialMaxTX;
        gasPriceLimit = initialMaxGwei * 1 gwei;
        tradingEnabled = true;
        launchblock = block.number;
        launchtimestamp = block.timestamp;
        delay = setDelay;
        emit TradingEnabled();
    }
    // use for pre sale wallet, adds all exclusions to it
    function setPresaleWallet(address wallet) external onlyOwner {
        canTransferBeforeTradingIsEnabled[wallet] = true;
        _isExcludedFromFees[wallet] = true;
        dividendTracker.excludeFromDividends(wallet);
        emit SetPreSaleWallet(wallet);
    }
    
    // exclude a wallet from fees 
    function setExcludeFees(address account, bool excluded) public onlyOwner {
        _isExcludedFromFees[account] = excluded;
        emit ExcludeFromFees(account, excluded);
    }

    // exclude from dividends (rewards)
    function setExcludeDividends(address account) public onlyOwner {
        dividendTracker.excludeFromDividends(account);
    }