// File: ChainFactory.sol



/*
   ________          _       ______           __                  
  / ____/ /_  ____ _(_)___  / ____/___ ______/ /_____  _______  __
 / /   / __ \/ __ `/ / __ \/ /_  / __ `/ ___/ __/ __ \/ ___/ / / /
/ /___/ / / / /_/ / / / / / __/ / /_/ / /__/ /_/ /_/ / /  / /_/ / 
\____/_/ /_/\__,_/_/_/ /_/_/    \__,_/\___/\__/\____/_/   \__, /  
                                                         /____/   
  Smart-Contract generated and deployed by ChainFactory

  Web:      https://chainfactory.app/
  X:        https://x.com/ChainFactoryApp
  Telegram: https://t.me/ChainFactory
  Discord:  https://discord.gg/fpjxD39v3k
  YouTube:  https://youtube.com/@UpfrontDeFi

  By using this Smart-Contract generated and deployed by ChainFactory,
  you acknowledge and agree that ChainFactory shall not be liable for any
  damages arising from the use of this Smart-Contract, including but not
  limited to any damages resulting from any malicious or illegal use of
  the Smart-Contract by any third party or by the owner.

  The owner of the Smart-Contract generated by ChainFactory agrees not to
  misuse the Smart-Contract, including but not limited to:

  - Using the Smart-Contract to engage in any illegal or fraudulent
    activity, including but not limited to scams, theft, or money
    laundering.

  - Using the Smart-Contract in any manner that could cause harm to
    others, including but not limited to disrupting financial
    markets or causing financial loss to others.

  - Using the Smart-Contract to infringe upon the intellectual
    property rights of others, including but not limited to
    copyright, trademark, or patent infringement.

  The owner of the Smart-Contract generated by ChainFactory acknowledges
  that any misuse of the Smart-Contract may result in legal action,
  and agrees to indemnify and hold harmless ChainFactory from any and all
  claims, damages, or expenses arising from any such misuse.

*/

// SPDX-License-Identifier: MIT

pragma solidity 0.8.23;

import "./CF_Ownable.sol";
import "./CF_Common.sol";
import "./CF_ERC20.sol";
import "./CF_Recoverable.sol";
import "./CF_Burnable.sol";
import "./CF_Blacklist.sol";
import "./CF_Whitelist.sol";
import "./CF_Cooldown.sol";
import "./CF_MaxBalance.sol";
import "./CF_Taxable.sol";
import "./CF_DEXRouterV2.sol";

contract ChainFactory is CF_Ownable, CF_Common, CF_ERC20, CF_Recoverable, CF_Burnable, CF_Blacklist, CF_Whitelist, CF_Cooldown, CF_MaxBalance, CF_Taxable, CF_DEXRouterV2 {
  constructor() {
    _name = unicode"ChainFactory";
    _symbol = unicode"FACTORY";
    _decimals = 18;
    _totalSupply = 75000000000000000000000000; // 75,000,000 FACTORY
    _transferOwnership(0xb8F8a463a725502B5E0642bB0dc55CA8d1675434);
    _transferInitialSupply(0xb8F8a463a725502B5E0642bB0dc55CA8d1675434, 100000); // 100%
    _setEarlyPenaltyTime(120); // 2min
    _setDEXRouter(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D, 0xb8F8a463a725502B5E0642bB0dc55CA8d1675434);
    _setReflection(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
    _setMinSwapPercent(500); // 0.5% of totalSupply
    _setMinTaxDistributionPercent(500); // 0.5% of totalSupply
    _setTaxBeneficiary(0, 0x6Aa1f46Fd34dDAa9f5EFcaB3Ebd43c54a87Cbf8E, [ uint24(0), uint24(5000), uint24(5000) ], [ uint24(40000), uint24(40000), uint24(40000) ]);
    _initialWhitelist([ 0xb8F8a463a725502B5E0642bB0dc55CA8d1675434 ]);
    _setCooldown(5, 3600, 3600); // 5 tx in 1h will result in a 1h freeze
    _setMaxBalancePercent(2000); // 2% of totalSupply
    _domainSeparator = keccak256(abi.encode(keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(_name)), keccak256(bytes("1")), block.chainid, address(this)));
    _initialized = true;
  }

  function _transfer(address from, address to, uint256 amount) internal virtual override {
    require(!_blacklisted[from] && !_blacklisted[to], "Blacklisted");
    require(to != address(0xdEaD));

    if (!_distributing && !_swapping && (from != _dex.pair && from != _dex.router)) {
      _autoSwap(false);
      _autoTaxDistribute(false);
    }

    if (amount > 0 && !_whitelisted[from] && !_whitelisted[to] && from != address(this) && to != address(this) && to != _dex.router) {
      require((from != _dex.pair && to != _dex.pair) || ((from == _dex.pair || to == _dex.pair) && _tradingEnabled > 0), "Trading disabled");

      unchecked {
        if (_cooldownPeriod > 0 && from != _dex.pair) {
          require(remainingCooldownTime(from) == 0, "Cooldown");

          if (_holder[from].start + _cooldownTriggerTime < _timestamp()) {
            _holder[from].count = 1;
            _holder[from].start = _timestamp();
          } else {
            if (++_holder[from].count >= _cooldownTriggerCount) { _cooldown(from); }
          }
        }

        require(_maxBalanceAmount == 0 || to == address(this) || (to == _dex.pair || to == _dex.router) || _balance[to] + amount <= _maxBalanceAmount, "Exceeds maxBalance");

        if (!_suspendTaxes && !_distributing && !_swapping) {
          uint256 appliedTax;
          uint8 taxType;

          if (from == _dex.pair || to == _dex.pair) { taxType = from == _dex.pair ? 1 : 2; }

          address _account = taxType == 1 ? to : from;

          if (_tradingEnabled + _earlyPenaltyTime >= _timestamp() && !_holder[_account].penalty) { _holder[_account].penalty = true; }

          for (uint8 i; i < 5; i++) {
            uint256 percent = uint256(taxType > 0 ? (taxType == 1 ? (_holder[_account].penalty ? _taxBeneficiary[i].penalty[1] : _taxBeneficiary[i].percent[1]) : (_holder[_account].penalty ? _taxBeneficiary[i].penalty[2] : _taxBeneficiary[i].percent[2])) : (_holder[_account].penalty ? _taxBeneficiary[i].penalty[0] : _taxBeneficiary[i].percent[0]));

            if (percent == 0) { continue; }

            uint256 taxAmount = _percentage(amount, percent);

            super._transfer(from, address(this), taxAmount);

            if (_taxBeneficiary[i].account == _dex.pair) {
              _amountForLiquidity += taxAmount;
            } else if (_taxBeneficiary[i].account == address(0xdEaD)) {
              _burn(address(this), taxAmount);
            } else {
              _taxBeneficiary[i].unclaimed += taxAmount;
              _amountForTaxDistribution += taxAmount;
            }

            appliedTax += taxAmount;
          }

          if (appliedTax > 0) {
            _totalTaxCollected += appliedTax;

            amount -= appliedTax;
          }
        }
      }
    }

    super._transfer(from, to, amount);
  }

  function _burn(address account, uint256 amount) internal virtual override {
    super._burn(account, amount);

    _setMaxBalancePercent(_maxBalancePercent);
    _setMinTaxDistributionPercent(_minTaxDistributionPercent);
    _setMinSwapPercent(_minSwapPercent);
  }

  function _transferInitialSupply(address account, uint24 percent) private {
    require(!_initialized);

    uint256 amount = _percentage(_totalSupply, uint256(percent));
    _balance[account] = amount;

    emit Transfer(address(0), account, amount);
  }

  /// @notice Returns a list specifying the renounce status of each feature
  function renounced() external view returns (bool Blacklist, bool Whitelist, bool Cooldown, bool MaxBalance, bool Taxable, bool DEXRouterV2) {
    return (_renounced.Blacklist, _renounced.Whitelist, _renounced.Cooldown, _renounced.MaxBalance, _renounced.Taxable, _renounced.DEXRouterV2);
  }

  /// @notice Returns basic information about this Smart-Contract
  function info() external view returns (string memory name, string memory symbol, uint8 decimals, address owner, uint256 totalSupply, string memory version) {
    return (_name, _symbol, _decimals, _owner, _totalSupply, _version);
  }

  receive() external payable { }
  fallback() external payable { }
}

// File: CF_Ownable.sol



// SPDX-License-Identifier: MIT

pragma solidity 0.8.23;

abstract contract CF_Ownable {
  address internal _owner;

  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

  modifier onlyOwner() {
    require(_owner == msg.sender, "Unauthorized");

    _;
  }

  function owner() external view returns (address) {
    return _owner;
  }

  function renounceOwnership() external onlyOwner {
    _transferOwnership(address(0));
  }

  function transferOwnership(address newOwner) external onlyOwner {
    require(newOwner != address(0));

    _transferOwnership(newOwner);
  }

  function _transferOwnership(address newOwner) internal {
    address oldOwner = _owner;
    _owner = newOwner;

    emit OwnershipTransferred(oldOwner, newOwner);
  }
}

// File: CF_Common.sol



// SPDX-License-Identifier: MIT

pragma solidity 0.8.23;

import "./IDEXV2.sol";
import "./IERC20.sol";

abstract contract CF_Common {
  string internal constant _version = "1.0.0";

  mapping(address => uint256) internal _balance;
  mapping(address => mapping(address => uint256)) internal _allowance;
  mapping(address => bool) internal _blacklisted;
  mapping(address => bool) internal _whitelisted;
  mapping(address => holderAccount) internal _holder;
  mapping(uint8 => taxBeneficiary) internal _taxBeneficiary;

  address[] internal _holders;

  bool internal _swapEnabled;
  bool internal _swapping;
  bool internal _suspendTaxes;
  bool internal _distributing;
  bool internal immutable _initialized;

  uint8 internal immutable _decimals;
  uint8 internal _cooldownTriggerCount;
  uint24 internal constant _denominator = 1000;
  uint24 internal _maxBalancePercent;
  uint24 internal _totalTxTax;
  uint24 internal _totalBuyTax;
  uint24 internal _totalSellTax;
  uint24 internal _totalPenaltyTxTax;
  uint24 internal _totalPenaltyBuyTax;
  uint24 internal _totalPenaltySellTax;
  uint24 internal _minTaxDistributionPercent;
  uint24 internal _minSwapPercent;
  uint32 internal _lastTaxDistribution;
  uint32 internal _tradingEnabled;
  uint32 internal _lastSwap;
  uint32 internal _earlyPenaltyTime;
  uint32 internal _cooldownTriggerTime;
  uint32 internal _cooldownPeriod;
  uint256 internal _totalSupply;
  uint256 internal _totalBurned;
  uint256 internal _maxBalanceAmount;
  uint256 internal _totalTaxCollected;
  uint256 internal _minTaxDistributionAmount;
  uint256 internal _amountForTaxDistribution;
  uint256 internal _amountSwappedForTaxDistribution;
  uint256 internal _minSwapAmount;
  uint256 internal _amountForLiquidity;
  uint256 internal _ethForTaxDistribution;
  uint256 internal _reflectionTokensForTaxDistribution;

  struct Renounced {
    bool Blacklist;
    bool Whitelist;
    bool Cooldown;
    bool MaxBalance;
    bool Taxable;
    bool DEXRouterV2;
  }

  struct holderAccount {
    bool exists;
    bool penalty;
    uint32 count;
    uint32 start;
    uint32 cooldown;
  }

  struct taxBeneficiary {
    bool exists;
    address account;
    uint24[3] percent; // 0: tx, 1: buy, 2: sell
    uint24[3] penalty;
    uint256 unclaimed;
  }

  struct DEXRouterV2 {
    address router;
    address pair;
    address WETH;
    address receiver;
  }

  Renounced internal _renounced;
  DEXRouterV2 internal _dex;
  IERC20 internal _reflectionToken;

  function _percentage(uint256 amount, uint256 bps) internal pure returns (uint256) {
    unchecked {
      return (amount * bps) / (100 * uint256(_denominator));
    }
  }

  function _timestamp() internal view returns (uint32) {
    unchecked {
      return uint32(block.timestamp % 2**32);
    }
  }

  function version() external pure returns (string memory) {
    return _version;
  }

  function denominator() external view returns (uint24) {
    return _denominator;
  }
}

// File: CF_ERC20.sol



// SPDX-License-Identifier: MIT

pragma solidity 0.8.23;

import "./CF_Common.sol";

abstract contract CF_ERC20 is CF_Common {
  string internal _name;
  string internal _symbol;
  bytes32 internal _domainSeparator;
  bytes32 private constant PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
  mapping(address => uint256) private _nonces;

  event Transfer(address indexed from, address indexed to, uint256 value);
  event Approval(address indexed owner, address indexed spender, uint256 value);

  function name() external view returns (string memory) {
    return _name;
  }

  function symbol() external view returns (string memory) {
    return _symbol;
  }

  function decimals() external view returns (uint8) {
    return _decimals;
  }

  function totalSupply() external view returns (uint256) {
    return _totalSupply;
  }

  function balanceOf(address account) external view returns (uint256) {
    return _balance[account];
  }

  function allowance(address owner, address spender) public view returns (uint256) {
    return _allowance[owner][spender];
  }

  function approve(address spender, uint256 amount) external returns (bool) {
    _approve(msg.sender, spender, amount);

    return true;
  }

  function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external {
    require(deadline >= block.timestamp, "Expired signature");

    unchecked {
      bytes32 digest = keccak256(abi.encodePacked(hex"1901", _domainSeparator, keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, _nonces[owner]++, deadline))));
      address recoveredAddress = ecrecover(digest, v, r, s);

      require(recoveredAddress != address(0) && recoveredAddress == owner, "Invalid signature");
    }

    _approve(owner, spender, value);
  }

  function nonces(address owner) external view returns (uint256) {
    return _nonces[owner];
  }

  function DOMAIN_SEPARATOR() external view returns (bytes32) {
    return _domainSeparator;
  }

  function transfer(address to, uint256 amount) external returns (bool) {
    _transfer(msg.sender, to, amount);

    return true;
  }

  function transferFrom(address from, address to, uint256 amount) external returns (bool) {
    _spendAllowance(from, msg.sender, amount);
    _transfer(from, to, amount);

    return true;
  }

  function increaseAllowance(address spender, uint256 addedValue) external returns (bool) {
    unchecked {
      _approve(msg.sender, spender, allowance(msg.sender, spender) + addedValue);
    }

    return true;
  }

  function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool) {
    uint256 currentAllowance = allowance(msg.sender, spender);

    require(currentAllowance >= subtractedValue, "Negative allowance");

    unchecked {
      _approve(msg.sender, spender, currentAllowance - subtractedValue);
    }

    return true;
  }

  function _approve(address owner, address spender, uint256 amount) internal {
    _allowance[owner][spender] = amount;

    emit Approval(owner, spender, amount);
  }

  function _spendAllowance(address owner, address spender, uint256 amount) internal {
    uint256 currentAllowance = allowance(owner, spender);

    require(currentAllowance >= amount, "Insufficient allowance");

    unchecked {
      _approve(owner, spender, currentAllowance - amount);
    }
  }

  function _transfer(address from, address to, uint256 amount) internal virtual {
    require(from != address(0) && to != address(0), "Transfer from/to zero address");
    require(_balance[from] >= amount, "Exceeds balance");

    if (amount > 0) {
      unchecked {
        _balance[from] -= amount;
        _balance[to] += amount;
      }
    }

    emit Transfer(from, to, amount);
  }
}

// File: CF_Recoverable.sol



// SPDX-License-Identifier: MIT

pragma solidity 0.8.23;

import "./CF_Ownable.sol";
import "./CF_Common.sol";

abstract contract CF_Recoverable is CF_Ownable, CF_Common {
  /// @notice Recovers a misplaced amount of an ERC-20 token sitting in the contract balance
  /// @dev Beware of scam tokens!
  /// @dev Amounts allocated for tax distribution and liquidity cannot be recovered unless forced
  /// @param token Address of the ERC-20 token
  /// @param to Recipient
  /// @param amount Amount to be transferred
  /// @param force Retrieve amounts allocated for tax distribution and liquidity if needed
  function recoverERC20(address token, address to, uint256 amount, bool force) external onlyOwner {
    unchecked {
      uint256 balance = IERC20(token).balanceOf(address(this));
      uint256 allocated = token == address(this) ? _amountForTaxDistribution + _amountForLiquidity : (address(_reflectionToken) == token ? _reflectionTokensForTaxDistribution : 0);

      require((!force && balance - (allocated >= balance ? balance : allocated) >= amount) || (force && balance >= amount), "Exceeds balance");

      if (force && (token == address(this) || address(_reflectionToken) == token) && balance - (allocated >= balance ? balance : allocated) < amount) {
        require(!_distributing && !_swapping);

        if (token == address(this)) {
          uint256 pickFromAmountForTaxDistribution = amount >= _amountForTaxDistribution ? _amountForTaxDistribution : _amountForTaxDistribution - amount;

          _amountForTaxDistribution -= pickFromAmountForTaxDistribution;
          allocated -= pickFromAmountForTaxDistribution;

          if (balance - (allocated >= balance ? balance : allocated) < amount) { _amountForLiquidity -= amount >= _amountForLiquidity ? _amountForLiquidity : _amountForLiquidity - amount; }
        } else if (address(_reflectionToken) == token) {
          _reflectionTokensForTaxDistribution -= amount >= _reflectionTokensForTaxDistribution ? _reflectionTokensForTaxDistribution : _reflectionTokensForTaxDistribution - amount;
        }
      }
    }

    IERC20(token).transfer(to, amount);
  }

  /// @notice Recovers a misplaced amount of native ETH sitting in the contract balance
  /// @dev Amounts allocated for tax distribution and/or liquidity cannot be recovered unless forced
  /// @param to Recipient
  /// @param amount Amount of ETH to be transferred
  /// @param force Retrieve amounts allocated for tax distribution and liquidity if needed
  function recoverETH(address payable to, uint256 amount, bool force) external onlyOwner {
    unchecked {
      uint256 balance = address(this).balance;
      uint256 allocated = address(_reflectionToken) == _dex.WETH ? _ethForTaxDistribution : 0;

      require((!force && balance - (allocated >= balance ? balance : allocated) >= amount) || (force && balance >= amount), "Exceeds balance");

      if (force && address(_reflectionToken) == _dex.WETH && balance - (allocated >= balance ? balance : allocated) < amount) {
        require(!_distributing && !_swapping);

        _ethForTaxDistribution -= amount >= _ethForTaxDistribution ? _ethForTaxDistribution : _ethForTaxDistribution - amount;
      }
    }

    (bool success, ) = to.call{ value: amount }("");

    require(success);
  }
}

// File: CF_Burnable.sol



// SPDX-License-Identifier: MIT

pragma solidity 0.8.23;

import "./CF_Common.sol";
import "./CF_ERC20.sol";

abstract contract CF_Burnable is CF_Common, CF_ERC20 {
  /// @notice Total amount of tokens burned so far
  function totalBurned() external view returns (uint256) {
    return _totalBurned;
  }

  function burn(uint256 amount) external {
    _burn(msg.sender, amount);
  }

  function burnFrom(address account, uint256 amount) external {
    _spendAllowance(account, msg.sender, amount);
    _burn(account, amount);
  }

  function _burn(address account, uint256 amount) internal virtual {
    require(_balance[account] >= amount, "Exceeds balance");

    unchecked {
      _balance[account] -= amount;
      _totalSupply -= amount;
      _totalBurned += amount;
    }

    emit Transfer(account, address(0xdEaD), amount);
  }
}

// File: CF_Blacklist.sol



// SPDX-License-Identifier: MIT

pragma solidity 0.8.23;

import "./CF_Ownable.sol";
import "./CF_Common.sol";

abstract contract CF_Blacklist is CF_Ownable, CF_Common {
  event Blacklisted(address indexed account, bool status);
  event RenouncedBlacklist();

  /// @notice Permanently renounce and prevent the owner from being able to update the blacklist
  /// @dev Existing entries will continue to be effective
  function renounceBlacklist() external onlyOwner {
    _renounced.Blacklist = true;

    emit RenouncedBlacklist();
  }

  /// @notice Check if an address is blacklisted.
  /// @param account Address to check
  function isBlacklisted(address account) external view returns (bool) {
    return _blacklisted[account];
  }

  /// @notice Add or remove an address from the blacklist
  /// @param status True for adding, False for removing
  function blacklist(address account, bool status) public onlyOwner {
    _blacklist(account, status);
  }

  function _blacklist(address account, bool status) internal {
    require(!_renounced.Blacklist);
    require(account != _owner && account != address(0) && account != address(0xdEaD));
    require(account != _dex.router && account != _dex.pair, "DEX router or pair");

    if (status) { require(!_whitelisted[account], "Whitelisted"); }

    _blacklisted[account] = status;

    emit Blacklisted(account, status);
  }

  /// @notice Add or remove multiple addresses from the blacklist
  /// @param status True for adding, False for removing
  function blacklist(address[] calldata accounts, bool status) external onlyOwner {
    unchecked {
      uint256 cnt = accounts.length;

      for (uint256 i; i < cnt; i++) { _blacklist(accounts[i], status); }
    }
  }
}

// File: CF_Whitelist.sol



// SPDX-License-Identifier: MIT

pragma solidity 0.8.23;

import "./CF_Ownable.sol";
import "./CF_Common.sol";

abstract contract CF_Whitelist is CF_Ownable, CF_Common {
  event Whitelisted(address indexed account, bool status);
  event RenouncedWhitelist();

  /// @notice Permanently renounce and prevent the owner from being able to update the whitelist
  /// @dev Existing entries will continue to be effective
  function renounceWhitelist() external onlyOwner {
    _renounced.Whitelist = true;

    emit RenouncedWhitelist();
  }

  /// @notice Check if an address is whitelisted
  /// @param account Address to check
  function isWhitelisted(address account) external view returns (bool) {
    return _whitelisted[account];
  }

  /// @notice Add or remove an address from the whitelist
  /// @param status True for adding, False for removing
  function whitelist(address account, bool status) public onlyOwner {
    _whitelist(account, status);
  }

  function _whitelist(address account, bool status) internal {
    require(!_renounced.Whitelist);
    require(account != address(0) && account != address(0xdEaD));
    require(account != _dex.router && account != _dex.pair, "DEX router and pair are privileged");

    if (status) { require(!_blacklisted[account], "Blacklisted"); }

    _whitelisted[account] = status;

    emit Whitelisted(account, status);
  }

  /// @notice Add or remove multiple addresses from the whitelist
  /// @param status True for adding, False for removing
  function whitelist(address[] calldata accounts, bool status) external onlyOwner {
    unchecked {
      uint256 cnt = accounts.length;

      for (uint256 i; i < cnt; i++) { _whitelist(accounts[i], status); }
    }
  }

  function _initialWhitelist(address[1] memory accounts) internal {
    require(!_initialized);

    unchecked {
      for (uint256 i; i < 1; i++) { _whitelist(accounts[i], true); }
    }
  }
}

// File: CF_Cooldown.sol



// SPDX-License-Identifier: MIT

pragma solidity 0.8.23;

import "./CF_Ownable.sol";
import "./CF_Common.sol";

abstract contract CF_Cooldown is CF_Ownable, CF_Common {
  event SetCooldown(uint8 count, uint32 time, uint32 period);
  event RenouncedCooldown();

  /// @notice Permanently renounce and prevent the owner from being able to update cooldown features
  /// @dev Existing settings will continue to be effective
  function renounceCooldown() external onlyOwner {
    _renounced.Cooldown = true;

    emit RenouncedCooldown();
  }

  /// @notice Set cooldown settings
  /// @param count Number of transfers
  /// @param time Seconds during which the number of transfers will be taken into account
  /// @param period Seconds during which the wallet will be in cooldown
  function setCooldown(uint8 count, uint32 time, uint32 period) external onlyOwner {
    require(!_renounced.Cooldown);

    _setCooldown(count, time, period);
  }

  function _setCooldown(uint8 count, uint32 time, uint32 period) internal {
    require(count > 1 && time > 5);

    _cooldownTriggerCount = count;
    _cooldownTriggerTime = time;
    _cooldownPeriod = period;

    emit SetCooldown(count, time, period);
  }

  function _cooldown(address account) internal {
    unchecked {
      _holder[account].cooldown = _timestamp() + _cooldownPeriod;
    }
  }

  /// @notice Removes the cooldown status of a wallet
  /// @param account Address to unfreeze
  function removeCooldown(address account) external onlyOwner {
    require(!_renounced.Cooldown);

    _holder[account].count = 0;
    _holder[account].start = 0;
    _holder[account].cooldown = 0;
  }

  /// @notice Check if a wallet is currently in cooldown
  /// @param account Address to check
  /// @return Remaining seconds in cooldown
  function remainingCooldownTime(address account) public view returns (uint32) {
    if (_cooldownPeriod == 0 || !_holder[account].exists || _holder[account].cooldown < _timestamp()) { return 0; }

    unchecked {
      return _holder[account].cooldown - _timestamp();
    }
  }
}

// File: CF_MaxBalance.sol



// SPDX-License-Identifier: MIT

pragma solidity 0.8.23;

import "./CF_Ownable.sol";
import "./CF_Common.sol";

abstract contract CF_MaxBalance is CF_Ownable, CF_Common {
  event SetMaxBalancePercent(uint24 percent);
  event RenouncedMaxBalance();

  /// @notice Permanently renounce and prevent the owner from being able to update the max. balance
  /// @dev Existing settings will continue to be effective
  function renounceMaxBalance() external onlyOwner {
    _renounced.MaxBalance = true;

    emit RenouncedMaxBalance();
  }

  /// @notice Percentage of the max. balance per wallet, depending on total supply
  function getMaxBalancePercent() external view returns (uint24) {
    return _maxBalancePercent;
  }

  /// @notice Set the max. percentage of a wallet balance, depending on total supply
  /// @param percent Desired percentage, multiplied by denominator
  function setMaxBalancePercent(uint24 percent) external onlyOwner {
    require(!_renounced.MaxBalance);

    unchecked {
      require(percent <= 100 * _denominator);
    }

    _setMaxBalancePercent(percent);

    emit SetMaxBalancePercent(percent);
  }

  function _setMaxBalancePercent(uint24 percent) internal {
    _maxBalancePercent = percent;
    _maxBalanceAmount = percent > 0 ? _percentage(_totalSupply, uint256(percent)) : 0;

    if (!_initialized) { emit SetMaxBalancePercent(percent); }
  }
}

// File: CF_Taxable.sol



// SPDX-License-Identifier: MIT

pragma solidity 0.8.23;

import "./CF_Ownable.sol";
import "./CF_Common.sol";
import "./CF_ERC20.sol";

abstract contract CF_Taxable is CF_Ownable, CF_Common, CF_ERC20 {
  event SetTaxBeneficiary(uint8 slot, address account, uint24[3] percent, uint24[3] penalty);
  event SetEarlyPenaltyTime(uint32 time);
  event TaxDistributed(uint256 amount);
  event RenouncedTaxable();

  struct taxBeneficiaryView {
    address account;
    uint24[3] percent;
    uint24[3] penalty;
    uint256 unclaimed;
  }

  modifier lockDistributing {
    _distributing = true;
    _;
    _distributing = false;
  }

  /// @notice Permanently renounce and prevent the owner from being able to update the tax features
  /// @dev Existing settings will continue to be effective
  function renounceTaxable() external onlyOwner {
    _renounced.Taxable = true;

    emit RenouncedTaxable();
  }

  /// @notice Total amount of taxes collected so far
  function totalTaxCollected() external view returns (uint256) {
    return _totalTaxCollected;
  }

  /// @notice Tax applied per transfer
  /// @dev Taking in consideration your wallet address
  function txTax() external view returns (uint24) {
    return txTax(msg.sender);
  }

  /// @notice Tax applied per transfer
  /// @param from Sender address
  function txTax(address from) public view returns (uint24) {
    unchecked {
      return from == address(this) || _whitelisted[from] || from == _dex.pair ? 0 : (_holder[from].penalty || _tradingEnabled + _earlyPenaltyTime >= _timestamp() ? _totalPenaltyTxTax : _totalTxTax);
    }
  }

  /// @notice Tax applied for buying
  /// @dev Taking in consideration your wallet address
  function buyTax() external view returns (uint24) {
    return buyTax(msg.sender);
  }

  /// @notice Tax applied for buying
  /// @param from Buyer's address
  function buyTax(address from) public view returns (uint24) {
    unchecked {
      return from == address(this) || _whitelisted[from] || from == _dex.pair ? 0 : (_holder[from].penalty || _tradingEnabled + _earlyPenaltyTime >= _timestamp() ? _totalPenaltyBuyTax : _totalBuyTax);
    }
  }
  /// @notice Tax applied for selling
  /// @dev Taking in consideration your wallet address
  function sellTax() external view returns (uint24) {
    return sellTax(msg.sender);
  }

  /// @notice Tax applied for selling
  /// @param to Seller's address
  function sellTax(address to) public view returns (uint24) {
    unchecked {
      return to == address(this) || _whitelisted[to] || to == _dex.pair || to == _dex.router ? 0 : (_holder[to].penalty || _tradingEnabled + _earlyPenaltyTime >= _timestamp() ? _totalPenaltySellTax : _totalSellTax);
    }
  }

  /// @notice List of all tax beneficiaries and their assigned percentage, according to type of transfer
  /// @custom:return `list[].account` Beneficiary address
  /// @custom:return `list[].percent[3]` Index 0 is for tx tax, 1 is for buy tax, 2 is for sell tax, multiplied by denominator
  /// @custom:return `list[].penalty[3]` Index 0 is for tx penalty, 1 is for buy penalty, 2 is for sell penalty, multiplied by denominator
  function listTaxBeneficiaries() external view returns (taxBeneficiaryView[] memory list) {
    list = new taxBeneficiaryView[](5);

    unchecked {
      for (uint8 i; i < 5; i++) { list[i] = taxBeneficiaryView(_taxBeneficiary[i].account, _taxBeneficiary[i].percent, _taxBeneficiary[i].penalty, _taxBeneficiary[i].unclaimed); }
    }
  }

  /// @notice Sets a tax beneficiary
  /// @dev Maximum of 5 wallets can be assigned
  /// @param slot Slot number (0 to 4)
  /// @param account Beneficiary address
  /// @param percent[3] Index 0 is for tx tax, 1 is for buy tax, 2 is for sell tax, multiplied by denominator
  /// @param penalty[3] Index 0 is for tx penalty, 1 is for buy penalty, 2 is for sell penalty, multiplied by denominator
  function setTaxBeneficiary(uint8 slot, address account, uint24[3] memory percent, uint24[3] memory penalty) external onlyOwner {
    require(!_renounced.Taxable);

    _setTaxBeneficiary(slot, account, percent, penalty);
  }

  function _setTaxBeneficiary(uint8 slot, address account, uint24[3] memory percent, uint24[3] memory penalty) internal {
    require(slot < 5);
    require(account != address(this) && account != address(0));

    taxBeneficiary storage _taxBeneficiary = _taxBeneficiary[slot];

    if (account == address(0xdEaD) && _taxBeneficiary.exists && _taxBeneficiary.unclaimed > 0) { revert("Unclaimed taxes"); }

    _taxBeneficiary.account = account;
    _taxBeneficiary.percent = percent;
    _taxBeneficiary.penalty = penalty;

    unchecked {
      _totalTxTax += percent[0] - (_taxBeneficiary.exists ? _taxBeneficiary.percent[0] : 0);
      _totalBuyTax += percent[1] - (_taxBeneficiary.exists ? _taxBeneficiary.percent[1] : 0);
      _totalSellTax += percent[2] - (_taxBeneficiary.exists ? _taxBeneficiary.percent[2] : 0);
      _totalPenaltyTxTax += penalty[0] - (_taxBeneficiary.exists ? _taxBeneficiary.penalty[0] : 0);
      _totalPenaltyBuyTax += penalty[1] - (_taxBeneficiary.exists ? _taxBeneficiary.penalty[1] : 0);
      _totalPenaltySellTax += penalty[2] - (_taxBeneficiary.exists ? _taxBeneficiary.penalty[2] : 0);

      require(_totalTxTax <= 25 * _denominator && _totalBuyTax <= 25 * _denominator && _totalSellTax <= 25 * _denominator, "High Tax");
      require(_totalPenaltyTxTax <= 50 * _denominator && _totalPenaltyBuyTax <= 50 * _denominator && _totalPenaltySellTax <= 50 * _denominator, "High Penalty");
    }

    if (!_taxBeneficiary.exists) { _taxBeneficiary.exists = true; }

    emit SetTaxBeneficiary(slot, account, percent, penalty);
  }

  /// @notice Triggers the tax distribution
  /// @dev Will only be executed if there is no ongoing swap or tax distribution and the min. threshold has been reached unless forced
  /// @param force Ignore the min. threshold amount
  function autoTaxDistribute(bool force) external onlyOwner {
    require(!_swapping && !_distributing);

    _autoTaxDistribute(force);
  }

  function _autoTaxDistribute(bool force) internal lockDistributing {
    if (!force) {
      if (address(_reflectionToken) == address(this) && (_amountForTaxDistribution == 0 || _balance[address(this)] < _amountForTaxDistribution || _amountForTaxDistribution < _minTaxDistributionAmount)) { return; }
      if (address(_reflectionToken) == _dex.WETH && (_ethForTaxDistribution == 0 || _ethForTaxDistribution < address(this).balance)) { return; }
      if (address(_reflectionToken) != address(this) && address(_reflectionToken) != _dex.WETH && (_reflectionTokensForTaxDistribution == 0 || _reflectionTokensForTaxDistribution < _reflectionToken.balanceOf(address(this)))) { return; }
    }

    unchecked {
      uint256 distributed;

      for (uint8 i; i < 5; i++) {
        address account = _taxBeneficiary[i].account;
        uint256 unclaimed = _taxBeneficiary[i].unclaimed;

        if (unclaimed == 0 || account == address(0xdEaD) || account == _dex.pair) { continue; }

        uint256 _distributed = _distribute(account, unclaimed);

        if (_distributed > 0) { _taxBeneficiary[i].unclaimed -= _distributed; }

        distributed += _distributed;
      }

      _lastTaxDistribution = _timestamp();

      emit TaxDistributed(distributed);
    }
  }

  function _distribute(address account, uint256 unclaimed) private returns (uint256) {
    if (address(_reflectionToken) == address(this)) {
      super._transfer(address(this), account, unclaimed);

      _amountForTaxDistribution -= unclaimed;
    } else {
      uint256 percent = (uint256(_denominator) * unclaimed * 100) / _amountSwappedForTaxDistribution;
      uint256 amount;

      if (address(_reflectionToken) == _dex.WETH) {
        amount = _percentage(_ethForTaxDistribution, percent);

        if (_ethForTaxDistribution < amount) { return 0; }

        (bool success, ) = payable(account).call{ value: amount, gas: 30000 }("");

        if (!success) { return 0; }

        _ethForTaxDistribution -= amount;
      } else {
        amount = _percentage(_reflectionTokensForTaxDistribution, percent);

        if (_reflectionTokensForTaxDistribution < unclaimed) { return 0; }

        _reflectionToken.transfer(account, amount);
        _reflectionTokensForTaxDistribution -= amount;
      }

      _amountSwappedForTaxDistribution -= unclaimed;
    }

    return unclaimed;
  }

  /// @notice Suspend or reinstate tax collection
  /// @dev Also applies to early penalties
  /// @param status True to suspend, False to reinstate existent taxes
  function suspendTaxes(bool status) external onlyOwner {
    require(!_renounced.Taxable);

    _suspendTaxes = status;
  }

  /// @notice Checks if tax collection is currently suspended
  function taxesSuspended() external view returns (bool) {
    return _suspendTaxes;
  }

  /// @notice Returns the minimum percentage of the total supply accumulated in the Smart-Contract balance to trigger tax distribution
  function getMinTaxDistributionPercent() external view returns (uint24) {
    return _minTaxDistributionPercent;
  }

  /// @notice Sets the minimum percentage of the total supply accumulated in the Smart-Contract balance to trigger tax distribution
  /// @param percent Desired percentage, multiplied by denominator
  function setMinTaxDistributionPercent(uint24 percent) external onlyOwner {
    require(!_renounced.Taxable);
    require(percent >= 1 && percent <= 1000, "0.001% to 1%");

    _setMinTaxDistributionPercent(percent);
  }

  function _setMinTaxDistributionPercent(uint24 percent) internal {
    _minTaxDistributionPercent = percent;
    _minTaxDistributionAmount = _percentage(_totalSupply, uint256(percent));
  }

  /// @notice Removes the penalty status of a wallet
  /// @param account Address to depenalize
  function removePenalty(address account) external onlyOwner {
    require(!_renounced.Taxable);

    _holder[account].penalty = false;
  }

  /// @notice Check if a wallet is penalized due to an early transaction
  /// @param account Address to check
  function isPenalized(address account) external view returns (bool) {
    return _holder[account].penalty;
  }

  /// @notice Defines the period of time from contract creation during which early buyers will be penalized
  /// @param time Time, in seconds
  function setEarlyPenaltyTime(uint32 time) external onlyOwner {
    require(!_renounced.Taxable);
    require(time <= 7 days);

    _setEarlyPenaltyTime(time);
  }

  function _setEarlyPenaltyTime(uint32 time) internal {
    _earlyPenaltyTime = time;

    emit SetEarlyPenaltyTime(time);
  }
}

// File: CF_DEXRouterV2.sol



// SPDX-License-Identifier: MIT

pragma solidity 0.8.23;

import "./CF_Ownable.sol";
import "./CF_Common.sol";
import "./CF_ERC20.sol";

abstract contract CF_DEXRouterV2 is CF_Ownable, CF_Common, CF_ERC20 {
  event SwapAndLiquify(uint256 tokenAmount, uint256 ethAmount, uint256 liquidity);
  event SwappedTokensForETH(uint256 tokenAmount, uint256 ethAmount);
  event SwappedTokensForERC20(address token, uint256 token0Amount, uint256 token1Amount);
  event SetDEXRouter(address indexed router, address indexed pair, address receiver);
  event RenouncedDEXRouterV2();

  modifier lockSwapping {
    _swapping = true;
    _;
    _swapping = false;
  }

  /// @notice Permanently renounce and prevent the owner from being able to update the DEX features
  /// @dev Existing settings will continue to be effective
  function renounceDEXRouterV2() external onlyOwner {
    _renounced.DEXRouterV2 = true;

    emit RenouncedDEXRouterV2();
  }

  /// @notice Sets the DEX router and where to receive the LP tokens
  /// @param router Address of the DEX router
  /// @param receiver Address of the LP tokens receiver
  function setDEXRouter(address router, address receiver) external onlyOwner returns (address) {
    require(!_renounced.DEXRouterV2);

    return _setDEXRouter(router, receiver);
  }

  function _setDEXRouter(address router, address receiver) internal returns (address) {
    require(router != address(0));

    if (_dex.router != router) {
      IDEXRouterV2 _router = IDEXRouterV2(router);
      IDEXFactoryV2 factory = IDEXFactoryV2(_router.factory());
      address WETH = _router.WETH();
      address pair = factory.getPair(address(this), WETH);

      if (pair == address(0)) { pair = factory.createPair(address(this), WETH); }

      _dex = DEXRouterV2(router, pair, WETH, receiver);
    }

    if (receiver != _dex.receiver) { _dex.receiver = receiver; }

    emit SetDEXRouter(router, _dex.pair, receiver);

    return _dex.pair;
  }

  /// @notice Returns the DEX router currently in use
  function getDEXRouter() external view returns (address) {
    return _dex.router;
  }

  /// @notice Returns the trading pair
  function getDEXPair() external view returns (address) {
    return _dex.pair;
  }

  /// @notice Returns address of the LP tokens receiver
  function getDEXReceiver() external view returns (address) {
    return _dex.receiver;
  }

  /// @notice Returns address of the reflection token
  function getReflectionToken() external view returns (address) {
    return address(_reflectionToken);
  }

  /// @notice Checks the status of the auto-swapping feature
  function isSwapEnabled() external view returns (bool) {
    return _swapEnabled;
  }

  /// @notice Checks whether the token can be traded through the assigned DEX
  function isTradingEnabled() external view returns (bool) {
    return _tradingEnabled > 0;
  }

  /// @notice Assign the excess token balance of the Smart-Contract to liquidity
  function liquifyExcess() external onlyOwner {
    require(_swapEnabled && !_swapping);

    unchecked {
      uint256 assigned = _amountForTaxDistribution + _amountForLiquidity;

      require(_balance[address(this)] > assigned);

      uint256 excess = _balance[address(this)] - assigned;

      _amountForLiquidity += excess;
    }

    _autoSwap(false);
  }

  /// @notice Swaps the assigned amount for liquidity and taxes to the corresponding token
  /// @dev Will only be executed if there is no ongoing swap or tax distribution and the min. threshold has been reached unless forced
  /// @param force Ignore the min. threshold amount
  function autoSwap(bool force) external onlyOwner {
    require(_swapEnabled && !_swapping && !_distributing);

    _autoSwap(force);
  }

  function _autoSwap(bool force) internal lockSwapping {
    if (!_swapEnabled) { return; }

    unchecked {
      if (force || ((address(_reflectionToken) == _dex.WETH ? _amountForTaxDistribution : 0) + _amountForLiquidity / 2 >= _minSwapAmount && _balance[address(this)] >= (address(_reflectionToken) == _dex.WETH ? _amountForTaxDistribution : 0) + _amountForLiquidity)) {
        uint256 tokenAmountForLiquidity = _amountForLiquidity / 2;
        uint256 ethBalance = address(this).balance;
        address[] memory pathToSwapExactTokensForETH = new address[](2);
        pathToSwapExactTokensForETH[0] = address(this);
        pathToSwapExactTokensForETH[1] = _dex.WETH;

        _approve(address(this), _dex.router, (address(_reflectionToken) == _dex.WETH ? _amountForTaxDistribution : 0) + tokenAmountForLiquidity);

        try IDEXRouterV2(_dex.router).swapExactTokensForETHSupportingFeeOnTransferTokens((address(_reflectionToken) == _dex.WETH ? _amountForTaxDistribution : 0) + tokenAmountForLiquidity, 0, pathToSwapExactTokensForETH, address(this), block.timestamp + 1) {
          _lastSwap = _timestamp();

          if (_amountForLiquidity > 0) { _amountForLiquidity /= 2; }

          uint256 ethAmount = address(this).balance - ethBalance;

          emit SwappedTokensForETH((address(_reflectionToken) == _dex.WETH ? _amountForTaxDistribution : 0) + tokenAmountForLiquidity, ethAmount);

          if (ethAmount > 0) {
            uint256 ethForLiquidity = ethAmount;

            if (address(_reflectionToken) == _dex.WETH) {
              ethForLiquidity = _percentage(ethAmount, tokenAmountForLiquidity >= _amountForTaxDistribution ? (100 * uint256(_denominator)) - ((uint256(_denominator) * _amountForTaxDistribution * 100) / (tokenAmountForLiquidity + _amountForTaxDistribution)) : (uint256(_denominator) * tokenAmountForLiquidity * 100) / (tokenAmountForLiquidity + _amountForTaxDistribution));

              _amountSwappedForTaxDistribution += _amountForTaxDistribution;
              _amountForTaxDistribution = 0;
              _ethForTaxDistribution += ethAmount - ethForLiquidity;
            }

            if (tokenAmountForLiquidity > 0 && ethForLiquidity > 0) {
              _approve(address(this), _dex.router, tokenAmountForLiquidity);

              try IDEXRouterV2(_dex.router).addLiquidityETH{ value: ethForLiquidity }(address(this), tokenAmountForLiquidity, 0, 0, _dex.receiver, block.timestamp + 1) returns (uint256 amountToken, uint256 amountETH, uint256 liquidity) {
                emit SwapAndLiquify(amountToken, amountETH, liquidity);

                _amountForLiquidity = 0;
              } catch {
                _approve(address(this), _dex.router, 0);
              }
            }
          }
        } catch {
          _approve(address(this), _dex.router, 0);
        }
      }

      if (force || (address(_reflectionToken) != address(this) && address(_reflectionToken) != _dex.WETH && _amountForTaxDistribution >= _minSwapAmount && _balance[address(this)] >= _amountForTaxDistribution)) {
        uint256 reflectionTokenBalance = _reflectionToken.balanceOf(address(this));
        address[] memory pathToSwapExactTokensForERC20 = new address[](3);
        pathToSwapExactTokensForERC20[0] = address(this);
        pathToSwapExactTokensForERC20[1] = _dex.WETH;
        pathToSwapExactTokensForERC20[2] = address(_reflectionToken);

        _reflectionToken.approve(_dex.router, _amountForTaxDistribution);

        try IDEXRouterV2(_dex.router).swapExactTokensForTokensSupportingFeeOnTransferTokens(_amountForTaxDistribution, 0, (pathToSwapExactTokensForERC20), address(this), block.timestamp + 1) {
          emit SwappedTokensForERC20(address(_reflectionToken), _amountForTaxDistribution, reflectionTokenBalance - _reflectionToken.balanceOf(address(this)));

          _amountSwappedForTaxDistribution += _amountForTaxDistribution;
          _amountForTaxDistribution = 0;
          _reflectionTokensForTaxDistribution += reflectionTokenBalance - _reflectionToken.balanceOf(address(this));
        } catch {
          _reflectionToken.approve(_dex.router, 0);
        }
      }
    }
  }

  /// @notice Sets the desired ERC-20 reflection token
  /// @dev If other token than WETH is specified, the pair WETH-token must already exist
  /// @param token Address of the ERC-20 token
  function setReflection(address token) external onlyOwner {
    require(!_renounced.DEXRouterV2);

    _setReflection(token);
  }

  function _setReflection(address token) internal {
    require(token == address(0) || token == address(this) || token == _dex.WETH || IDEXFactoryV2(IDEXRouterV2(_dex.router).factory()).getPair(_dex.WETH, token) != address(0), "No Pair");

    if (token == address(0)) { token == address(this); }

    _reflectionToken = IERC20(token);
  }

  /// @notice Returns the minimum percentage of the total supply in the Smart-Contract balance to trigger auto swap
  function getMinSwapPercent() external view returns (uint24) {
    return _minSwapPercent;
  }

  /// @notice Sets the minimum percentage of the total supply in the Smart-Contract balance to trigger auto swap
  /// @param percent Desired percentage, multiplied by denominator
  function setMinSwapPercent(uint24 percent) external onlyOwner {
    require(!_renounced.DEXRouterV2);
    require(percent >= 1 && percent <= 1000, "0.001% to 1%");

    _setMinSwapPercent(percent);
  }

  function _setMinSwapPercent(uint24 percent) internal {
    _minSwapPercent = percent;
    _minSwapAmount = _percentage(_totalSupply, uint256(percent));
  }

  /// @notice Enables or disables the auto swap function
  /// @param status True to enable, False to disable
  function setSwapStatus(bool status) external onlyOwner {
    require(!_renounced.DEXRouterV2);
    require(!status || _dex.router != address(0), "No DEX");

    _swapEnabled = status;
  }

  /// @notice Enables or disables the trading capability via the DEX set up
  /// @param status True to enable, False to disable
  function setTradingStatus(bool status) external onlyOwner {
    require(!_renounced.DEXRouterV2);

    _tradingEnabled = status ? _timestamp() : 0;
  }
}

// File: IDEXV2.sol



// SPDX-License-Identifier: MIT

pragma solidity 0.8.23;

interface IDEXRouterV2 {
  function factory() external pure returns (address);
  function WETH() external pure returns (address);
  function addLiquidityETH(address token, uint256 amountTokenDesired, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline) external payable returns (uint256 amountToken, uint256 amountETH, uint256 liquidity);
  function swapExactTokensForETHSupportingFeeOnTransferTokens(uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline) external;
  function swapExactTokensForTokensSupportingFeeOnTransferTokens(uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline) external;
}

interface IDEXFactoryV2 {
  function createPair(address tokenA, address tokenB) external returns (address pair);
  function getPair(address tokenA, address tokenB) external returns (address pair);
}

// File: IERC20.sol



// SPDX-License-Identifier: MIT

pragma solidity 0.8.23;

interface IERC20 {
  function balanceOf(address account) external view returns (uint256);
  function transfer(address to, uint256 amount) external returns (bool);
  function approve(address spender, uint256 amount) external returns (bool);
}