HIGH severity: PVO - Potential Volume Overflow. The contract's volume tracking logic does not adequately check for overflow when a user is flagged as `isExcludedFromDailyVolume`, leading to potential unintended behavior.

Vulnerable code:
// 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 {}

    }

}

Vulnerability type: CWE-703|CWE-755|CWE-390