// Contract: TXHASHDOME
// Target function: function purgeBeforeSwitch() public onlyOwner
 currentIndex;
    }

    function getNumberOfTokenHolders() external view returns (uint256) {
        return shareholders.length;
    }

    function getShareHoldersList() external view returns (address[] memory) {
        return shareholders;
    }

    function totalDistributedRewards() external view returns (uint256) {
        return totalDistributed;
    }

    function addShareholder(address shareholder) internal {
        shareholderIndexes[shareholder] = shareholders.length;
        shareholders.push(shareholder);
    }

    function removeShareholder(address shareholder) internal {
        shareholders[shareholderIndexes[shareholder]] = shareholders[
            shareholders.length - 1
        ];
        shareholderIndexes[
            shareholders[shareholders.length - 1]
        ] = shareholderIndexes[shareholder];
        shareholders.pop();
    }
}

contract TXHASHDOME is IERC20, Ownable {
    using SafeMath for uint256;

    //address WBNB    = 0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd;
    address WBNB = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;

    address DEAD = 0x000000000000000000000000000000000000dEaD;
    address ZERO = 0x0000000000000000000000000000000000000000;

    // Swap token can be set to a non-WBNB token if desired
    //address public SWAPTOKEN    = 0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd;
    address public SWAPTOKEN = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;

    // USDT Reward
    //address public REWARD   = 0xeD24FC36d5Ee211Ea25A80239Fb8C4Cfd80f12Ee;
    address public REWARD = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;

    string public constant _name = "TxHash Dome";
    string public constant _symbol = "TxHD";
    uint8 public constant _decimals = 18;
    uint256 public _totalSupply = 100_000_000_000 * (10**_decimals);
    uint256 public _maxTxAmount = _totalSupply.div(200); //.5%
    uint256 public _maxWalletAmount = _totalSupply.div(100); //1%

    bool public tradingStart = false;

    mapping(address => uint256) _balances;
    mapping(address => mapping(address => uint256)) _allowances;

    mapping(address => bool) isFeeExempt;
    mapping(address => bool) isDividendExempt;

    // Buy fees - 10% - base 1000
    uint256 public buyDividendRewardsFee = 0;
    uint256 public buyMarketingFee = 40;
    uint256 public buyLiquidityFee = 20;
    uint256 public buyDevFee = 30;
    uint256 public buyBurnFee = 0;
    uint256 public buyCharityFee = 10;
    uint256 public buyTotalFees = 100;

    // Sell fees - 12% - base 1000
    uint256 public sellDividendRewardsFee = 0;
    uint256 public sellMarketingFee = 50;
    uint256 public sellLiquidityFee = 20;
    uint256 public sellDevFee = 40;
    uint256 public sellBurnFee = 0;
    uint256 public sellCharityFee = 10;
    uint256 public sellTotalFees = 120;

    uint256 public totalLiquidityFee = buyLiquidityFee.add(sellLiquidityFee);
    uint256 public totalMarketingFee = buyMarketingFee.add(sellMarketingFee);
    uint256 public totalDevFee = buyDevFee.add(sellDevFee);
    uint256 public totalBurnFee = buyBurnFee.add(sellBurnFee);
    uint256 public totalCharityFee = buyCharityFee.add(sellCharityFee);
    uint256 public totalDividendRewardsFee =
        buyDividendRewardsFee.add(sellDividendRewardsFee);
    uint256 public totalFees = buyTotalFees.add(sellTotalFees);

    address public marketingFeeReceiver =
        0xa559115d3a5A7d82d39Bd5Fb0c6B9f2B556A6467;
    address public devFeeReceiver = 0xc9243539FdBd1d7707E9234c2036f380d67c2f11;
    address public charityFeeReceiver =
        0xA7F4784606dC04E32a129b63322824BF242052a9;
    address public LPReceiver = 0x808d5f4f990B861d764b24b3dD6bB41246E7CedF;

    IUniswapV2Router02 public router;
    address public pair;

    DividendDistributor public dividendDistributor;
    uint256 distributorGas = 500000;

    event AutoLiquify(uint256 amountBNB, uint256 amountBOG);
    event SendFeesInToken(address wallet, uint256 amount);
    event ChangeRewardTracker(address token);
    event IncludeInReward(address holder);

    bool public swapEnabled = true;

    // Swap threshold is set at .01% of supply currently, 10m tokens
    uint256 public swapThreshold = _totalSupply.div(10000);
    bool inSwap;
    modifier swapping() {
        inSwap = true;
        _;
        inSwap = false;
    }

    constructor() {
        //router      = IUniswapV2Router02(0x9Ac64Cc6e4415144C455BD8E4837Fea55603e5c3);
        router = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);

        pair = IUniswapV2Factory(router.factory()).createPair(
            WBNB,
            address(this)
        );

        _allowances[address(this)][address(router)] = type(uint256).max;

        dividendDistributor = new DividendDistributor(address(router), REWARD);

        isFeeExempt[msg.sender] = true;
        isDividendExempt[msg.sender] = true;

        isDividendExempt[pair] = true;
        isDividendExempt[address(this)] = true;
        isDividendExempt[DEAD] = true;

        isFeeExempt[marketingFeeReceiver] = true;
        isFeeExempt[devFeeReceiver] = true;
        isFeeExempt[charityFeeReceiver] = true;

        _balances[msg.sender] = _totalSupply;
        emit Transfer(address(0), msg.sender, _totalSupply);
    }

    receive() external payable {}

    function totalSupply() external view override returns (uint256) {
        return _totalSupply;
    }

    function name() public pure returns (string memory) {
        return _name;
    }

    function symbol() public pure returns (string memory) {
        return _symbol;
    }

    function decimals() public pure returns (uint8) {
        return _decimals;
    }

    function balanceOf(address account) public view override returns (uint256) {
        return _balances[account];
    }

    // tracker dashboard functions
    function getHolderDetails(address holder)
        public
        view
        returns (
            uint256,
            uint256,
            uint256,
            uint256
        )
    {
        return dividendDistributor.getHolderDetails(holder);
    }

    function getLastProcessedIndex() public view returns (uint256) {
        return dividendDistributor.getLastProcessedIndex();
    }

    function getNumberOfTokenHolders() public view returns (uint256) {
        return dividendDistributor.getNumberOfTokenHolders();
    }

    function totalDistributedRewards() public view returns (uint256) {
        return dividendDistributor.totalDistributedRewards();
    }

    function allowance(address holder, address spender)
        external
        view
        override
        returns (uint256)
    {
        return _allowances[holder][spender];
    }

    function approve(address spender, uint256 amount)
        public
        override
        returns (bool)
    {
        _allowances[msg.sender][spender] = amount;
        emit Approval(msg.sender, spender, amount);
        return true;
    }

    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);
    }

    function approveMax(address spender) external returns (bool) {
        return approve(spender, type(uint256).max);
    }

    function transfer(address recipient, uint256 amount)
        external
        override
        returns (bool)
    {
        return _transferFrom(msg.sender, recipient, amount);
    }

    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external override returns (bool) {
        if (_allowances[sender][msg.sender] != type(uint256).max) {
            _allowances[sender][msg.sender] = _allowances[sender][msg.sender]
                .sub(amount, "Insufficient Allowance");
        }

        return _transferFrom(sender, recipient, amount);
    }

    function _transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) internal returns (bool) {
        if (inSwap) {
            return _basicTransfer(sender, recipient, amount);
        }

        if (!isFeeExempt[sender] && !isFeeExempt[recipient]) {
            require(tradingStart == true, "Trading not started yet");

            if (sender == pair) {
                require(
                    amount <= _maxTxAmount,
                    "Transfer amount exceeds the maxTxAmount"
                );

                uint256 contractBalanceRecepient = balanceOf(recipient);
                require(
                    contractBalanceRecepient + amount <= _maxWalletAmount,
                    "Exceeds max wallet token amount"
                );
            }
        }

        if (shouldSwapBack()) {
            if (SWAPTOKEN == WBNB) {
                swapBackInBnb();
            } else {
                swapBackInTokens();
            }
        }

        //Exchange tokens
        _balances[sender] = _balances[sender].sub(
            amount,
            "Insufficient Balance"
        );

        uint256 amountReceived = shouldTakeFee(sender, recipient)
            ? takeFee(sender, amount, recipient)
            : amount;
        _balances[recipient] = _balances[recipient].add(amountReceived);

        // Dividend tracker
        if (!isDividendExempt[sender]) {
            try
                dividendDistributor.setShare(sender, _balances[sender])
            {} catch {}
        }

        if (!isDividendExempt[recipient]) {
            try
                dividendDistributor.setShare(recipient, _balances[recipient])
            {} catch {}
        }

        try dividendDistributor.process(distributorGas) {} catch {}

        emit Transfer(sender, recipient, amountReceived);
        return true;
    }

    function _basicTransfer(
        address sender,
        address recipient,
        uint256 amount
    ) internal returns (bool) {
        _balances[sender] = _balances[sender].sub(
            amount,
            "Insufficient Balance"
        );
        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
        return true;
    }

    function shouldTakeFee(address sender, address recipient)
        internal
        view
        returns (bool)
    {
        return (!isFeeExempt[sender] && !isFeeExempt[recipient]);
    }

    function takeFee(
        address sender,
        uint256 amount,
        address to
    ) internal returns (uint256) {
        uint256 feeAmount = 0;
        uint256 burnFee = 0;

        if (to == pair) {
            feeAmount = amount.mul(sellTotalFees).div(1000);

            if (sellBurnFee > 0) {
                burnFee = feeAmount.mul(sellBurnFee).div(sellTotalFees);
                _balances[DEAD] = _balances[DEAD].add(burnFee);
                emit Transfer(sender, DEAD, burnFee);
            }
        } else {
            feeAmount = amount.mul(buyTotalFees).div(1000);

            if (buyBurnFee > 0) {
                burnFee = feeAmount.mul(buyBurnFee).div(buyTotalFees);
                _balances[DEAD] = _balances[DEAD].add(burnFee);
                emit Transfer(sender, DEAD, burnFee);
            }
        }

        uint256 feesToContract = feeAmount.sub(burnFee);
        _balances[address(this)] = _balances[address(this)].add(feesToContract);
        emit Transfer(sender, address(this), feesToContract);

        return amount.sub(feeAmount);
    }

    function shouldSwapBack() internal view returns (bool) {
        return
            msg.sender != pair &&
            !inSwap &&
            swapEnabled &&
            _balances[address(this)] >= swapThreshold;
    }

    function clearStuckBalance(uint256 amountPercentage) external onlyOwner {
        uint256 amountBNB = address(this).balance;
        payable(msg.sender).transfer(amountBNB.mul(amountPercentage).div(100));
    }

    function changeSwapToken(address token) external onlyOwner {
        SWAPTOKEN = token;
    }

    // Taxes are set based on 1000
    // Where 10 is equal to a 1% tax (10/1000 = 1%)
    function updateBuyFees(
        uint256 reward,
        uint256 marketing,
        uint256 liquidity,
        uint256 dev,
        uint256 burn,
        uint256 charity
    ) public onlyOwner {
        require(
            (reward + marketing + liquidity + dev + burn + charity) <= 250,
            "Total Fee must be less than 25%"
        );

        buyDividendRewardsFee = reward;
        buyMarketingFee = marketing;
        buyLiquidityFee = liquidity;
        buyDevFee = dev;
        buyBurnFee = burn;
        buyCharityFee = charity;
        buyTotalFees = reward
            .add(marketing)
            .add(liquidity)
            .add(dev)
            .add(burn)
            .add(charity);

        totalLiquidityFee = buyLiquidityFee.add(sellLiquidityFee);
        totalMarketingFee = buyMarketingFee.add(sellMarketingFee);
        totalDevFee = buyDevFee.add(sellDevFee);
        totalBurnFee = buyBurnFee.add(sellBurnFee);
        totalCharityFee = buyCharityFee.add(sellCharityFee);
        totalDividendRewardsFee = buyDividendRewardsFee.add(
            sellDividendRewardsFee
        );
        totalFees = buyTotalFees.add(sellTotalFees);
    }

    // Taxes are set based on 1000
    // Where 10 is equal to a 1% tax (10/1000 = 1%)
    function updateSellFees(
        uint256 reward,
        uint256 marketing,
        uint256 liquidity,
        uint256 dev,
        uint256 burn,
        uint256 charity
    ) public onlyOwner {
        require(
            (reward + marketing + liquidity + dev + burn + charity) <= 250,
            "Total Fee must be less than 25%"
        );

        sellDividendRewardsFee = reward;
        sellMarketingFee = marketing;
        sellLiquidityFee = liquidity;
        sellDevFee = dev;
        sellBurnFee = burn;
        sellCharityFee = charity;
        sellTotalFees = reward
            .add(marketing)
            .add(liquidity)
            .add(dev)
            .add(burn)
            .add(charity);

        totalLiquidityFee = buyLiquidityFee.add(sellLiquidityFee);
        totalMarketingFee = buyMarketingFee.add(sellMarketingFee);
        totalDevFee = buyDevFee.add(sellDevFee);
        totalBurnFee = buyBurnFee.add(sellBurnFee);
        totalCharityFee = buyCharityFee.add(sellCharityFee);
        totalDividendRewardsFee = buyDividendRewardsFee.add(
            sellDividendRewardsFee
        );
        totalFees = buyTotalFees.add(sellTotalFees);
    }

    function whitelistPreSalePlatform(address _preSale) public onlyOwner {
        isFeeExempt[_preSale] = true;
        isDividendExempt[_preSale] = true;
    }