ETH Price: $2,241.90 (-1.13%)

Transaction Decoder

Block:
19705428 at Apr-21-2024 05:59:35 PM +UTC
Transaction Fee:
0.001733555869225521 ETH $3.89
Gas Used:
202,773 Gas / 8.549244077 Gwei

Emitted Events:

269 GalaxyFox.Approval( owner=[Sender] 0xcf1983cd217726bef503f02fc1f643062e7dbcce, spender=[Receiver] ERC1967Proxy, value=0 )
270 GalaxyFox.Transfer( from=[Sender] 0xcf1983cd217726bef503f02fc1f643062e7dbcce, to=[Receiver] ERC1967Proxy, value=59687500000000000000000 )
271 ERC1967Proxy.0x1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90( 0x1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90, 0x000000000000000000000000cf1983cd217726bef503f02fc1f643062e7dbcce, 0000000000000000000000000000000000000000000000000000000000000000, 000000000000000000000000000000000000000000000ca3aa75b41257ee0000 )

Account State Difference:

  Address   Before After State Difference Code
(Titan Builder)
6.743151269673064851 Eth6.743151472446064851 Eth0.000000202773
0x80846B54...2c65CB0E4
0x8F1CecE0...25F4F2662
0xcF1983cD...62E7dbcce
0.126522903442216694 Eth
Nonce: 8
0.124789347572991173 Eth
Nonce: 9
0.001733555869225521

Execution Trace

ERC1967Proxy.7b0472f0( )
  • 0xed46fd7ee84b13391ff9d6260012068de8fdf5e2.7b0472f0( )
    • GalaxyFox.transferFrom( sender=0xcF1983cD217726BEf503F02Fc1f643062E7dbcce, recipient=0x80846B546BaecE682496cAAF8B8AbA62c65CB0E4, amount=59687500000000000000000 ) => ( True )
      File 1 of 2: ERC1967Proxy
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
      pragma solidity ^0.8.20;
      import {Context} from "../utils/Context.sol";
      /**
       * @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);
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol)
      pragma solidity ^0.8.20;
      /**
       * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
       */
      interface IERC1967 {
          /**
           * @dev Emitted when the implementation is upgraded.
           */
          event Upgraded(address indexed implementation);
          /**
           * @dev Emitted when the admin account has changed.
           */
          event AdminChanged(address previousAdmin, address newAdmin);
          /**
           * @dev Emitted when the beacon is changed.
           */
          event BeaconUpgraded(address indexed beacon);
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/BeaconProxy.sol)
      pragma solidity ^0.8.20;
      import {IBeacon} from "./IBeacon.sol";
      import {Proxy} from "../Proxy.sol";
      import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol";
      /**
       * @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}.
       *
       * The beacon address can only be set once during construction, and cannot be changed afterwards. It is stored in an
       * immutable variable to avoid unnecessary storage reads, and also in the beacon storage slot specified by
       * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] so that it can be accessed externally.
       *
       * CAUTION: Since the beacon address can never be changed, you must ensure that you either control the beacon, or trust
       * the beacon to not upgrade the implementation maliciously.
       *
       * IMPORTANT: Do not use the implementation logic to modify the beacon storage slot. Doing so would leave the proxy in
       * an inconsistent state where the beacon storage slot does not match the beacon address.
       */
      contract BeaconProxy is Proxy {
          // An immutable address for the beacon to avoid unnecessary SLOADs before each delegate call.
          address private immutable _beacon;
          /**
           * @dev Initializes the proxy with `beacon`.
           *
           * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This
           * will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity
           * constructor.
           *
           * Requirements:
           *
           * - `beacon` must be a contract with the interface {IBeacon}.
           * - If `data` is empty, `msg.value` must be zero.
           */
          constructor(address beacon, bytes memory data) payable {
              ERC1967Utils.upgradeBeaconToAndCall(beacon, data);
              _beacon = beacon;
          }
          /**
           * @dev Returns the current implementation address of the associated beacon.
           */
          function _implementation() internal view virtual override returns (address) {
              return IBeacon(_getBeacon()).implementation();
          }
          /**
           * @dev Returns the beacon.
           */
          function _getBeacon() internal view virtual returns (address) {
              return _beacon;
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
      pragma solidity ^0.8.20;
      /**
       * @dev This is the interface that {BeaconProxy} expects of its beacon.
       */
      interface IBeacon {
          /**
           * @dev Must return an address that can be used as a delegate call target.
           *
           * {UpgradeableBeacon} will check that this address is a contract.
           */
          function implementation() external view returns (address);
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/UpgradeableBeacon.sol)
      pragma solidity ^0.8.20;
      import {IBeacon} from "./IBeacon.sol";
      import {Ownable} from "../../access/Ownable.sol";
      /**
       * @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their
       * implementation contract, which is where they will delegate all function calls.
       *
       * An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon.
       */
      contract UpgradeableBeacon is IBeacon, Ownable {
          address private _implementation;
          /**
           * @dev The `implementation` of the beacon is invalid.
           */
          error BeaconInvalidImplementation(address implementation);
          /**
           * @dev Emitted when the implementation returned by the beacon is changed.
           */
          event Upgraded(address indexed implementation);
          /**
           * @dev Sets the address of the initial implementation, and the initial owner who can upgrade the beacon.
           */
          constructor(address implementation_, address initialOwner) Ownable(initialOwner) {
              _setImplementation(implementation_);
          }
          /**
           * @dev Returns the current implementation address.
           */
          function implementation() public view virtual returns (address) {
              return _implementation;
          }
          /**
           * @dev Upgrades the beacon to a new implementation.
           *
           * Emits an {Upgraded} event.
           *
           * Requirements:
           *
           * - msg.sender must be the owner of the contract.
           * - `newImplementation` must be a contract.
           */
          function upgradeTo(address newImplementation) public virtual onlyOwner {
              _setImplementation(newImplementation);
          }
          /**
           * @dev Sets the implementation contract address for this beacon
           *
           * Requirements:
           *
           * - `newImplementation` must be a contract.
           */
          function _setImplementation(address newImplementation) private {
              if (newImplementation.code.length == 0) {
                  revert BeaconInvalidImplementation(newImplementation);
              }
              _implementation = newImplementation;
              emit Upgraded(newImplementation);
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Proxy.sol)
      pragma solidity ^0.8.20;
      import {Proxy} from "../Proxy.sol";
      import {ERC1967Utils} from "./ERC1967Utils.sol";
      /**
       * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
       * implementation address that can be changed. This address is stored in storage in the location specified by
       * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
       * implementation behind the proxy.
       */
      contract ERC1967Proxy is Proxy {
          /**
           * @dev Initializes the upgradeable proxy with an initial implementation specified by `implementation`.
           *
           * If `_data` is nonempty, it's used as data in a delegate call to `implementation`. This will typically be an
           * encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.
           *
           * Requirements:
           *
           * - If `data` is empty, `msg.value` must be zero.
           */
          constructor(address implementation, bytes memory _data) payable {
              ERC1967Utils.upgradeToAndCall(implementation, _data);
          }
          /**
           * @dev Returns the current implementation address.
           *
           * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
           * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
           * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
           */
          function _implementation() internal view virtual override returns (address) {
              return ERC1967Utils.getImplementation();
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)
      pragma solidity ^0.8.20;
      import {IBeacon} from "../beacon/IBeacon.sol";
      import {Address} from "../../utils/Address.sol";
      import {StorageSlot} from "../../utils/StorageSlot.sol";
      /**
       * @dev This abstract contract provides getters and event emitting update functions for
       * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
       */
      library ERC1967Utils {
          // We re-declare ERC-1967 events here because they can't be used directly from IERC1967.
          // This will be fixed in Solidity 0.8.21. At that point we should remove these events.
          /**
           * @dev Emitted when the implementation is upgraded.
           */
          event Upgraded(address indexed implementation);
          /**
           * @dev Emitted when the admin account has changed.
           */
          event AdminChanged(address previousAdmin, address newAdmin);
          /**
           * @dev Emitted when the beacon is changed.
           */
          event BeaconUpgraded(address indexed beacon);
          /**
           * @dev Storage slot with the address of the current implementation.
           * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
           */
          // solhint-disable-next-line private-vars-leading-underscore
          bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
          /**
           * @dev The `implementation` of the proxy is invalid.
           */
          error ERC1967InvalidImplementation(address implementation);
          /**
           * @dev The `admin` of the proxy is invalid.
           */
          error ERC1967InvalidAdmin(address admin);
          /**
           * @dev The `beacon` of the proxy is invalid.
           */
          error ERC1967InvalidBeacon(address beacon);
          /**
           * @dev An upgrade function sees `msg.value > 0` that may be lost.
           */
          error ERC1967NonPayable();
          /**
           * @dev Returns the current implementation address.
           */
          function getImplementation() internal view returns (address) {
              return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
          }
          /**
           * @dev Stores a new address in the EIP1967 implementation slot.
           */
          function _setImplementation(address newImplementation) private {
              if (newImplementation.code.length == 0) {
                  revert ERC1967InvalidImplementation(newImplementation);
              }
              StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
          }
          /**
           * @dev Performs implementation upgrade with additional setup call if data is nonempty.
           * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
           * to avoid stuck value in the contract.
           *
           * Emits an {IERC1967-Upgraded} event.
           */
          function upgradeToAndCall(address newImplementation, bytes memory data) internal {
              _setImplementation(newImplementation);
              emit Upgraded(newImplementation);
              if (data.length > 0) {
                  Address.functionDelegateCall(newImplementation, data);
              } else {
                  _checkNonPayable();
              }
          }
          /**
           * @dev Storage slot with the admin of the contract.
           * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
           */
          // solhint-disable-next-line private-vars-leading-underscore
          bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
          /**
           * @dev Returns the current admin.
           *
           * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
           * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
           * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
           */
          function getAdmin() internal view returns (address) {
              return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
          }
          /**
           * @dev Stores a new address in the EIP1967 admin slot.
           */
          function _setAdmin(address newAdmin) private {
              if (newAdmin == address(0)) {
                  revert ERC1967InvalidAdmin(address(0));
              }
              StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
          }
          /**
           * @dev Changes the admin of the proxy.
           *
           * Emits an {IERC1967-AdminChanged} event.
           */
          function changeAdmin(address newAdmin) internal {
              emit AdminChanged(getAdmin(), newAdmin);
              _setAdmin(newAdmin);
          }
          /**
           * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
           * This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
           */
          // solhint-disable-next-line private-vars-leading-underscore
          bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
          /**
           * @dev Returns the current beacon.
           */
          function getBeacon() internal view returns (address) {
              return StorageSlot.getAddressSlot(BEACON_SLOT).value;
          }
          /**
           * @dev Stores a new beacon in the EIP1967 beacon slot.
           */
          function _setBeacon(address newBeacon) private {
              if (newBeacon.code.length == 0) {
                  revert ERC1967InvalidBeacon(newBeacon);
              }
              StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
              address beaconImplementation = IBeacon(newBeacon).implementation();
              if (beaconImplementation.code.length == 0) {
                  revert ERC1967InvalidImplementation(beaconImplementation);
              }
          }
          /**
           * @dev Change the beacon and trigger a setup call if data is nonempty.
           * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
           * to avoid stuck value in the contract.
           *
           * Emits an {IERC1967-BeaconUpgraded} event.
           *
           * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
           * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
           * efficiency.
           */
          function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
              _setBeacon(newBeacon);
              emit BeaconUpgraded(newBeacon);
              if (data.length > 0) {
                  Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
              } else {
                  _checkNonPayable();
              }
          }
          /**
           * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
           * if an upgrade doesn't perform an initialization call.
           */
          function _checkNonPayable() private {
              if (msg.value > 0) {
                  revert ERC1967NonPayable();
              }
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (proxy/Proxy.sol)
      pragma solidity ^0.8.20;
      /**
       * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
       * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
       * be specified by overriding the virtual {_implementation} function.
       *
       * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
       * different contract through the {_delegate} function.
       *
       * The success and return data of the delegated call will be returned back to the caller of the proxy.
       */
      abstract contract Proxy {
          /**
           * @dev Delegates the current call to `implementation`.
           *
           * This function does not return to its internal call site, it will return directly to the external caller.
           */
          function _delegate(address implementation) internal virtual {
              assembly {
                  // Copy msg.data. We take full control of memory in this inline assembly
                  // block because it will not return to Solidity code. We overwrite the
                  // Solidity scratch pad at memory position 0.
                  calldatacopy(0, 0, calldatasize())
                  // Call the implementation.
                  // out and outsize are 0 because we don't know the size yet.
                  let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                  // Copy the returned data.
                  returndatacopy(0, 0, returndatasize())
                  switch result
                  // delegatecall returns 0 on error.
                  case 0 {
                      revert(0, returndatasize())
                  }
                  default {
                      return(0, returndatasize())
                  }
              }
          }
          /**
           * @dev This is a virtual function that should be overridden so it returns the address to which the fallback
           * function and {_fallback} should delegate.
           */
          function _implementation() internal view virtual returns (address);
          /**
           * @dev Delegates the current call to the address returned by `_implementation()`.
           *
           * This function does not return to its internal call site, it will return directly to the external caller.
           */
          function _fallback() internal virtual {
              _delegate(_implementation());
          }
          /**
           * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
           * function in the contract matches the call data.
           */
          fallback() external payable virtual {
              _fallback();
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (proxy/transparent/ProxyAdmin.sol)
      pragma solidity ^0.8.20;
      import {ITransparentUpgradeableProxy} from "./TransparentUpgradeableProxy.sol";
      import {Ownable} from "../../access/Ownable.sol";
      /**
       * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an
       * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.
       */
      contract ProxyAdmin is Ownable {
          /**
           * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgrade(address)`
           * and `upgradeAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
           * while `upgradeAndCall` will invoke the `receive` function if the second argument is the empty byte string.
           * If the getter returns `"5.0.0"`, only `upgradeAndCall(address,bytes)` is present, and the second argument must
           * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
           * during an upgrade.
           */
          string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
          /**
           * @dev Sets the initial owner who can perform upgrades.
           */
          constructor(address initialOwner) Ownable(initialOwner) {}
          /**
           * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation.
           * See {TransparentUpgradeableProxy-_dispatchUpgradeToAndCall}.
           *
           * Requirements:
           *
           * - This contract must be the admin of `proxy`.
           * - If `data` is empty, `msg.value` must be zero.
           */
          function upgradeAndCall(
              ITransparentUpgradeableProxy proxy,
              address implementation,
              bytes memory data
          ) public payable virtual onlyOwner {
              proxy.upgradeToAndCall{value: msg.value}(implementation, data);
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (proxy/transparent/TransparentUpgradeableProxy.sol)
      pragma solidity ^0.8.20;
      import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol";
      import {ERC1967Proxy} from "../ERC1967/ERC1967Proxy.sol";
      import {IERC1967} from "../../interfaces/IERC1967.sol";
      import {ProxyAdmin} from "./ProxyAdmin.sol";
      /**
       * @dev Interface for {TransparentUpgradeableProxy}. In order to implement transparency, {TransparentUpgradeableProxy}
       * does not implement this interface directly, and its upgradeability mechanism is implemented by an internal dispatch
       * mechanism. The compiler is unaware that these functions are implemented by {TransparentUpgradeableProxy} and will not
       * include them in the ABI so this interface must be used to interact with it.
       */
      interface ITransparentUpgradeableProxy is IERC1967 {
          function upgradeToAndCall(address, bytes calldata) external payable;
      }
      /**
       * @dev This contract implements a proxy that is upgradeable through an associated {ProxyAdmin} instance.
       *
       * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
       * clashing], which can potentially be used in an attack, this contract uses the
       * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
       * things that go hand in hand:
       *
       * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
       * that call matches the {ITransparentUpgradeableProxy-upgradeToAndCall} function exposed by the proxy itself.
       * 2. If the admin calls the proxy, it can call the `upgradeToAndCall` function but any other call won't be forwarded to
       * the implementation. If the admin tries to call a function on the implementation it will fail with an error indicating
       * the proxy admin cannot fallback to the target implementation.
       *
       * These properties mean that the admin account can only be used for upgrading the proxy, so it's best if it's a
       * dedicated account that is not used for anything else. This will avoid headaches due to sudden errors when trying to
       * call a function from the proxy implementation. For this reason, the proxy deploys an instance of {ProxyAdmin} and
       * allows upgrades only if they come through it. You should think of the `ProxyAdmin` instance as the administrative
       * interface of the proxy, including the ability to change who can trigger upgrades by transferring ownership.
       *
       * NOTE: The real interface of this proxy is that defined in `ITransparentUpgradeableProxy`. This contract does not
       * inherit from that interface, and instead `upgradeToAndCall` is implicitly implemented using a custom dispatch
       * mechanism in `_fallback`. Consequently, the compiler will not produce an ABI for this contract. This is necessary to
       * fully implement transparency without decoding reverts caused by selector clashes between the proxy and the
       * implementation.
       *
       * NOTE: This proxy does not inherit from {Context} deliberately. The {ProxyAdmin} of this contract won't send a
       * meta-transaction in any way, and any other meta-transaction setup should be made in the implementation contract.
       *
       * IMPORTANT: This contract avoids unnecessary storage reads by setting the admin only during construction as an
       * immutable variable, preventing any changes thereafter. However, the admin slot defined in ERC-1967 can still be
       * overwritten by the implementation logic pointed to by this proxy. In such cases, the contract may end up in an
       * undesirable state where the admin slot is different from the actual admin.
       *
       * WARNING: It is not recommended to extend this contract to add additional external functions. If you do so, the
       * compiler will not check that there are no selector conflicts, due to the note above. A selector clash between any new
       * function and the functions declared in {ITransparentUpgradeableProxy} will be resolved in favor of the new one. This
       * could render the `upgradeToAndCall` function inaccessible, preventing upgradeability and compromising transparency.
       */
      contract TransparentUpgradeableProxy is ERC1967Proxy {
          // An immutable address for the admin to avoid unnecessary SLOADs before each call
          // at the expense of removing the ability to change the admin once it's set.
          // This is acceptable if the admin is always a ProxyAdmin instance or similar contract
          // with its own ability to transfer the permissions to another account.
          address private immutable _admin;
          /**
           * @dev The proxy caller is the current admin, and can't fallback to the proxy target.
           */
          error ProxyDeniedAdminAccess();
          /**
           * @dev Initializes an upgradeable proxy managed by an instance of a {ProxyAdmin} with an `initialOwner`,
           * backed by the implementation at `_logic`, and optionally initialized with `_data` as explained in
           * {ERC1967Proxy-constructor}.
           */
          constructor(address _logic, address initialOwner, bytes memory _data) payable ERC1967Proxy(_logic, _data) {
              _admin = address(new ProxyAdmin(initialOwner));
              // Set the storage value and emit an event for ERC-1967 compatibility
              ERC1967Utils.changeAdmin(_proxyAdmin());
          }
          /**
           * @dev Returns the admin of this proxy.
           */
          function _proxyAdmin() internal virtual returns (address) {
              return _admin;
          }
          /**
           * @dev If caller is the admin process the call internally, otherwise transparently fallback to the proxy behavior.
           */
          function _fallback() internal virtual override {
              if (msg.sender == _proxyAdmin()) {
                  if (msg.sig != ITransparentUpgradeableProxy.upgradeToAndCall.selector) {
                      revert ProxyDeniedAdminAccess();
                  } else {
                      _dispatchUpgradeToAndCall();
                  }
              } else {
                  super._fallback();
              }
          }
          /**
           * @dev Upgrade the implementation of the proxy. See {ERC1967Utils-upgradeToAndCall}.
           *
           * Requirements:
           *
           * - If `data` is empty, `msg.value` must be zero.
           */
          function _dispatchUpgradeToAndCall() private {
              (address newImplementation, bytes memory data) = abi.decode(msg.data[4:], (address, bytes));
              ERC1967Utils.upgradeToAndCall(newImplementation, data);
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
      pragma solidity ^0.8.20;
      /**
       * @dev Collection of functions related to the address type
       */
      library Address {
          /**
           * @dev The ETH balance of the account is not enough to perform the operation.
           */
          error AddressInsufficientBalance(address account);
          /**
           * @dev There's no code at `target` (it is not a contract).
           */
          error AddressEmptyCode(address target);
          /**
           * @dev A call to an address target failed. The target may have reverted.
           */
          error FailedInnerCall();
          /**
           * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
           * `recipient`, forwarding all available gas and reverting on errors.
           *
           * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
           * of certain opcodes, possibly making contracts go over the 2300 gas limit
           * imposed by `transfer`, making them unable to receive funds via
           * `transfer`. {sendValue} removes this limitation.
           *
           * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
           *
           * IMPORTANT: because control is transferred to `recipient`, care must be
           * taken to not create reentrancy vulnerabilities. Consider using
           * {ReentrancyGuard} or the
           * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
           */
          function sendValue(address payable recipient, uint256 amount) internal {
              if (address(this).balance < amount) {
                  revert AddressInsufficientBalance(address(this));
              }
              (bool success, ) = recipient.call{value: amount}("");
              if (!success) {
                  revert FailedInnerCall();
              }
          }
          /**
           * @dev Performs a Solidity function call using a low level `call`. A
           * plain `call` is an unsafe replacement for a function call: use this
           * function instead.
           *
           * If `target` reverts with a revert reason or custom error, it is bubbled
           * up by this function (like regular Solidity function calls). However, if
           * the call reverted with no returned reason, this function reverts with a
           * {FailedInnerCall} error.
           *
           * Returns the raw returned data. To convert to the expected return value,
           * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
           *
           * Requirements:
           *
           * - `target` must be a contract.
           * - calling `target` with `data` must not revert.
           */
          function functionCall(address target, bytes memory data) internal returns (bytes memory) {
              return functionCallWithValue(target, data, 0);
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but also transferring `value` wei to `target`.
           *
           * Requirements:
           *
           * - the calling contract must have an ETH balance of at least `value`.
           * - the called Solidity function must be `payable`.
           */
          function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
              if (address(this).balance < value) {
                  revert AddressInsufficientBalance(address(this));
              }
              (bool success, bytes memory returndata) = target.call{value: value}(data);
              return verifyCallResultFromTarget(target, success, returndata);
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but performing a static call.
           */
          function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
              (bool success, bytes memory returndata) = target.staticcall(data);
              return verifyCallResultFromTarget(target, success, returndata);
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but performing a delegate call.
           */
          function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
              (bool success, bytes memory returndata) = target.delegatecall(data);
              return verifyCallResultFromTarget(target, success, returndata);
          }
          /**
           * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
           * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
           * unsuccessful call.
           */
          function verifyCallResultFromTarget(
              address target,
              bool success,
              bytes memory returndata
          ) internal view returns (bytes memory) {
              if (!success) {
                  _revert(returndata);
              } else {
                  // only check if target is a contract if the call was successful and the return data is empty
                  // otherwise we already know that it was a contract
                  if (returndata.length == 0 && target.code.length == 0) {
                      revert AddressEmptyCode(target);
                  }
                  return returndata;
              }
          }
          /**
           * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
           * revert reason or with a default {FailedInnerCall} error.
           */
          function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
              if (!success) {
                  _revert(returndata);
              } else {
                  return returndata;
              }
          }
          /**
           * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
           */
          function _revert(bytes memory returndata) private pure {
              // Look for revert reason and bubble it up if present
              if (returndata.length > 0) {
                  // The easiest way to bubble the revert reason is using memory via assembly
                  /// @solidity memory-safe-assembly
                  assembly {
                      let returndata_size := mload(returndata)
                      revert(add(32, returndata), returndata_size)
                  }
              } else {
                  revert FailedInnerCall();
              }
          }
      }
      // SPDX-License-Identifier: MIT
      // 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;
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
      // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
      pragma solidity ^0.8.20;
      /**
       * @dev Library for reading and writing primitive types to specific storage slots.
       *
       * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
       * This library helps with reading and writing to such slots without the need for inline assembly.
       *
       * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
       *
       * Example usage to set ERC1967 implementation slot:
       * ```solidity
       * contract ERC1967 {
       *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
       *
       *     function _getImplementation() internal view returns (address) {
       *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
       *     }
       *
       *     function _setImplementation(address newImplementation) internal {
       *         require(newImplementation.code.length > 0);
       *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
       *     }
       * }
       * ```
       */
      library StorageSlot {
          struct AddressSlot {
              address value;
          }
          struct BooleanSlot {
              bool value;
          }
          struct Bytes32Slot {
              bytes32 value;
          }
          struct Uint256Slot {
              uint256 value;
          }
          struct StringSlot {
              string value;
          }
          struct BytesSlot {
              bytes value;
          }
          /**
           * @dev Returns an `AddressSlot` with member `value` located at `slot`.
           */
          function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
              /// @solidity memory-safe-assembly
              assembly {
                  r.slot := slot
              }
          }
          /**
           * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
           */
          function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
              /// @solidity memory-safe-assembly
              assembly {
                  r.slot := slot
              }
          }
          /**
           * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
           */
          function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
              /// @solidity memory-safe-assembly
              assembly {
                  r.slot := slot
              }
          }
          /**
           * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
           */
          function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
              /// @solidity memory-safe-assembly
              assembly {
                  r.slot := slot
              }
          }
          /**
           * @dev Returns an `StringSlot` with member `value` located at `slot`.
           */
          function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
              /// @solidity memory-safe-assembly
              assembly {
                  r.slot := slot
              }
          }
          /**
           * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
           */
          function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
              /// @solidity memory-safe-assembly
              assembly {
                  r.slot := store.slot
              }
          }
          /**
           * @dev Returns an `BytesSlot` with member `value` located at `slot`.
           */
          function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
              /// @solidity memory-safe-assembly
              assembly {
                  r.slot := slot
              }
          }
          /**
           * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
           */
          function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
              /// @solidity memory-safe-assembly
              assembly {
                  r.slot := store.slot
              }
          }
      }
      

      File 2 of 2: GalaxyFox
      // SPDX-License-Identifier: MIT
      pragma solidity 0.8.23;
      
      string constant NAME = "Galaxy Fox";
      
      string constant SYMBOL = "GFOX";
      
      uint256 constant INITIAL_SUPPLY = 5000000000 * 10 ** 18;
      
      uint16 constant BUY_TAX_LIQUIDIY = 200;
      
      // 2%
      uint16 constant BUY_TAX_MARKETING = 200;
      
      // 2%
      uint16 constant BUY_TAX_ECOSYSTEM = 200;
      
      // 2%
      uint16 constant SELL_TAX_LIQUIDIY = 200;
      
      // 2%
      uint16 constant SELL_TAX_MARKETING = 200;
      
      // 2%
      uint16 constant SELL_TAX_ECOSYSTEM = 200;
      
      // 2%
      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);
      }
      
      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);
      }
      
      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;
          }
      }
      
      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);
      }
      
      //
      // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)
      /**
       * @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;
      
          /**
           * @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_) {
              _name = name_;
              _symbol = symbol_;
          }
      
          /**
           * @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;
                  }
              }
      
              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);
                  }
              }
          }
      }
      
      interface IERC20Permit {
          /**
           * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
           * given ``owner``'s signed approval.
           *
           * IMPORTANT: The same issues {IERC20-approve} has related to transaction
           * ordering also apply here.
           *
           * Emits an {Approval} event.
           *
           * Requirements:
           *
           * - `spender` cannot be the zero address.
           * - `deadline` must be a timestamp in the future.
           * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
           * over the EIP712-formatted function arguments.
           * - the signature must use ``owner``'s current nonce (see {nonces}).
           *
           * For more information on the signature format, see the
           * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
           * section].
           *
           * CAUTION: See Security Considerations above.
           */
          function permit(
              address owner,
              address spender,
              uint256 value,
              uint256 deadline,
              uint8 v,
              bytes32 r,
              bytes32 s
          ) external;
      
          /**
           * @dev Returns the current nonce for `owner`. This value must be
           * included whenever a signature is generated for {permit}.
           *
           * Every successful call to {permit} increases ``owner``'s nonce by one. This
           * prevents a signature from being used multiple times.
           */
          function nonces(address owner) external view returns (uint256);
      
          /**
           * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
           */
          // solhint-disable-next-line func-name-mixedcase
          function DOMAIN_SEPARATOR() external view returns (bytes32);
      }
      
      library Address {
          /**
           * @dev The ETH balance of the account is not enough to perform the operation.
           */
          error AddressInsufficientBalance(address account);
      
          /**
           * @dev There's no code at `target` (it is not a contract).
           */
          error AddressEmptyCode(address target);
      
          /**
           * @dev A call to an address target failed. The target may have reverted.
           */
          error FailedInnerCall();
      
          /**
           * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
           * `recipient`, forwarding all available gas and reverting on errors.
           *
           * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
           * of certain opcodes, possibly making contracts go over the 2300 gas limit
           * imposed by `transfer`, making them unable to receive funds via
           * `transfer`. {sendValue} removes this limitation.
           *
           * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
           *
           * IMPORTANT: because control is transferred to `recipient`, care must be
           * taken to not create reentrancy vulnerabilities. Consider using
           * {ReentrancyGuard} or the
           * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
           */
          function sendValue(address payable recipient, uint256 amount) internal {
              if (address(this).balance < amount) {
                  revert AddressInsufficientBalance(address(this));
              }
      
              (bool success, ) = recipient.call{value: amount}("");
              if (!success) {
                  revert FailedInnerCall();
              }
          }
      
          /**
           * @dev Performs a Solidity function call using a low level `call`. A
           * plain `call` is an unsafe replacement for a function call: use this
           * function instead.
           *
           * If `target` reverts with a revert reason or custom error, it is bubbled
           * up by this function (like regular Solidity function calls). However, if
           * the call reverted with no returned reason, this function reverts with a
           * {FailedInnerCall} error.
           *
           * Returns the raw returned data. To convert to the expected return value,
           * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
           *
           * Requirements:
           *
           * - `target` must be a contract.
           * - calling `target` with `data` must not revert.
           */
          function functionCall(
              address target,
              bytes memory data
          ) internal returns (bytes memory) {
              return functionCallWithValue(target, data, 0);
          }
      
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but also transferring `value` wei to `target`.
           *
           * Requirements:
           *
           * - the calling contract must have an ETH balance of at least `value`.
           * - the called Solidity function must be `payable`.
           */
          function functionCallWithValue(
              address target,
              bytes memory data,
              uint256 value
          ) internal returns (bytes memory) {
              if (address(this).balance < value) {
                  revert AddressInsufficientBalance(address(this));
              }
              (bool success, bytes memory returndata) = target.call{value: value}(
                  data
              );
              return verifyCallResultFromTarget(target, success, returndata);
          }
      
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but performing a static call.
           */
          function functionStaticCall(
              address target,
              bytes memory data
          ) internal view returns (bytes memory) {
              (bool success, bytes memory returndata) = target.staticcall(data);
              return verifyCallResultFromTarget(target, success, returndata);
          }
      
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but performing a delegate call.
           */
          function functionDelegateCall(
              address target,
              bytes memory data
          ) internal returns (bytes memory) {
              (bool success, bytes memory returndata) = target.delegatecall(data);
              return verifyCallResultFromTarget(target, success, returndata);
          }
      
          /**
           * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
           * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
           * unsuccessful call.
           */
          function verifyCallResultFromTarget(
              address target,
              bool success,
              bytes memory returndata
          ) internal view returns (bytes memory) {
              if (!success) {
                  _revert(returndata);
              } else {
                  // only check if target is a contract if the call was successful and the return data is empty
                  // otherwise we already know that it was a contract
                  if (returndata.length == 0 && target.code.length == 0) {
                      revert AddressEmptyCode(target);
                  }
                  return returndata;
              }
          }
      
          /**
           * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
           * revert reason or with a default {FailedInnerCall} error.
           */
          function verifyCallResult(
              bool success,
              bytes memory returndata
          ) internal pure returns (bytes memory) {
              if (!success) {
                  _revert(returndata);
              } else {
                  return returndata;
              }
          }
      
          /**
           * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
           */
          function _revert(bytes memory returndata) private pure {
              // Look for revert reason and bubble it up if present
              if (returndata.length > 0) {
                  // The easiest way to bubble the revert reason is using memory via assembly
                  /// @solidity memory-safe-assembly
                  assembly {
                      let returndata_size := mload(returndata)
                      revert(add(32, returndata), returndata_size)
                  }
              } else {
                  revert FailedInnerCall();
              }
          }
      }
      
      //
      // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
      /**
       * @title SafeERC20
       * @dev Wrappers around ERC20 operations that throw on failure (when the token
       * contract returns false). Tokens that return no value (and instead revert or
       * throw on failure) are also supported, non-reverting calls are assumed to be
       * successful.
       * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
       * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
       */
      library SafeERC20 {
          using Address for address;
      
          /**
           * @dev An operation with an ERC20 token failed.
           */
          error SafeERC20FailedOperation(address token);
      
          /**
           * @dev Indicates a failed `decreaseAllowance` request.
           */
          error SafeERC20FailedDecreaseAllowance(
              address spender,
              uint256 currentAllowance,
              uint256 requestedDecrease
          );
      
          /**
           * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
           * non-reverting calls are assumed to be successful.
           */
          function safeTransfer(IERC20 token, address to, uint256 value) internal {
              _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
          }
      
          /**
           * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
           * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
           */
          function safeTransferFrom(
              IERC20 token,
              address from,
              address to,
              uint256 value
          ) internal {
              _callOptionalReturn(
                  token,
                  abi.encodeCall(token.transferFrom, (from, to, value))
              );
          }
      
          /**
           * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
           * non-reverting calls are assumed to be successful.
           */
          function safeIncreaseAllowance(
              IERC20 token,
              address spender,
              uint256 value
          ) internal {
              uint256 oldAllowance = token.allowance(address(this), spender);
              forceApprove(token, spender, oldAllowance + value);
          }
      
          /**
           * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
           * value, non-reverting calls are assumed to be successful.
           */
          function safeDecreaseAllowance(
              IERC20 token,
              address spender,
              uint256 requestedDecrease
          ) internal {
              unchecked {
                  uint256 currentAllowance = token.allowance(address(this), spender);
                  if (currentAllowance < requestedDecrease) {
                      revert SafeERC20FailedDecreaseAllowance(
                          spender,
                          currentAllowance,
                          requestedDecrease
                      );
                  }
                  forceApprove(token, spender, currentAllowance - requestedDecrease);
              }
          }
      
          /**
           * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
           * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
           * to be set to zero before setting it to a non-zero value, such as USDT.
           */
          function forceApprove(
              IERC20 token,
              address spender,
              uint256 value
          ) internal {
              bytes memory approvalCall = abi.encodeCall(
                  token.approve,
                  (spender, value)
              );
      
              if (!_callOptionalReturnBool(token, approvalCall)) {
                  _callOptionalReturn(
                      token,
                      abi.encodeCall(token.approve, (spender, 0))
                  );
                  _callOptionalReturn(token, approvalCall);
              }
          }
      
          /**
           * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
           * on the return value: the return value is optional (but if data is returned, it must not be false).
           * @param token The token targeted by the call.
           * @param data The call data (encoded using abi.encode or one of its variants).
           */
          function _callOptionalReturn(IERC20 token, bytes memory data) private {
              // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
              // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
              // the target address contains contract code and also asserts for success in the low-level call.
      
              bytes memory returndata = address(token).functionCall(data);
              if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
                  revert SafeERC20FailedOperation(address(token));
              }
          }
      
          /**
           * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
           * on the return value: the return value is optional (but if data is returned, it must not be false).
           * @param token The token targeted by the call.
           * @param data The call data (encoded using abi.encode or one of its variants).
           *
           * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
           */
          function _callOptionalReturnBool(
              IERC20 token,
              bytes memory data
          ) private returns (bool) {
              // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
              // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
              // and not revert is the subcall reverts.
      
              (bool success, bytes memory returndata) = address(token).call(data);
              return
                  success &&
                  (returndata.length == 0 || abi.decode(returndata, (bool))) &&
                  address(token).code.length > 0;
          }
      }
      
      //
      // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
      /**
       * @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);
          }
      }
      
      interface IUniswapV2Router01 {
          function factory() external pure returns (address);
      
          function WETH() external pure returns (address);
      
          function addLiquidity(
              address tokenA,
              address tokenB,
              uint amountADesired,
              uint amountBDesired,
              uint amountAMin,
              uint amountBMin,
              address to,
              uint deadline
          ) external returns (uint amountA, uint amountB, uint liquidity);
      
          function addLiquidityETH(
              address token,
              uint amountTokenDesired,
              uint amountTokenMin,
              uint amountETHMin,
              address to,
              uint deadline
          )
              external
              payable
              returns (uint amountToken, uint amountETH, uint liquidity);
      
          function removeLiquidity(
              address tokenA,
              address tokenB,
              uint liquidity,
              uint amountAMin,
              uint amountBMin,
              address to,
              uint deadline
          ) external returns (uint amountA, uint amountB);
      
          function removeLiquidityETH(
              address token,
              uint liquidity,
              uint amountTokenMin,
              uint amountETHMin,
              address to,
              uint deadline
          ) external returns (uint amountToken, uint amountETH);
      
          function removeLiquidityWithPermit(
              address tokenA,
              address tokenB,
              uint liquidity,
              uint amountAMin,
              uint amountBMin,
              address to,
              uint deadline,
              bool approveMax,
              uint8 v,
              bytes32 r,
              bytes32 s
          ) external returns (uint amountA, uint amountB);
      
          function removeLiquidityETHWithPermit(
              address token,
              uint liquidity,
              uint amountTokenMin,
              uint amountETHMin,
              address to,
              uint deadline,
              bool approveMax,
              uint8 v,
              bytes32 r,
              bytes32 s
          ) external returns (uint amountToken, uint amountETH);
      
          function swapExactTokensForTokens(
              uint amountIn,
              uint amountOutMin,
              address[] calldata path,
              address to,
              uint deadline
          ) external returns (uint[] memory amounts);
      
          function swapTokensForExactTokens(
              uint amountOut,
              uint amountInMax,
              address[] calldata path,
              address to,
              uint deadline
          ) external returns (uint[] memory amounts);
      
          function swapExactETHForTokens(
              uint amountOutMin,
              address[] calldata path,
              address to,
              uint deadline
          ) external payable returns (uint[] memory amounts);
      
          function swapTokensForExactETH(
              uint amountOut,
              uint amountInMax,
              address[] calldata path,
              address to,
              uint deadline
          ) external returns (uint[] memory amounts);
      
          function swapExactTokensForETH(
              uint amountIn,
              uint amountOutMin,
              address[] calldata path,
              address to,
              uint deadline
          ) external returns (uint[] memory amounts);
      
          function swapETHForExactTokens(
              uint amountOut,
              address[] calldata path,
              address to,
              uint deadline
          ) external payable returns (uint[] memory amounts);
      
          function quote(
              uint amountA,
              uint reserveA,
              uint reserveB
          ) external pure returns (uint amountB);
      
          function getAmountOut(
              uint amountIn,
              uint reserveIn,
              uint reserveOut
          ) external pure returns (uint amountOut);
      
          function getAmountIn(
              uint amountOut,
              uint reserveIn,
              uint reserveOut
          ) external pure returns (uint amountIn);
      
          function getAmountsOut(
              uint amountIn,
              address[] calldata path
          ) external view returns (uint[] memory amounts);
      
          function getAmountsIn(
              uint amountOut,
              address[] calldata path
          ) external view returns (uint[] memory amounts);
      }
      
      interface IUniswapV2Router02 is IUniswapV2Router01 {
          function removeLiquidityETHSupportingFeeOnTransferTokens(
              address token,
              uint liquidity,
              uint amountTokenMin,
              uint amountETHMin,
              address to,
              uint deadline
          ) external returns (uint amountETH);
      
          function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
              address token,
              uint liquidity,
              uint amountTokenMin,
              uint amountETHMin,
              address to,
              uint deadline,
              bool approveMax,
              uint8 v,
              bytes32 r,
              bytes32 s
          ) external returns (uint amountETH);
      
          function swapExactTokensForTokensSupportingFeeOnTransferTokens(
              uint amountIn,
              uint amountOutMin,
              address[] calldata path,
              address to,
              uint deadline
          ) external;
      
          function swapExactETHForTokensSupportingFeeOnTransferTokens(
              uint amountOutMin,
              address[] calldata path,
              address to,
              uint deadline
          ) external payable;
      
          function swapExactTokensForETHSupportingFeeOnTransferTokens(
              uint amountIn,
              uint amountOutMin,
              address[] calldata path,
              address to,
              uint deadline
          ) external;
      }
      
      interface IUniswapV2Pair {
          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;
      }
      
      //
      // Uncomment this line to use console.log
      // import "hardhat/console.sol";
      
      // 5%
      uint256 constant TAX_BASE = 10000;
      
      uint256 constant MAX_TAX = 2000;
      
      // 20%
      uint256 constant DAY = 1 days;
      
      struct Tax {
          uint16 liquidity;
          uint16 marketing;
          uint16 ecosystem;
      }
      
      interface IUniFactory {
          function createPair(
              address tokenA,
              address tokenB
          ) external returns (address pair);
      }
      
      contract GalaxyFox is ERC20, Ownable {
          using SafeERC20 for IERC20;
      
          Tax public buyTax =
              Tax(BUY_TAX_LIQUIDIY, BUY_TAX_MARKETING, BUY_TAX_ECOSYSTEM); // 6 bytes
          Tax public sellTax =
              Tax(SELL_TAX_LIQUIDIY, SELL_TAX_MARKETING, SELL_TAX_ECOSYSTEM); // 6 bytes
      
          address payable public liquidityHolder; // 20 bytes
          address payable public marketingHolder; // 20 bytes
          address payable public ecosystemHolder; // 20 bytes
          bool public taxEnabled = false;
      
          IUniFactory public immutable uniFactory; // 20 bytes
          IUniswapV2Router02 public immutable uniRouter; // 20 bytes
          address public immutable weth; // 20 bytes
          address public immutable uniPair; // 20 bytes
      
          mapping(address => bool) public isExcludedFromFee;
      
          mapping(address => bool) public isPair;
      
          mapping(address => mapping(uint256 => uint256)) public volume;
          mapping(address => bool) public isExcludedFromDailyVolume;
      
          uint256 public maxDailyVolume = INITIAL_SUPPLY / 1000;
      
          uint256 public liquidityReserves;
          uint256 public miniBeforeLiquify;
      
          event TaxEnabled(bool enabled);
          event ExeededFromFee(address account, bool excluded);
          event Pair(address pair, bool isPair);
          event EcosystemHolder(address oldHolder, address holder);
          event MarketingHolder(address oldHolder, address holder);
          event LiquidityHolder(address oldHolder, address holder);
          event SellTaxChanged(uint16 liquidity, uint16 marketing, uint16 ecosystem);
          event BuyTaxChanged(uint16 liquidity, uint16 marketing, uint16 ecosystem);
          event ExcludedFromDailyVolume(address account, bool excluded);
          event MaxDailyVolumeChanged(uint256 maxDailyVolume);
          event MiniBeforeLiquifyChanged(uint256 miniBeforeLiquifyArg);
      
          constructor(
              // to allow for easy testing/deploy on behalf of someone else
              address _ownerArg,
              address payable _ecosystemHolder,
              address payable _marketingHolder,
              address payable _liquidityHolder,
              IUniswapV2Router02 _uniswapV2Router,
              IUniFactory _uniswapV2Factory
          ) ERC20(NAME, SYMBOL) Ownable(_ownerArg) {
              _mint(_ownerArg, INITIAL_SUPPLY);
      
              require(
                  _ecosystemHolder != address(0),
                  "GalaxyFox: ecosystem holder is the zero address"
              );
              ecosystemHolder = _ecosystemHolder;
              require(
                  _marketingHolder != address(0),
                  "GalaxyFox: marketing holder is the zero address"
              );
              marketingHolder = _marketingHolder;
              require(
                  _liquidityHolder != address(0),
                  "GalaxyFox: liquidity holder is the zero address"
              );
              liquidityHolder = _liquidityHolder;
      
              uniRouter = _uniswapV2Router;
              uniFactory = _uniswapV2Factory;
      
              weth = _uniswapV2Router.WETH();
      
              // Create a uniswap pair for this new token
              uniPair = _uniswapV2Factory.createPair(address(this), weth);
      
              // approve token transfer to cover all future transfereFrom calls
              _approve(address(this), address(_uniswapV2Router), type(uint256).max);
      
              isPair[uniPair] = true;
      
              isExcludedFromFee[address(this)] = true;
      
              isExcludedFromFee[_ownerArg] = true;
      
              isExcludedFromDailyVolume[_ownerArg] = true;
      
              isExcludedFromDailyVolume[uniPair] = true;
      
              isExcludedFromDailyVolume[address(this)] = true;
          }
      
          receive() external payable {
              // only receive from router
              require(msg.sender == address(uniRouter), "Invalid sender");
          }
      
          /**
           * @notice Transfers tokens to a recipient
           * @param recipient address to send the tokens to
           * @param amount  amount of tokens to send
           */
          function transfer(
              address recipient,
              uint256 amount
          ) public virtual override returns (bool) {
              _customTransfer(_msgSender(), recipient, amount);
              return true;
          }
      
          /**
           * @notice Transfers tokens from a sender to a recipient (requires approval)
           * @param sender address to send the tokens from
           * @param recipient address to send the tokens to
           * @param amount  amount of tokens to send
           */
          function transferFrom(
              address sender,
              address recipient,
              uint256 amount
          ) public virtual override returns (bool) {
              uint256 allowance = allowance(sender, _msgSender());
              require(amount <= allowance, "Transfer amount exceeds allowance");
      
              // overflow is checked above
              unchecked {
                  // decrease allowance if not max approved
                  if (allowance < type(uint256).max)
                      _approve(sender, _msgSender(), allowance - amount, true);
              }
      
              _customTransfer(sender, recipient, amount);
      
              return true;
          }
      
          function _customTransfer(
              address sender,
              address recipient,
              uint256 amount
          ) internal {
              if (sender != uniPair) _liquify();
      
              if (
                  !taxEnabled ||
                  isExcludedFromFee[sender] ||
                  isExcludedFromFee[recipient] ||
                  (!isPair[recipient] && !isPair[sender]) ||
                  inswap == 1
              ) {
                  _transfer(sender, recipient, amount);
              } else {
                  Tax memory tax = isPair[recipient] ? buyTax : sellTax;
      
                  // buy
                  uint256 marketingTax = (amount * tax.marketing) / TAX_BASE;
                  uint256 ecosystemTax = (amount * tax.ecosystem) / TAX_BASE;
                  uint256 liquidityTax = (amount * tax.liquidity) / TAX_BASE;
      
                  if (ecosystemTax > 0)
                      _transfer(sender, ecosystemHolder, ecosystemTax);
                  if (marketingTax > 0)
                      _transfer(sender, marketingHolder, marketingTax);
      
                  _transfer(
                      sender,
                      recipient,
                      amount - marketingTax - ecosystemTax - liquidityTax
                  );
      
                  if (liquidityTax > 0) {
                      liquidityReserves += liquidityTax;
                      _transfer(sender, address(this), liquidityTax);
                  }
              }
      
              // DAY is constant so no division by 0
              // volume can't overflow if we reached this point (balance check)
              unchecked {
                  // loss of precision is wanted here
                  uint256 period = block.timestamp / DAY;
      
                  volume[sender][period] += amount;
                  require(
                      volume[sender][period] <= maxDailyVolume ||
                          isExcludedFromDailyVolume[sender],
                      "GalaxyFox: max daily volume exceeded"
                  );
              }
          }
      
          /**
           * @notice Enable or disable taxes
           * @param taxEnabledArg true to enable tax, false to disable
           */
          function setTaxEnabled(bool taxEnabledArg) public onlyOwner {
              require(taxEnabled != taxEnabledArg, "GalaxyFox: already set");
              taxEnabled = taxEnabledArg;
      
              emit TaxEnabled(taxEnabledArg);
          }
      
          /**
           * @notice Sets the minimum amount of tokens that must be in the contract before liquifying
           * @param miniBeforeLiquifyArg  The minimum amount of tokens that must be in the contract before liquifying
           */
          function setMiniBeforeLiquify(
              uint256 miniBeforeLiquifyArg
          ) public onlyOwner {
              require(
                  miniBeforeLiquifyArg != miniBeforeLiquify,
                  "GalaxyFox: already set"
              );
              miniBeforeLiquify = miniBeforeLiquifyArg;
      
              emit MiniBeforeLiquifyChanged(miniBeforeLiquifyArg);
          }
      
          /**
           * @notice sets whether an address is excluded  from fees or not
           * @param account The address to exclude/include from fees
           * @param excluded  true to exclude, false to include
           */
          function setExcludedFromFee(
              address account,
              bool excluded
          ) public onlyOwner {
              require(
                  isExcludedFromFee[account] != excluded,
                  "GalaxyFox: already set"
              );
              isExcludedFromFee[account] = excluded;
      
              emit ExeededFromFee(account, excluded);
          }
      
          /**
           *  @notice declare if an address is an lp pair or not
           * @param pair address of the LP Pool
           * @param isPairArg  true if the address is a pair, false otherwise
           */
          function setPair(address pair, bool isPairArg) public onlyOwner {
              require(isPair[pair] != isPairArg, "GalaxyFox: already set");
              isPair[pair] = isPairArg;
      
              emit Pair(pair, isPairArg);
          }
      
          /**
           * @dev sets the ecosystem holder address
           * @param _ecosystemHolder The address of the ecosystem holder
           */
          function setEcosystemHolder(
              address payable _ecosystemHolder
          ) public onlyOwner {
              require(_ecosystemHolder != ecosystemHolder, "GalaxyFox: already set");
              require(_ecosystemHolder != address(0), "GalaxyFox: zero address");
              ecosystemHolder = _ecosystemHolder;
      
              emit EcosystemHolder(ecosystemHolder, _ecosystemHolder);
          }
      
          /**
           * @dev Sets the marketing holder address
           * @param _marketingHolder The address of the marketing holder
           */
          function setMarketingHolder(
              address payable _marketingHolder
          ) public onlyOwner {
              require(_marketingHolder != marketingHolder, "GalaxyFox: already set");
              require(_marketingHolder != address(0), "GalaxyFox: zero address");
              marketingHolder = _marketingHolder;
      
              emit MarketingHolder(marketingHolder, _marketingHolder);
          }
      
          /**
           * @dev Sets the liquidity holder address
           * @param _liquidityHolder The address of the liquidity holder
           */
          function setLiquidityHolder(
              address payable _liquidityHolder
          ) public onlyOwner {
              require(_liquidityHolder != liquidityHolder, "GalaxyFox: already set");
              require(_liquidityHolder != address(0), "GalaxyFox: zero address");
              liquidityHolder = _liquidityHolder;
              emit LiquidityHolder(liquidityHolder, _liquidityHolder);
          }
      
          /**
           * @dev Changes the tax on buys
           * @param _liquidity liquidity tax in basis points
           * @param _marketing marketing tax in basis points
           * @param _ecosystem ecosystem tax in basis points
           */
          function setSellTax(
              uint16 _liquidity,
              uint16 _marketing,
              uint16 _ecosystem
          ) public onlyOwner {
              require(
                  _liquidity + _marketing + _ecosystem <= MAX_TAX,
                  "GalaxyFox: tax too high"
              );
              sellTax = Tax(_liquidity, _marketing, _ecosystem);
      
              emit SellTaxChanged(_liquidity, _marketing, _ecosystem);
          }
      
          /**
           * @dev Changes the tax on sells
           * @param _liquidity liquidity tax in basis points
           * @param _marketing marketing tax in basis points
           * @param _ecosystem ecosystem tax in basis points
           */
          function setBuyTax(
              uint16 _liquidity,
              uint16 _marketing,
              uint16 _ecosystem
          ) public onlyOwner {
              require(
                  _liquidity + _marketing + _ecosystem <= MAX_TAX,
                  "GalaxyFox: tax too high"
              );
              buyTax = Tax(_liquidity, _marketing, _ecosystem);
      
              emit BuyTaxChanged(_liquidity, _marketing, _ecosystem);
          }
      
          /**
           * @notice Burns tokens from the caller
           * @param amount amount of tokens to burn
           */
          function burn(uint256 amount) public {
              _burn(msg.sender, amount);
          }
      
          /**
           * @notice Recovers lost tokens or ETH, doesn't include the liquidity reserves
           * @param tokenAddress address of the token to recover
           */
          function recoverLostTokens(address tokenAddress) public onlyOwner {
              if (tokenAddress != address(this)) {
                  uint256 tokenAmount = tokenAddress != address(0)
                      ? IERC20(tokenAddress).balanceOf(address(this))
                      : address(this).balance;
      
                  if (tokenAmount > 0 && tokenAddress != address(0)) {
                      IERC20(tokenAddress).safeTransfer(msg.sender, tokenAmount);
                  } else if (tokenAmount > 0) {
                      (bool success, ) = payable(msg.sender).call{value: tokenAmount}(
                          ""
                      );
                      require(success, "Failed to send Ether");
                  }
              } else {
                  uint256 tokenAmount = balanceOf(address(this)) - liquidityReserves;
                  _transfer(address(this), msg.sender, tokenAmount);
              }
          }
      
          /**
           * @notice Sets whether an address is excluded from maxDailyVolume or not
           * @param account account to be included/excluded from maxDailyVolume
           * @param excluded true to exclude, false to include
           */
          function setExludedFromDailyVolume(
              address account,
              bool excluded
          ) public onlyOwner {
              require(
                  isExcludedFromDailyVolume[account] != excluded,
                  "GalaxyFox: already set"
              );
              isExcludedFromDailyVolume[account] = excluded;
      
              emit ExcludedFromDailyVolume(account, excluded);
          }
      
          /**
           * @notice Sets the max daily volume max is 0.1% of the total supply
           * @param maxDailyVolumeArg The new max daily volume
           */
          function setMaxDailyVolume(uint256 maxDailyVolumeArg) public onlyOwner {
              require(maxDailyVolumeArg != maxDailyVolume, "GalaxyFox: already set");
              // require that the max daily volume is at least 0.1% of the total supply
              require(
                  maxDailyVolumeArg >= totalSupply() / 1000,
                  "GalaxyFox: max daily volume too low"
              );
              maxDailyVolume = maxDailyVolumeArg;
      
              emit MaxDailyVolumeChanged(maxDailyVolumeArg);
          }
      
          // using uint256 is cheaper than using bool
          // because there will be no extra work to read it
          // sunce when used we always return it back to 0
          // it will trigger a refund
          uint256 inswap = 0;
      
          /**
           * @notice creates lp from the liquidity reserves
           */
          function liquify() external onlyOwner {
              _liquify();
          }
      
          function _liquify() private {
              if (inswap == 1) return;
      
              if (liquidityReserves > miniBeforeLiquify) {
                  inswap = 1;
                  // get reserves from pair
                  (uint256 reserves0, uint256 reserves1, ) = IUniswapV2Pair(uniPair)
                      .getReserves();
      
                  // Check Uniswap library sortTokens (token0 < token1)
                  uint256 tokenReserves = address(this) < weth
                      ? reserves0
                      : reserves1;
      
                  // swap capped at 10% of the reserves which is tecnically 5% because we only swap half
                  uint256 maxToSwap = (tokenReserves * 10) / 100;
      
                  uint256 toswap = liquidityReserves > maxToSwap
                      ? maxToSwap
                      : liquidityReserves;
      
                  uint256 half = toswap / 2;
                  // avoids precision loss
                  uint256 otherHalf = toswap - half;
      
                  _swapTokensForEth(half);
      
                  uint256 newBalance = address(this).balance;
      
                  _addLiquidity(otherHalf, newBalance);
      
                  liquidityReserves -= toswap;
                  inswap = 0;
              }
          }
      
          function _swapTokensForEth(uint256 tokenAmount) internal {
              // generate the uniswap pair path of token -> weth
              address[] memory path = new address[](2);
              path[0] = address(this);
              path[1] = weth;
      
              // make the swap safely, do not revert if swap fails
              try
                  uniRouter.swapExactTokensForETHSupportingFeeOnTransferTokens(
                      tokenAmount,
                      0, // accept any amount of ETH
                      path,
                      address(this),
                      block.timestamp
                  )
              {} catch {}
          }
      
          function _addLiquidity(uint256 tokenAmount, uint256 ethAmount) internal {
              // do not revert if addlp fails
              try
                  uniRouter.addLiquidityETH{value: ethAmount}(
                      address(this),
                      tokenAmount,
                      0,
                      0,
                      liquidityHolder,
                      block.timestamp
                  )
              {} catch {}
          }
      }