// Contract: DogeHunt
// Target function: function releaseLP() external onlyOwner
3e,
        PublicRelations: 0x84ecD6d601cf856354ff95544Ae7E444dD28b68e
    });

    MaxLimits public _limits;

    LimitRatios public _limitRatios = LimitRatios({
        wallet: 2,
        sell: 2,
        buy: 2,
        divisor: 200
    });

    uint8 private totalTaxRatio;
    uint8 private totalSwapRatio;
    uint8 private distributeRatio;

    //these values must add up to 100
    uint8 private mainRewardSplit=100;
    uint8 private miscRewardSplit=0;

    uint256 private _liquidityUnlockTime;

    //Antibot variables
    uint256 private liquidityBlock;
    bool private liquidityAdded;
    bool private revertSameBlock = true; //block same block buys

    bool private dynamicBurn = false;            
    //dynamicBurn = true will burn all extra sell tax from dynamicSells
    //dynamicBurn = false will divert all extra sell tax to swaps

    bool private dynamicSellsEnabled = false;    
    //dynamic sells will increase tax based on price impact
    //any sells over 1% price impact will incur extra sell tax
    //max extra sell tax is 20% when price impact >= 10%

    bool private dynamicLimits = false;
    //dynamicLimits = true will change MaxLimits based on circulating supply rather than total supply

    bool private dynamicLiqEnabled = false;
    //dynamicLiqEnabled = true will stop autoLP if targetLiquidityRatio is met
    //tax meant for liquidity will be redirected to other swap taxes in this case

    uint16 private targetLiquidityRatio = 15; //target liquidity out of 100

    uint16 public swapThreshold = 25; //threshold that contract will swap. out of 1000
    bool public manualSwap;

    //change this address to desired reward token. miscReward is custom chosen by holder
    address public mainReward = 0x7B4328c127B85369D9f82ca0503B000D09CF9180;

    address public _pancakePairAddress; 
    IPancakeRouter02 private  _pancakeRouter;
    address public PancakeRouter;

/////////////////////////////   EVENTS  /////////////////////////////////////////
    event AdjustedDynamicSettings(bool burn, bool limits, bool liquidity, bool sells);
    event AccountExcluded(address account);
    event ChangeMainReward (address newMainReward);
    event ClaimToken(uint256 amount, address token, address recipient);
    event ClaimETH(address from,address to, uint256 amount); 
    event EnableManualSwap(bool enabled);
    event ExcludedAccountFromFees(address account, bool exclude);               
    event ExcludeFromStaking(address account, bool excluded);      
    event ExtendLiquidityLock(uint256 extendedLockTime);
    event UpdateTaxes(uint8 buyTax, uint8 sellTax, uint8 transferTax);    
    event RatiosChanged(
        uint8 newBurn, 
        uint8 newBuyback, 
        uint8 newDev, 
        uint8 newLiquidity, 
        uint8 newDonation, 
        uint8 newPublicRelations, 
        uint8 newRewards
        );
    event UpdateDevWallet(address newDevWallet);
    event UpdateDonationWallet(address newDonationWallet);          
    event UpdatePublicRelationsWallet(address newPublicRelationsWallet);  
    event UpdateRewardSplit (uint8 newMainSplit, uint8 newMiscSplit);        
    event UpdateSwapThreshold(uint16 newThreshold);
    event UpdateTargetLiquidity(uint16 target);

/////////////////////////////   MODIFIERS  /////////////////////////////////////////

    modifier authorized() {
        require(_authorized(msg.sender), "Caller not authorized");
        _;
    }

    modifier lockTheSwap {
        _isSwappingContractModifier = true;
        _;
        _isSwappingContractModifier = false;
    }

/////////////////////////////   CONSTRUCTOR  /////////////////////////////////////////

    constructor () {
        if (block.chainid == 1) {
            PancakeRouter = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
        } else if (block.chainid == 3) {
            PancakeRouter = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
        } else 
            revert();        
        _pancakeRouter = IPancakeRouter02(PancakeRouter);
        _pancakePairAddress = IPancakeFactory(
            _pancakeRouter.factory()).createPair(address(this), _pancakeRouter.WETH()
        );
        _addToken(msg.sender,INITIAL_SUPPLY);
        emit Transfer(address(0), msg.sender, INITIAL_SUPPLY);
        _allowances[address(this)][address(_pancakeRouter)] = type(uint256).max;         
        
        //setup ratio divisors based on Dev's chosen ratios
        totalTaxRatio = _taxRatios.burn 
        + _taxRatios.buyback 
        + _taxRatios.Dev 
        + _taxRatios.liquidity 
        + _taxRatios.Donation 
        + _taxRatios.PublicRelations 
        + _taxRatios.rewards;

        totalSwapRatio = totalTaxRatio - _taxRatios.burn;
        distributeRatio = totalSwapRatio - _taxRatios.liquidity;

        //circulating supply begins as initial supply
        _circulatingSupply = INITIAL_SUPPLY;
        
        //setup _limits
        _limits = MaxLimits({
            maxWallet: INITIAL_SUPPLY * _limitRatios.wallet / _limitRatios.divisor,
            maxSell: INITIAL_SUPPLY * _limitRatios.sell / _limitRatios.divisor,
            maxBuy: INITIAL_SUPPLY * _limitRatios.buy / _limitRatios.divisor
        });
        
        _excluded.add(msg.sender);
        _excluded.add(_taxWallet.PublicRelations);
        _excluded.add(_taxWallet.Dev);    
        _excluded.add(_taxWallet.Donation);
        _excluded.add(address(this));
        _excluded.add(BURN_ADDRESS);
        _excludedFromStaking.add(address(this));
        _excludedFromStaking.add(BURN_ADDRESS);
        _excludedFromStaking.add(address(_pancakeRouter));
        _excludedFromStaking.add(_pancakePairAddress);

        _approve(address(this), address(_pancakeRouter), type(uint256).max);        
    }

    receive() external payable {}


    function decimals() external pure override returns (uint8) { return TOKEN_DECIMALS; }
    function getOwner() external view override returns (address) { return owner(); }
    function name() external view override returns (string memory) { return _name; }
    function symbol() external view override returns (string memory) { return _symbol; }
    function totalSupply() external view override returns (uint256) { return _circulatingSupply; }

    function _authorized(address addr) private view returns (bool) {
        return addr == owner() 
            || addr == _taxWallet.PublicRelations 
            || addr == _taxWallet.Dev 
            || addr == _taxWallet.Donation;
    }

    function allowance(address _owner, address spender) external view override returns (uint256) {
        return _allowances[_owner][spender];
    }

    function approve(address spender, uint256 amount) external override returns (bool) {
        _approve(msg.sender, spender, amount);
        return true;
    }

    function _approve(address owner, address spender, uint256 amount) private {
        require(owner != address(0), "Approve from zero");
        require(spender != address(0), "Approve to zero");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    function balanceOf(address account) external view override returns (uint256) {
        return _balances[account];
    }

    function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool) {
        uint256 currentAllowance = _allowances[msg.sender][spender];
        require(currentAllowance >= subtractedValue, "<0 allowance");

        _approve(msg.sender, spender, currentAllowance - subtractedValue);
        return true;
    } 

    function increaseAllowance(address spender, uint256 addedValue) external returns (bool) {
        _approve(msg.sender, spender, _allowances[msg.sender][spender] + addedValue);
        return true;
    }  
      
    function transfer(address recipient, uint256 amount) external override returns (bool) {
        _transfer(msg.sender, recipient, amount);
        return true;
    }
    
    function transferFrom(address sender, address recipient, uint256 amount) external override returns (bool) {
        _transfer(sender, recipient, amount);

        uint256 currentAllowance = _allowances[sender][msg.sender];
        require(currentAllowance >= amount, "Transfer > allowance");

        _approve(sender, msg.sender, currentAllowance - amount);
        return true;
    }

///// FUNCTIONS CALLABLE BY ANYONE /////

    //Claims reward set by Dev
    function ClaimMainReward() external {
        if (mainReward == _pancakeRouter.WETH()) {
            claimETHTo(msg.sender,msg.sender,getStakeBalance(msg.sender, true), true);        
        } else 
            claimToken(msg.sender,mainReward,0, true);
    }
    
    //Claims reward chosen by holder. Differentiates between ETH and other ERC20 tokens
    function ClaimMiscReward(address tokenAddress) external {
        if (tokenAddress == _pancakeRouter.WETH()) {
            claimETHTo(msg.sender,msg.sender,getStakeBalance(msg.sender, false), false);
        } else 
            claimToken(msg.sender,tokenAddress,0, false);
    }

    //Allows holders to include themselves back into staking if excluded
    //ExcludeFromStaking function should be used for contracts(CEX, pair, address(this), etc.)
    function IncludeMeToStaking() external {
        includeToStaking(msg.sender);
        emit ExcludeFromStaking(msg.sender, false);        
    }

///// AUTHORIZED FUNCTIONS /////

    //Allows Dev to change reward
    function changeMainReward(address newReward) external authorized {
        mainReward = newReward;
        emit ChangeMainReward(newReward);
    }

    //Manually perform a contract swap
    function createLPandETH(uint16 permilleOfPancake, bool ignoreLimits) external authorized {
        _swapContractToken(permilleOfPancake, ignoreLimits);
    }  

   

    //Toggle dynamic features on and off
    function dynamicSettings(bool burn, bool limits, bool liquidity, bool sells) external authorized {
        dynamicBurn = burn;
        dynamicLimits = limits;
        dynamicLiqEnabled = liquidity;
        dynamicSellsEnabled = sells;
        emit AdjustedDynamicSettings(burn, limits, liquidity, sells);
    }

    //Mainly used for addresses such as CEX, presale, etc
    function excludeAccountFromFees(address account, bool exclude) external authorized {
        if(exclude == true)
            _excluded.add(account);
        else
            _excluded.remove(account);
        emit ExcludedAccountFromFees(account, exclude);
    }

    //Mainly used for addresses such as CEX, presale, etc    
    function setStakingExclusionStatus(address addr, bool exclude) external authorized {
        if(exclude)
            excludeFromStaking(addr);
        else
            includeToStaking(addr);
        emit ExcludeFromStaking(addr, exclude);
    }  

    //Toggle manual swap on and off
    function enableManualSwap(bool enabled) external authorized { 
        manualSwap = enabled; 
        emit EnableManualSwap(enabled);
    } 

    //Toggle whether multiple buys in a block from a single address can be performed
    function sameBlockRevert(bool enabled) external authorized {
        revertSameBlock = enabled;
    }

    //Excludes presale address from fees and staking
    function setPresale(address presaleAddress) external authorized {
        _excluded.add(presaleAddress);
        _excludedFromStaking.add(presaleAddress);
    } 



    //indepedently set whether wallet is exempt from taxes
    function setTaxExemptionStatus(address account, bool exempt) external authorized {
        taxExempt[account] = exempt;
    }

    //independtly set whether wallet is exempt from limits
    function setLimitExemptionStatus(address account, bool exempt) external authorized {
        limitExempt[account] = exempt;
    }
    
    //Performs a buyback and automatically burns tokens
    function triggerBuyback(uint256 amount) external authorized{
        buybackToken(amount, address(this)); 
    }


    //Update limit ratios. ofCurrentSupply = true will set max wallet based on current supply. False will use initial supply
    function updateLimits(uint16 newMaxWalletRatio, uint16 newMaxSellRatio, uint16 newMaxBuyRatio, uint16 newDivisor, bool ofCurrentSupply) external authorized {
        uint256 supply = INITIAL_SUPPLY;
        if (ofCurrentSupply) 
            supply = _circulatingSupply;
        uint256 minLimit = supply / 1000;   
        uint256 newMaxWallet = supply * newMaxWalletRatio / newDivisor;
        uint256 newMaxSell = supply * newMaxSellRatio / newDivisor;
        uint256 newMaxBuy = supply * newMaxBuyRatio / newDivisor;

        //Dev can never set sells below 0.1% of circulating/initial supply
        require((newMaxWallet >= minLimit && newMaxSell >= minLimit), 
            "limits cannot be <0.1% of circulating supply");

        _limits = MaxLimits(newMaxWallet, newMaxSell, newMaxBuy);
        
        _limitRatios = LimitRatios(newMaxWalletRatio, newMaxSellRatio, newMaxBuyRatio, newDivisor);
    }

    //update tax ratios
    function updateRatios(
        uint8 newBurn, 
        uint8 newBuyback, 
        uint8 newDev, 
        uint8 newLiquidity, 
        uint8 newDonation, 
        uint8 newPublicRelations, 
        uint8 newRewards
    ) 
        external 
        authorized 
    {

        _taxRatios = TaxRatios(
            newBurn, 
            newBuyback, 
            newDev, 
            newLiquidity, 
            newDonation, 
            newPublicRelations, 
            newRewards
        );

        totalTaxRatio = newBurn + newBuyback + newDev + newLiquidity + newDonation + newPublicRelations + newRewards;
        totalSwapRatio = totalTaxRatio - newBurn;
        distributeRatio = totalSwapRatio - newLiquidity;

        emit RatiosChanged (newBurn, newBuyback, newDev, newLiquidity, newDonation, newPublicRelations, newRewards);
    }

    //update allocation of mainReward and miscReward
    function updateRewardSplit (uint8 mainSplit, uint8 miscSplit) external authorized {
        uint8 totalSplit = mainSplit + miscSplit;
        require(totalSplit == 100, "mainSplit + miscSplit needs to equal 100%");
        mainRewardSplit = mainSplit;
        miscRewardSplit = miscSplit;
        emit UpdateRewardSplit(mainSplit, miscSplit);
    }

    //update threshold that triggers contract swaps
    function updateSwapThreshold(uint16 threshold) external authorized {
        require(threshold > 0,"Threshold needs to be more than 0");
        require(threshold <= 50,"Threshold needs to be below 50");
        swapThreshold = threshold;
        emit UpdateSwapThreshold(threshold);
    }

    //targetLiquidity is out of 100
    function updateTargetLiquidity(uint16 target) external authorized {
        require(target <= 100);
        targetLiquidityRatio = target;
        emit UpdateTargetLiquidity(target);
    }

    function updateTax(uint8 newBuy, uint8 newSell, uint8 newTransfer) external authorized {
        //buy and sell tax can never be higher than MAX_TAX set at beginning of contract
        //this is a security check and prevents malicious tax use       
        require(newBuy <= MAX_TAX && newSell <= MAX_TAX && newTransfer <= 50, "taxes higher than max tax");
        _taxRates = Taxes(newBuy, newSell, newTransfer);
        emit UpdateTaxes(newBuy, newSell, newTransfer);
    }

    function withdrawDev() external authorized {
        uint256 remaining = address(this).balance 
            - DevBalance 
            - DonationBalance 
            - PublicRelationsBalance 
            - buybackBalance
            - getTotalUnclaimed();
        bool lostBalance = remaining > 0;       
        uint256 amount = lostBalance ? DevBalance + remaining : DevBalance;
        DevBalance = 0;
        _sendETH(_taxWallet.Dev, amount);
    } 

    function withdrawDonation() external authorized {
        uint256 amount = DonationBalance;
        DonationBalance = 0;
        _sendETH(_taxWallet.Donation, amount);
    }

    function withdrawPublicRelations() external authorized {
        uint256 amount = PublicRelationsBalance;
        PublicRelationsBalance = 0;
        _sendETH(_taxWallet.PublicRelations, amount);
    } 

///// OWNER FUNCTIONS /////  

    //liquidity can only be extended
    function lockLiquidityTokens(uint256 lockTimeInSeconds) external onlyOwner {
        setUnlockTime(lockTimeInSeconds + block.timestamp);
        emit ExtendLiquidityLock(lockTimeInSeconds);
    }

    //recovers stuck ETH to make sure it isnt burnt/lost
    //only callablewhen liquidity is unlocked
    function recoverETH() external onlyOwner {
        require(block.timestamp >= _liquidityUnlockTime, "Not yet unlocked");
        _liquidityUnlockTime=block.timestamp;
        _sendETH(msg.sender, address(this).balance);
    }

    //Can only be used to recover miscellaneous tokens accidentally sent to contract
    //Can't pull liquidity or native token using this function
    function recoverMiscToken(address tokenAddress) external onlyOwner {
        require(tokenAddress != _pancakePairAddress && tokenAddress != address(this),
        "can't recover LP token or this token");
        IERC20 token = IERC20(tokenAddress);
        token.transfer(msg.sender,token.balanceOf(address(this)));
    }