AVAX Price: $24.85 (-6.37%)
Gas: 1.6 nAVAX
 

Overview

AVAX Balance

Avalanche C-Chain LogoAvalanche C-Chain LogoAvalanche C-Chain Logo42.411642075942201611 AVAX

AVAX Value

$1,053.87 (@ $24.85/AVAX)

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Swap Native To T...569484452025-02-07 1:34:396 hrs ago1738892079IN
0x9393F19A...cF1F15347
0.09393 AVAX0.000117521.06224254
Swap Native To T...569484342025-02-07 1:34:156 hrs ago1738892055IN
0x9393F19A...cF1F15347
0.09393 AVAX0.000114921.03874655
Swap Native To T...569484212025-02-07 1:33:536 hrs ago1738892033IN
0x9393F19A...cF1F15347
0.09393 AVAX0.000113791.02852631
Swap Native To T...569484162025-02-07 1:33:406 hrs ago1738892020IN
0x9393F19A...cF1F15347
0.09393 AVAX0.000131961.03308818
Transfer569476252025-02-07 1:07:586 hrs ago1738890478IN
0x9393F19A...cF1F15347
0 AVAX0.000147242.50157906
Claim Fees569379342025-02-06 20:14:5711 hrs ago1738872897IN
0x9393F19A...cF1F15347
0 AVAX0.000060821.01609084
Approve569019282025-02-06 3:06:0128 hrs ago1738811161IN
0x9393F19A...cF1F15347
0 AVAX0.000123342.50411294
Remove Liquidity569018842025-02-06 3:04:2728 hrs ago1738811067IN
0x9393F19A...cF1F15347
0 AVAX0.000126041.00063723
Swap Token To Na...568954182025-02-05 23:45:1632 hrs ago1738799116IN
0x9393F19A...cF1F15347
0 AVAX0.000173991.5041708
Swap Token To Na...568726722025-02-05 12:44:4443 hrs ago1738759484IN
0x9393F19A...cF1F15347
0 AVAX0.000121851.05329426
Remove Liquidity568726602025-02-05 12:44:2043 hrs ago1738759460IN
0x9393F19A...cF1F15347
0 AVAX0.000113511.0428656
Remove Liquidity568711182025-02-05 11:59:3943 hrs ago1738756779IN
0x9393F19A...cF1F15347
0 AVAX0.00024582.00313029
Remove Liquidity568567362025-02-05 4:56:482 days ago1738731408IN
0x9393F19A...cF1F15347
0 AVAX0.000163131.54468497
Approve568503612025-02-05 1:41:172 days ago1738719677IN
0x9393F19A...cF1F15347
0 AVAX0.000125542.55002512
Swap Token To Na...568421332025-02-04 21:45:172 days ago1738705517IN
0x9393F19A...cF1F15347
0 AVAX0.000238252.05972142
Approve568139512025-02-04 9:30:082 days ago1738661408IN
0x9393F19A...cF1F15347
0 AVAX0.000126842.56321027
Approve567994302025-02-04 2:53:373 days ago1738637617IN
0x9393F19A...cF1F15347
0 AVAX0.00012492.53703398
Swap Native To T...567959112025-02-04 1:06:213 days ago1738631181IN
0x9393F19A...cF1F15347
0.09393 AVAX0.000117781.06455505
Swap Token To Na...567952692025-02-04 0:48:413 days ago1738630121IN
0x9393F19A...cF1F15347
0 AVAX0.000119211.03026447
Swap Native To T...567930962025-02-03 23:43:213 days ago1738626201IN
0x9393F19A...cF1F15347
0.09393 AVAX0.000111851.01095526
Swap Native To T...567928262025-02-03 23:36:103 days ago1738625770IN
0x9393F19A...cF1F15347
0.02 AVAX0.000283442.56243774
Approve567881612025-02-03 21:46:563 days ago1738619216IN
0x9393F19A...cF1F15347
0 AVAX0.000059091.19964026
Remove Liquidity567871712025-02-03 21:23:523 days ago1738617832IN
0x9393F19A...cF1F15347
0 AVAX0.000250462.04109211
Swap Token To Na...567700022025-02-03 14:29:033 days ago1738592943IN
0x9393F19A...cF1F15347
0 AVAX0.000183671.58785789
Swap Token To Na...567684932025-02-03 13:55:153 days ago1738590915IN
0x9393F19A...cF1F15347
0 AVAX0.000126631.09472791
View all transactions

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
569379342025-02-06 20:14:5711 hrs ago1738872897
0x9393F19A...cF1F15347
0.16450163 AVAX
569018842025-02-06 3:04:2728 hrs ago1738811067
0x9393F19A...cF1F15347
0.59141041 AVAX
568954212025-02-05 23:45:2032 hrs ago1738799120
0x9393F19A...cF1F15347
1 AVAX
568954182025-02-05 23:45:1632 hrs ago1738799116
0x9393F19A...cF1F15347
1.72019552 AVAX
568726722025-02-05 12:44:4443 hrs ago1738759484
0x9393F19A...cF1F15347
0.02731642 AVAX
568726602025-02-05 12:44:2043 hrs ago1738759460
0x9393F19A...cF1F15347
0.02769366 AVAX
568711182025-02-05 11:59:3943 hrs ago1738756779
0x9393F19A...cF1F15347
0.03557569 AVAX
568567362025-02-05 4:56:482 days ago1738731408
0x9393F19A...cF1F15347
0.28456475 AVAX
568421362025-02-04 21:45:202 days ago1738705520
0x9393F19A...cF1F15347
0.5 AVAX
568421332025-02-04 21:45:172 days ago1738705517
0x9393F19A...cF1F15347
1.20140331 AVAX
567994452025-02-04 2:54:063 days ago1738637646
0x9393F19A...cF1F15347
0.76848177 AVAX
567978162025-02-04 2:03:533 days ago1738634633
0x9393F19A...cF1F15347
0.75 AVAX
567976942025-02-04 2:00:143 days ago1738634414
0x9393F19A...cF1F15347
0.25 AVAX
567952692025-02-04 0:48:413 days ago1738630121
0x9393F19A...cF1F15347
0.12609483 AVAX
567882052025-02-03 21:48:023 days ago1738619282
0x9393F19A...cF1F15347
3.81089449 AVAX
567881872025-02-03 21:47:363 days ago1738619256
0x9393F19A...cF1F15347
4.08005723 AVAX
567871712025-02-03 21:23:523 days ago1738617832
0x9393F19A...cF1F15347
0.02136349 AVAX
567845322025-02-03 20:17:183 days ago1738613838
0x9393F19A...cF1F15347
0.18175 AVAX
567700042025-02-03 14:29:053 days ago1738592945
0x9393F19A...cF1F15347
1 AVAX
567700022025-02-03 14:29:033 days ago1738592943
0x9393F19A...cF1F15347
2.10718383 AVAX
567684952025-02-03 13:55:173 days ago1738590917
0x9393F19A...cF1F15347
1 AVAX
567684932025-02-03 13:55:153 days ago1738590915
0x9393F19A...cF1F15347
1.7476751 AVAX
567385612025-02-03 1:23:384 days ago1738545818
0x9393F19A...cF1F15347
0.04886135 AVAX
567317512025-02-02 22:33:274 days ago1738535607
0x9393F19A...cF1F15347
0.01584668 AVAX
567317222025-02-02 22:32:494 days ago1738535569
0x9393F19A...cF1F15347
0.01606014 AVAX
View All Internal Transactions
Loading...
Loading

Minimal Proxy Contract for 0x52d370e60c8220497da6abff36bb2587a31203b6

Contract Name:
BurstToken

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 125 runs

Other Settings:
paris EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 16 : BurstToken.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import "../BIFKN314.sol";

/**
 * @title BurstToken
 * @dev This contract extends the BIFKN314 contract to implement a token with a bonding curve mechanism.
 * It includes functionalities to manage the bonding curve phase and restrict certain operations during this phase.
 *
 * Key functionalities include:
 * - Initializing the Burst Factory address.
 * - Marking the bonding curve as complete.
 * - Overriding the `_update` function to include bonding curve restrictions.
 *
 * The contract uses the following custom errors for better error handling:
 * - `StillBonding`: Indicates that an operation cannot be performed because the bonding period is still active.
 * - `Unauthorized`: Indicates that the caller is not authorized to perform the operation.
 * - `InvalidAddress`: Indicates that an invalid address was provided.
 * - `AlreadyInitialized`: Indicates that the Burst Factory address has already been initialized.
 */
contract BurstToken is BIFKN314 {
    // Address of Burst Factory
    address public burstFactory;

    // Bonding Curve Complete
    bool public curveComplete;

    modifier onlyBurstFactory() {
        if (msg.sender != burstFactory) revert Unauthorized(msg.sender);
        _;
    }

    /**
     * @dev Error to indicate that an operation cannot be performed because the bonding period is still active.
     */
    error StillBonding();

    /**
     * @dev Constructor function for the BurstToken contract.
     * It initializes the contract by calling the constructor of the BIFKN314 contract.
     */
    constructor() BIFKN314() {}

    /**
     * @dev Initializes the Burst Token.
     * @param burstFactory_ The new address of the Burst Factory.
     * @notice Only the contract owner can call this function.
     * @notice Reverts if the provided address is invalid (address(0)).
     */
    function initializeBurstToken(address burstFactory_) external onlyOwner {
        if (burstFactory_ == address(0)) revert InvalidAddress();
        if (burstFactory != address(0)) revert AlreadyInitialized();

        burstFactory = burstFactory_;
    }

    /**
     * @notice Marks the curve as complete.
     * @dev This function can only be called by the BurstFactory contract.
     * @dev Sets the `curveComplete` state variable to true.
     * @dev External function.
     */
    function completeTheCurve() external onlyBurstFactory {
        curveComplete = true;
    }

    /**
     * @dev Internal function to update token transfers.
     * Overrides the `_update` function from the parent contract.
     *
     * This function performs the following actions:
     * 1. Calls the parent contract's `_update` function to handle the basic transfer logic.
     * 2. Checks if the bonding curve phase is still active (`curveComplete` is false).
     * 3. If the bonding curve phase is active, it ensures that the transfer is not between certain restricted addresses.
     *
     * @param from The address from which tokens are being transferred.
     * @param to The address to which tokens are being transferred.
     * @param amount The amount of tokens being transferred.
     *
     * @notice Reverts with `StillBonding` if the bonding curve phase is active and the transfer involves restricted addresses.
     */
    function _update(
        address from,
        address to,
        uint256 amount
    ) internal virtual override {
        // Is still in bonding curve phase
        if (!curveComplete) {
            if (
                from != burstFactory &&
                from != address(0) &&
                to != burstFactory &&
                to != DEAD_ADDRESS &&
                to != address(0)
            ) revert StillBonding();
        }
        super._update(from, to, amount);
    }
}

File 2 of 16 : BIFKN314.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import "./BIFKNERC20.sol";
import "./BIFKN314LP.sol";
import "./PreventAutoSwap.sol";
import "./interfaces/IBIFKN314Factory.sol";
import "./interfaces/IBIFKN314CALLEE.sol";
import "./interfaces/IERC314Errors.sol";
import "./interfaces/IERC314Events.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";

/**
 * @title BIFKN314
 * @dev This is a contract that implements the core functionality of the BIFKN314 token.
 * The contract is used to create a token that can be used for liquidity provision and swapping.
 * It follows the Automated Market Maker (AMM) model using the constant product formula.
 * The contract allows users to add and remove liquidity, swap tokens, and perform flash swaps.
 * The contract also accrues fees and distributes them to the feeTo address.
 * The contract is initialized with a supply cap.
 * The contract also maintains a reference to the BIFKN314LP contract for LP token management.
 * The contract allows for a factory address of address(0) to be set, which will disable fee distribution.
 * The contract owner can set the trading fee rate, maximum wallet percentage, and metadata URI.
 * The contract owner can also enable trading, set the fee collector address, and claim accrued trading fees.
 */

contract BIFKN314 is
    BIFKNERC20,
    ReentrancyGuard,
    PreventAutoSwap,
    IERC314Errors,
    IERC314Events
{
    using Math for uint256;

    /**
     * @dev Represents the address constant for the dead address.
     * The dead address is a predefined address with all zeros, used to represent
     * an address that is no longer in use or has been destroyed.
     */
    address public constant DEAD_ADDRESS =
        0x000000000000000000000000000000000000dEaD;

    /**
     * @dev The minimum liquidity required for a transaction.
     */
    uint256 public constant MINIMUM_LIQUIDITY = 10 ** 3;

    /**
     * @dev The `FLASHSWAP_FEE_RATE` constant represents the fee rate for flash swaps.
     * It is set to 30, which corresponds to a fee rate of 0.3%.
     */
    uint256 public constant FLASHSWAP_FEE_RATE = 30; // 0.3% fee

    /**
     * @dev The base swap rate for the contract.
     * It represents a 0.3% fee for each swap.
     */
    uint256 public constant BASE_SWAP_RATE = 30; // 0.3% fee

    /**
     * @dev The SCALE_FACTOR constant represents the scaling factor used in the contract.
     * It is set to 10000.
     */
    uint256 public constant SCALE_FACTOR = 10000;

    /**
     * @dev The MAX_FEE_RATE constant represents the maximum fee rate that can be set.
     * It is set to 500, which corresponds to a fee rate of 5%.
     */
    uint256 public constant MAX_FEE_RATE = 500; // 5% fee

    /**
     * @dev Represents the metadata URI for the contract.
     */
    string public metadataURI;

    /**
     * @dev Represents the LP token contract for the BIFKN314 contract.
     */
    BIFKN314LP public liquidityToken;

    /**
     * @dev A public boolean variable that indicates whether the contract is initialized or not.
     */
    bool public isInitialized;

    /**
     * @dev A boolean variable indicating whether trading is enabled or not.
     * Once trading is enabled, it cannot be disabled.
     * Trading must be enabled before users can swap tokens.
     * Trading can only be enabled by the contract owner.
     * Trading is disabled by default.
     */
    bool public tradingEnabled;

    /**
     * @dev A mapping that stores whether an address is exempt from the maximum wallet limit.
     */
    mapping(address => bool) public isMaxWalletExempt;

    /**
     * @dev Represents the last cumulative price of the native asset.
     */
    uint256 public price0CumulativeLast;

    /**
     * @dev Represents the last cumulative price of the token.
     */
    uint256 public price1CumulativeLast;

    /**
     * @dev Represents the timestamp of the last block for enabling twap
     */
    uint32 public blockTimestampLast;

    /**
     * @dev The address of the factory contract.
     */
    IBIFKN314Factory public factory;

    /**
     * @dev The maximum percentage of the total supply that a wallet can hold.
     * For example, a value of 100 represents 1% of the total supply.
     */
    uint256 public maxWalletPercent;

    /**
     * @dev A boolean variable that indicates whether the maximum wallet limit is enabled or not.
     */
    bool public maxWalletEnabled;

    /**
     * @dev Public variable to store the accrued native fees.
     */
    uint256 public accruedNativeFactoryFees;

    /**
     * @dev Public variable to store the amount of accrued token fees.
     */
    uint256 public accruedTokenFactoryFees;

    /**
     * @dev The tradingFeeRate variable represents the rate at which trading fees are charged.
     * It is a public variable, meaning it can be accessed and modified by other contracts and external accounts.
     * The value of tradingFeeRate is a uint256, which represents a non-negative integer.
     * If the value of tradingFeeRate is 0, no trading fees are charged.
     * 15 represents a trading fee of 0.15%.
     * 100 represents a trading fee of 1%.
     * If the value of tradingFeeRate is 500, a trading fee of 5% is charged.
     */
    uint256 public tradingFeeRate;

    /**
     * @dev Public variable to store the accrued trading fees.
     */
    uint256 public accruedNativeTradingFees;

    /**
     * @dev Public variable to store the accrued token trading fees.
     */
    uint256 public accruedTokenTradingFees;

    /**
     * @dev The address of the fee collector.
     */
    address public feeCollector;

    /**
     * @dev The address of the contract owner.
     */
    address public owner;

    /**
     * @dev Modifier that allows only the contract owner to execute the function.
     * Throws an error if the caller is not the owner.
     */
    modifier onlyOwner() {
        if (_msgSender() != owner) revert Unauthorized(_msgSender());
        _;
    }

    /**
     * @dev Modifier that allows only the fee collector to execute the function.
     * Throws an error if the caller is not the fee collector.
     */
    modifier onlyFeeCollector() {
        if (_msgSender() != feeCollector) revert Unauthorized(_msgSender());
        _;
    }

    /**
     * @dev Modifier to ensure that a transaction is executed before the specified deadline.
     * @param deadline The deadline timestamp after which the transaction is considered expired.
     * @notice This modifier reverts the transaction if the current block timestamp is greater than or equal to the deadline.
     */
    modifier ensureDeadline(uint deadline) {
        if (block.timestamp >= deadline) revert TransactionExpired();
        _;
    }

    /**
     * @dev Constructor function for the BIFKN314 contract.
     * It initializes the contract by calling the constructor of the BIFKNERC20 contract.
     * If the message sender is a contract, it sets the factory address to the message sender.
     * If the message sender is not a contract, it sets the factory address to address(0).
     * Finally, it transfers the ownership of the contract to the message sender.
     */
    constructor() BIFKNERC20() {
        address sender = _msgSender();
        _transferOwnership(sender);
    }

    /**
     * @dev Initializes the factory contract with a new owner.
     * @param newOwner The address of the new owner.
     * @notice This function can only be called once to initialize the factory contract.
     * @notice Once initialized, the ownership of the contract will be transferred to the factory contract.
     * @notice If the factory contract has already been initialized, calling this function will revert.
     */
    function initializeFactory(address newOwner) external virtual {
        // Check if the factory contract has already been initialized
        // if the address of the factory contract is not the zero address, revert
        if (address(factory) != address(0)) revert AlreadyInitialized();

        factory = IBIFKN314Factory(newOwner);
        _transferOwnership(address(factory));
    }

    /**
     * @dev Initializes the contract with the given name and symbol.
     * Only the contract owner can call this function.
     *
     * @param tokenName The name of the contract.
     * @param tokenSymbol The symbol of the contract.
     */
    function initialize(
        string memory tokenName,
        string memory tokenSymbol
    ) public override onlyOwner {
        super.initialize(tokenName, tokenSymbol);

        liquidityToken = new BIFKN314LP();
        liquidityToken.initialize(
            string(abi.encodePacked(tokenName, " LP Token")),
            string("BLP")
        );
    }

    /**
     * @dev Sets the total supply and mints tokens to the specified owner.
     * @param totalSupply_ The total supply of tokens to be minted.
     * @param owner_ The address of the owner to receive the minted tokens.
     * @param feeRate_ The trading fee rate to be set.
     * @param maxWalletPercent_ The maximum wallet percentage to be set.
     * @param metadataURI_ The metadata URI to be set.
     * @notice Only the contract owner can call this function.
     * @notice The total supply must be greater than zero.
     * @notice The total supply must not have been already minted.
     * @notice The owner address must not be the zero address.
     */
    function setSupplyAndMint(
        uint256 totalSupply_,
        address owner_,
        uint256 feeRate_,
        uint256 maxWalletPercent_,
        string memory metadataURI_
    ) public onlyOwner {
        if (totalSupply_ == 0) {
            revert AmountMustBeGreaterThanZero();
        }
        if (totalSupply() > 0) {
            revert SupplyAlreadyMinted();
        }
        if (owner_ == address(0)) {
            revert InvalidOwner();
        }

        if (maxWalletPercent_ > 0) {
            maxWalletEnabled = true;
            setMaxWalletPercent(maxWalletPercent_);
        }

        metadataURI = metadataURI_;
        setTradingFeeRate(feeRate_);
        _transferOwnership(owner_);
        feeCollector = owner_;

        super._mint(owner_, totalSupply_);
    }

    /**
     * @dev Transfers tokens from the sender to the recipient.
     * Overrides the transfer function from the inherited contract.
     * If the recipient is this contract and autoSwap is not prevented,
     * then it automatically swaps tokens to native currency.
     * Otherwise, calls the transfer function from the inherited contract.
     * @param recipient The address receiving the tokens.
     * @param amount The amount of tokens to transfer.
     * @return success A boolean indicating the success of the transfer.
     */
    function transfer(
        address recipient,
        uint256 amount
    ) public override returns (bool success) {
        if (_checkAndPerformAutoSwap(recipient, amount)) {
            success = true;
        } else {
            _checkMaxWallet(recipient, amount);
            success = super.transfer(recipient, amount);
        }
    }

    /**
     * @dev Transfers tokens from one address to another using an allowance.
     * Overrides the transferFrom function from the inherited contract.
     * Includes a max wallet check to ensure the recipient's balance does not exceed the limit.
     * @param sender The address sending the tokens.
     * @param recipient The address receiving the tokens.
     * @param amount The amount of tokens to transfer.
     * @return success A boolean indicating the success of the transfer.
     */
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) public override returns (bool success) {
        if (_checkAndPerformAutoSwap(recipient, amount)) {
            success = true;
        } else {
            _checkMaxWallet(recipient, amount);
            success = super.transferFrom(sender, recipient, amount);
        }
    }

    /**
     * @dev Internal function to transfer tokens from one address to another.
     * Overrides the internal transfer function from the inherited contract.
     * Calls the transfer function from the inherited contract.
     * This function is specifically used when transferring tokens to the contract
     * for the purpose of adding liquidity, swapping, or flash swapping.
     * @param from The address to transfer tokens from.
     * @param to The address to transfer tokens to.
     * @param value The amount of tokens to transfer.
     */
    function _internalTransfer(
        address from,
        address to,
        uint256 value
    ) internal {
        super._transfer(from, to, value);
    }

    /**
     * @dev Internal function to be called before any transfer of tokens.
     * Checks to see if an autoswap condition is true, if so it swaps tokens
     * @param to The address receiving the tokens.
     * @param amount The amount of tokens to transfer.
     * @return swapped A boolean indicating whether the tokens were swapped.
     */
    function _checkAndPerformAutoSwap(
        address to,
        uint256 amount
    ) internal returns (bool swapped) {
        if (to == address(this) && !_autoSwapIsPrevented()) {
            swapTokenToNative(
                amount,
                _calculateAutoSwapSlippage(amount, false),
                block.timestamp + 3 minutes
            );
            swapped = true;
        }
    }

    /**
     * @dev Adds liquidity to the contract by depositing tokens and native currency.
     * @param amountToken_ The amount of tokens to be deposited.
     * @param recipient The address of the recipient of the liquidity tokens.
     * @param deadline The deadline in unix time from the current timestamp for the transaction to occur.
     * @return liquidity The amount of liquidity tokens minted.
     */
    function addLiquidity(
        uint256 amountToken_,
        address recipient,
        uint256 deadline
    )
        public
        payable
        nonReentrant
        ensureDeadline(deadline)
        returns (uint256 liquidity)
    {
        address sender = _msgSender();

        if (amountToken_ == 0 || msg.value == 0) {
            revert AmountMustBeGreaterThanZero();
        }

        // get reserves
        (uint256 nativeReserve, uint256 tokenReserve) = getReserves();
        // the native reserve is the balance of the contract minus the value sent
        nativeReserve = nativeReserve - msg.value;

        uint256 lpTotalSupply = liquidityToken.totalSupply();
        uint256 amountNative = msg.value;
        uint256 amountToken = amountToken_;

        if (lpTotalSupply == 0) {
            uint256 _amountProduct = Math.sqrt(amountNative * amountToken);
            liquidity = _amountProduct - MINIMUM_LIQUIDITY;
            // Set owner of the first MINIMUM_LIQUIDITY tokens to the zero address
            liquidityToken.mint(DEAD_ADDRESS, MINIMUM_LIQUIDITY);
            // Liquidity is initialized
            isInitialized = true;
        } else {
            if (nativeReserve == 0 || tokenReserve == 0)
                revert InvalidReserves();

            // Determine the amount of token required to add liquidity
            // according to the native amount sent
            amountToken = (amountNative * tokenReserve) / nativeReserve;
            uint256 currentKValue = _calculateKValue(
                nativeReserve,
                tokenReserve
            );

            if (amountToken_ < amountToken) {
                revert AmountOfTokensLessThanMinimumRequired(
                    amountToken_,
                    amountToken
                );
            }

            /**
             * @dev Calculates the liquidity amount based on the given amounts of native currency and token.
             * The liquidity amount is determined by taking the minimum of two calculations:
             * 1. (amountNative * lpTotalSupply) / _nativeReserve
             * 2. (amountToken * lpTotalSupply) / _tokenReserve
             */
            liquidity = Math.min(
                (amountNative * lpTotalSupply) / nativeReserve,
                (amountToken * lpTotalSupply) / tokenReserve
            );

            /**
             * @dev Updates the reserves and checks the liquidity ratio.
             * The new k value is calculated by multiplying the new token reserve by the new native reserve.
             * If the new k value is less than the current k value, the transaction is reverted.
             */
            uint256 newNativeReserve = nativeReserve + amountNative;
            uint256 newTokenReserve = tokenReserve + amountToken;
            uint256 newKValue = newTokenReserve * newNativeReserve;
            if (newKValue < currentKValue) {
                revert DecreasesK();
            }
        }

        // check if liquidity is greater than 0
        if (liquidity == 0) {
            revert InsufficientLiquidityMinted();
        }
        // mint liquidity tokens to the liquidity provider
        liquidityToken.mint(recipient, liquidity);

        // Only transfer the necessary amount of tokens
        _internalTransfer(sender, address(this), amountToken);

        _updatePrices();

        emit AddLiquidity(sender, recipient, liquidity, msg.value, amountToken);
    }

    /**
     * @dev Removes liquidity from the contract by transferring native currency and tokens back to the liquidity provider.
     * @param amount The amount of liquidity to be removed.
     * @param recipient The address of the recipient of the native currency and tokens.
     * @param deadline The deadline in unix time from the current timestamp for the transaction to occur.
     * @return nativeAmount The amount of native currency received.
     * @return tokenAmount The amount of tokens received.
     * @notice The liquidity provider must have sufficient liquidity balance.
     */
    function removeLiquidity(
        uint256 amount,
        address recipient,
        uint256 deadline
    )
        public
        nonReentrant
        ensureDeadline(deadline)
        returns (uint256 nativeAmount, uint256 tokenAmount)
    {
        address sender = _msgSender();
        if (!isInitialized) {
            revert ContractIsNotInitialized();
        }

        uint256 lpTokenBalance = liquidityToken.balanceOf(sender);

        if (lpTokenBalance == 0) {
            revert YouHaveNoLiquidity();
        }
        if (amount > lpTokenBalance) {
            revert InsufficientLiquidity();
        }

        (nativeAmount, tokenAmount) = getAmountsForLP(amount);

        liquidityToken.burnFrom(sender, amount);

        _transferNative(recipient, nativeAmount);
        super._transfer(address(this), recipient, tokenAmount);

        emit RemoveLiquidity(
            sender,
            recipient,
            amount,
            nativeAmount,
            tokenAmount
        );

        _updatePrices();
    }

    /**
     * @dev Swaps native currency to tokens.
     * @param minimumTokensOut The minimum amount of tokens to receive in the swap.
     * @param deadline The deadline in unix time from current timestamp for the swap to occur.
     */
    function swapNativeToToken(
        uint256 minimumTokensOut,
        uint256 deadline
    )
        public
        payable
        nonReentrant
        ensureDeadline(deadline)
        returns (uint256[] memory amounts)
    {
        (uint256 nativeReserve, uint256 tokenReserve) = getReserves();
        uint256 nativeIn = msg.value;
        address sender = _msgSender();

        nativeReserve = nativeReserve - nativeIn;

        (uint256 tokensBought, uint256 factoryFee, uint256 tradingFee) = _swap(
            nativeIn,
            minimumTokensOut,
            nativeReserve,
            tokenReserve
        );

        accruedNativeTradingFees += tradingFee;
        _handleFactoryFees(factoryFee, true);

        _checkMaxWallet(sender, tokensBought);
        super._transfer(address(this), sender, tokensBought);

        _updatePrices();
        amounts = new uint256[](2);
        amounts[0] = nativeIn;
        amounts[1] = tokensBought;
        emit Swap(sender, 0, nativeIn, tokensBought, 0, false);
    }

    /**
     * @dev Swaps a specified amount of tokens for native currency.
     * @param tokensSold The amount of tokens to be sold.
     * @param minimumNativeOut The minimum amount of native currency expected to be received.
     * @param deadline The deadline in unix time from current timestamp for the swap to occur.
     */
    function swapTokenToNative(
        uint256 tokensSold,
        uint256 minimumNativeOut,
        uint256 deadline
    )
        public
        nonReentrant
        ensureDeadline(deadline)
        returns (uint256[] memory amounts)
    {
        (uint256 nativeReserve, uint256 tokenReserve) = getReserves();

        address sender = _msgSender();

        (uint256 nativeBought, uint256 factoryFee, uint256 tradingFee) = _swap(
            tokensSold,
            minimumNativeOut,
            tokenReserve,
            nativeReserve
        );

        accruedTokenTradingFees += tradingFee;
        _handleFactoryFees(factoryFee, false);

        _internalTransfer(sender, address(this), tokensSold);
        _transferNative(sender, nativeBought);

        _updatePrices();
        amounts = new uint256[](2);
        amounts[0] = tokensSold;
        amounts[1] = nativeBought;
        emit Swap(sender, tokensSold, 0, 0, nativeBought, false);
    }

    /**
     * @dev Executes a flash swap transaction.
     * @param recipient The address of the recipient of the flash swap.
     * @param amountNativeOut The amount of native currency to be sent to the recipient.
     * @param amountTokenOut The amount of tokens to be sent to the recipient.
     * @param data Additional data to be passed to the recipient.
     */
    function flashSwap(
        address recipient,
        uint256 amountNativeOut,
        uint256 amountTokenOut,
        bytes calldata data
    ) external nonReentrant preventAutoSwap {
        if (!isInitialized) revert ContractIsNotInitialized();
        if (!tradingEnabled) revert SwapNotEnabled();

        if (amountNativeOut == 0 && amountTokenOut == 0)
            revert AmountMustBeGreaterThanZero();

        if (recipient == address(0) || recipient == address(this))
            revert InvalidRecipient();

        (uint256 nativeReserve, uint256 tokenReserve) = getReserves();

        if (amountNativeOut > nativeReserve || amountTokenOut > tokenReserve)
            revert InsufficientLiquidity();

        address sender = _msgSender();

        if (amountNativeOut > 0) {
            // Sending native currency
            _transferNative(recipient, amountNativeOut);
        }
        if (amountTokenOut > 0) {
            // Sending token
            _checkMaxWallet(recipient, amountTokenOut);
            super._transfer(address(this), recipient, amountTokenOut);
        }

        IBIFKN314CALLEE(recipient).BIFKN314CALL(
            sender,
            amountNativeOut,
            amountTokenOut,
            data
        );

        (uint256 nativeReserveAfter, uint256 tokenReserveAfter) = getReserves();

        uint amountNativeIn = nativeReserveAfter > nativeReserve
            ? nativeReserveAfter - nativeReserve
            : 0;
        uint amountTokenIn = tokenReserveAfter > tokenReserve
            ? tokenReserveAfter - tokenReserve
            : 0;

        if (amountNativeIn == 0 && amountTokenIn == 0) {
            revert TokenRepaymentFailed();
        }

        {
            uint256 totalFees = FLASHSWAP_FEE_RATE + tradingFeeRate;

            uint256 nativeReserveAdjusted = (nativeReserveAfter *
                SCALE_FACTOR) - (amountNativeIn * totalFees);
            uint256 tokenReserveAdjusted = (tokenReserveAfter * SCALE_FACTOR) -
                (amountTokenIn * totalFees);

            if (
                nativeReserveAdjusted * tokenReserveAdjusted <
                nativeReserve * tokenReserve * (SCALE_FACTOR ** 2)
            ) {
                revert DecreasesK();
            }
        }

        accruedNativeTradingFees += _calculateTradingFee(amountNativeIn);
        accruedTokenTradingFees += _calculateTradingFee(amountTokenIn);

        _handleFactoryFees(_calculateFactoryFee(amountNativeIn), true);
        _handleFactoryFees(_calculateFactoryFee(amountTokenIn), false);

        _updatePrices();

        emit Swap(
            sender,
            amountTokenIn,
            amountNativeIn,
            amountTokenOut,
            amountNativeOut,
            true
        );
    }

    /**
     * @dev Calculates the amount of output tokens based on the input amount and reserves.
     * This accounts for all fees including the factory fee, trading fee, and base swap rate.
     * @param inputAmount The amount of input tokens.
     * @param inputReserve The amount of input tokens in the reserve.
     * @param outputReserve The amount of output tokens in the reserve.
     * @return outputAmount The amount of output tokens.
     * @return factoryFee The amount of factory fee.
     * @return tradingFee The amount of trading fee.
     */
    function getAmountOut(
        uint256 inputAmount,
        uint256 inputReserve,
        uint256 outputReserve
    )
        public
        view
        returns (uint256 outputAmount, uint256 factoryFee, uint256 tradingFee)
    {
        // Scale by 1e4 to avoid rounding errors
        // Since the SCALE_FACTOR is 1e4, the precision total is 1e8
        // This strikes a good balance between risk of overflow and precision
        uint256 precision = 1e4;
        uint256 feeFactor = SCALE_FACTOR - (BASE_SWAP_RATE + tradingFeeRate);
        uint256 inputAmountScaled = inputAmount * precision;
        // if reserves are greater than 0
        if (inputReserve > 0 && outputReserve > 0) {
            factoryFee = _calculateFactoryFee(inputAmountScaled) / precision;
            tradingFee = _calculateTradingFee(inputAmountScaled) / precision;
            uint256 inputAmountWithFee = inputAmountScaled * feeFactor;
            uint256 numerator = inputAmountWithFee * outputReserve;
            uint256 denominator = (inputReserve * SCALE_FACTOR * precision) +
                inputAmountWithFee;
            unchecked {
                outputAmount = numerator / denominator;
            }
        } else {
            revert InvalidReserves();
        }
    }

    /**
     * @dev Calculates the input amount and factory fee based on the output amount, output reserve, and input reserve.
     * This accounts for all fees including the factory fee, trading fee, and base swap rate.
     * @param outputAmount The desired output amount.
     * @param outputReserve The current output reserve.
     * @param inputReserve The current input reserve.
     * @return inputAmount The calculated input amount.
     */
    function getAmountIn(
        uint256 outputAmount,
        uint256 inputReserve,
        uint256 outputReserve
    ) public view returns (uint256 inputAmount) {
        // Scale by 1e4 to avoid rounding errors
        // Since the SCALE_FACTOR is 1e4, the precision total is 1e8
        // This strikes a good balance between risk of overflow and precision
        uint256 precision = 1e4;
        uint256 feeFactor = SCALE_FACTOR - (BASE_SWAP_RATE + tradingFeeRate);
        feeFactor = feeFactor * precision;
        // Ensure reserves are greater than 0
        if (outputReserve > 0 && inputReserve > 0) {
            uint256 numerator = inputReserve *
                outputAmount *
                SCALE_FACTOR *
                precision;
            uint256 denominator = (outputReserve - outputAmount) * feeFactor;
            unchecked {
                inputAmount = (numerator / denominator) + 1;
            }
        } else {
            revert InvalidReserves();
        }
    }

    /**
     * @dev Returns the number of tokens held by the contract.
     * @return tokenBalance The token balance of the contract.
     */
    function getTokensInContract() public view returns (uint256 tokenBalance) {
        tokenBalance = super.balanceOf(address(this));
    }

    /**
     * @dev Returns the reserves of the contract.
     * If the fees are greater than the reserves, the function returns 0 for the respective reserve.
     * @return amountNative The native reserve balance.
     * @return amountToken The token reserve balance.
     */
    function getReserves()
        public
        view
        returns (uint256 amountNative, uint256 amountToken)
    {
        uint256 totalNative = address(this).balance;
        uint256 totalNativeFees = accruedNativeTradingFees +
            accruedNativeFactoryFees;
        uint256 totalToken = getTokensInContract();
        uint256 totalTokenFees = accruedTokenTradingFees +
            accruedTokenFactoryFees;

        amountNative = totalNative >= totalNativeFees
            ? totalNative - totalNativeFees
            : 0;
        amountToken = totalToken >= totalTokenFees
            ? totalToken - totalTokenFees
            : 0;
    }

    /**
     * @dev Gets the amount of tokens held by the liquidity provider.
     * @param amount The amount of liquidity tokens to be converted.
     * @return nativeAmount The amount of native currency held by the liquidity provider.
     * @return tokenAmount The amount of tokens held by the liquidity provider.
     */
    function getAmountsForLP(
        uint256 amount
    ) public view returns (uint256 nativeAmount, uint256 tokenAmount) {
        if (amount == 0) revert AmountMustBeGreaterThanZero();
        (uint256 nativeReserve, uint256 tokenReserve) = getReserves();

        if (nativeReserve == 0 || tokenReserve == 0) revert InvalidReserves();

        uint256 totalLPSupply = liquidityToken.totalSupply();
        if (totalLPSupply == 0) revert InsufficientLiquidity();

        nativeAmount = (amount * nativeReserve) / totalLPSupply;
        tokenAmount = (amount * tokenReserve) / totalLPSupply;

        if (nativeAmount == 0 || tokenAmount == 0)
            revert InsufficientLiquidity();
    }

    /**
     * @dev Enables trading by setting the `tradingEnabled` flag to true.
     * Can only be called by the contract owner.
     * Once trading is enabled, it cannot be disabled.
     */
    function setTradingEnabled() public onlyOwner {
        tradingEnabled = true;
    }

    /**
     * @dev Sets the fee collector address.
     * @param feeCollector_ The address of the fee collector.
     * @notice Only the contract owner can call this function.
     * @notice The fee collector address cannot be set to the zero address.
     */
    function setFeeCollector(address feeCollector_) external onlyOwner {
        if (feeCollector_ == address(0)) revert InvalidAddress();
        feeCollector = feeCollector_;
    }

    /**
     * @dev Sets the fee rate for trading.
     * @param feeRate The new fee rate to be set.
     * Requirements:
     * - `feeRate` must be less than or equal to 50 (5%).
     * Only the contract owner can call this function.
     */
    function setTradingFeeRate(uint256 feeRate) public onlyOwner {
        if (feeRate > MAX_FEE_RATE) revert InvalidFeeRate(); // 5%
        tradingFeeRate = feeRate;
    }

    /**
     * @dev Sets the maximum wallet percentage.
     * @param maxWalletPercent_ The maximum wallet percentage to be set.
     * Requirements:
     * - `maxWalletPercent_` must be less than or equal to 10000 (100%)
     * and greater than 0 if maxWalletEnabled is true.
     * Only the contract owner can call this function.
     */
    function setMaxWalletPercent(uint256 maxWalletPercent_) public onlyOwner {
        if (maxWalletPercent_ > 10000) revert InvalidMaxWalletPercent(); // 100%
        if (maxWalletEnabled && maxWalletPercent_ == 0)
            revert InvalidMaxWalletPercent();
        maxWalletPercent = maxWalletPercent_;
    }

    /**
     * @dev Enables or disables the maximum wallet limit.
     * @param enabled The boolean value to set the maximum wallet limit.
     * Requirements:
     * - Only the contract owner can call this function.
     */
    function setMaxWalletEnabled(bool enabled) public onlyOwner {
        if (enabled && maxWalletPercent == 0) revert InvalidMaxWalletPercent();
        maxWalletEnabled = enabled;
    }

    /**
     * @dev Sets the metadata URI for the token.
     * @param newURI The new metadata URI to be set.
     * Requirements:
     * - Only the contract owner can call this function.
     */
    function setMetadataURI(string memory newURI) public onlyOwner {
        metadataURI = newURI;
    }

    /**
     * @dev Sets the maximum wallet exemption status for a given address.
     * @param addressToChange The address for which the maximum wallet exemption status is to be set.
     * @param isExempt A boolean value indicating whether the address should be exempt from the maximum wallet limit.
     * Only the contract owner can call this function.
     * Requirements:
     * - The address to change cannot be the zero address, the contract address, or the dead address.
     * @notice If the address to change is the zero address, the contract address, or the dead address, the transaction will revert.
     */
    function setMaxWalletExempt(
        address addressToChange,
        bool isExempt
    ) public onlyOwner {
        if (
            !isExempt &&
            (addressToChange == address(0) ||
                addressToChange == address(this) ||
                addressToChange == DEAD_ADDRESS)
        ) revert InvalidAddress();
        isMaxWalletExempt[addressToChange] = isExempt;
    }

    /**
     * @dev Allows the fee collector to claim accrued trading fees.
     * The function transfers the accrued native currency and token trading fees to the fee collector.
     * The accrued amounts are reset to zero after the transfer.
     * Emits a `FeesCollected` event with the fee collector's address, accrued native amount, and accrued token amount.
     *
     * Requirements:
     * - The caller must be the fee collector.
     */
    function claimFees() external onlyFeeCollector {
        uint256 accruedNativeAmount = accruedNativeTradingFees;
        uint256 accruedTokenAmount = accruedTokenTradingFees;
        address sender = _msgSender();

        if (accruedNativeAmount == 0 && accruedTokenAmount == 0)
            revert NoFeesToClaim();

        accruedNativeTradingFees = 0;

        // If the accrued token amount is greater than the balance of the contract
        // set the accrued token amount to the balance of the contract
        if (accruedTokenAmount > getTokensInContract())
            accruedTokenAmount = getTokensInContract();

        accruedTokenTradingFees = 0;

        _transferNative(sender, accruedNativeAmount);
        super._transfer(address(this), sender, accruedTokenAmount);

        emit FeesCollected(sender, accruedNativeAmount, accruedTokenAmount);
    }

    /**
     * @dev Transfers the ownership of the contract to a new address.
     * Can only be called by the current owner.
     *
     * @param newOwner The address of the new owner.
     */
    function transferOwnership(address newOwner) public onlyOwner {
        if (newOwner == address(0)) revert InvalidOwner();

        _transferOwnership(newOwner);
    }

    /**
     * @dev Allows the current owner to renounce their ownership.
     * It sets the owner address to 0, effectively removing the ownership.
     */
    function renounceOwnership() external onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers the ownership of the contract to a new address.
     * Can only be called by the current owner.
     *
     * @param newOwner The address of the new owner.
     * @notice Emits an {OwnershipTransferred} event.
     */
    function _transferOwnership(address newOwner) internal {
        address oldOwner = owner;
        owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }

    /**
     * @dev Calculates the product of two input values.
     * @param reserve1 The first input value.
     * @param reserve2 The second input value.
     * @return kValue_ The product of the two input values.
     */
    function _calculateKValue(
        uint256 reserve1,
        uint256 reserve2
    ) internal pure returns (uint256 kValue_) {
        kValue_ = reserve1 * reserve2;
    }

    /**
     * @dev Internal function to calculate the trading fee for a given amount.
     * @param amount The amount to apply the fee to.
     * @return amountForFee The amount to be deducted as a trading fee.
     * @notice If the amount is zero, the transaction will revert.
     * @notice If the trading fee rate is zero, the function will return zero.
     * @notice If the trading fee rate is 500, the function will return 5% of the amount.
     */
    function _calculateTradingFee(
        uint256 amount
    ) internal view returns (uint256 amountForFee) {
        // If the trading fee rate is 0, return 0
        if (tradingFeeRate == 0) amountForFee = 0;
        else {
            amountForFee = (amount * tradingFeeRate) / SCALE_FACTOR;
        }
    }

    /**
     * @dev Calculates the factory fee based on the input amount.
     * @param inputAmount The input amount for which the factory fee needs to be calculated.
     * @return amountForFee The amount to be deducted as a factory fee.
     * @notice If the input amount is zero, the transaction will revert.
     * @notice If the factory contract is not set, the function will return zero.
     */
    function _calculateFactoryFee(
        uint256 inputAmount
    ) internal view returns (uint256 amountForFee) {
        if (address(factory) == address(0)) {
            amountForFee = 0;
        } else {
            amountForFee = (inputAmount * factory.feeRate()) / SCALE_FACTOR;
        }
    }

    /**
     * @dev Checks if the recipient's wallet balance exceeds the maximum allowed amount.
     * @param recipient The address of the recipient.
     * @param amount The amount to be transferred.
     * @notice If the max wallet limit is exceeded, the transaction will revert.
     */
    function _checkMaxWallet(address recipient, uint256 amount) internal view {
        if (!maxWalletEnabled) return; // Skip if max wallet is not enabled
        // Only apply the max wallet check if the recipient is not (this) contract, address(0), or the dead address
        // and if the recipient is not exempt from the max wallet limit
        if (
            recipient == address(this) ||
            recipient == address(0) ||
            recipient == DEAD_ADDRESS ||
            isMaxWalletExempt[recipient]
        ) {
            return;
        }

        uint256 maxWalletAmount = ((totalSupply() * maxWalletPercent) / 10000);
        if (balanceOf(recipient) + amount > maxWalletAmount) {
            revert MaxWalletAmountExceeded();
        }
    }

    /**
     * @dev Internal function to check for swap errors.
     * @param tokensSold The number of tokens sold in the swap.
     * @param nativeReserve The native reserve balance.
     * @param tokenReserve The token reserve balance.
     * @notice If the contract is not initialized, the transaction will revert.
     * @notice If the reserves are invalid, the transaction will revert.
     * @notice If the swap is not enabled, the transaction will revert.
     * @notice If the amount of tokens sold is zero, the transaction will revert.
     */
    function _checkForSwapErrors(
        uint256 tokensSold,
        uint256 nativeReserve,
        uint256 tokenReserve
    ) internal view {
        if (!isInitialized) revert ContractIsNotInitialized();
        if (!tradingEnabled) revert SwapNotEnabled();
        if (tokensSold == 0) {
            revert AmountMustBeGreaterThanZero();
        }
        if (nativeReserve == 0 || tokenReserve == 0) revert InvalidReserves();
    }

    /**
     * @dev Performs a swap operation between two reserves.
     * @param amountIn The amount of tokens being swapped in.
     * @param minimumAmountOut The minimum amount of tokens expected to be received.
     * @param reserveIn The reserve of the input token.
     * @param reserveOut The reserve of the output token.
     * @return amountOut The amount of tokens received after the swap.
     * @return factoryFee The fee charged by the factory for the swap.
     * @return tradingFee The fee charged for the swap.
     */
    function _swap(
        uint256 amountIn,
        uint256 minimumAmountOut,
        uint256 reserveIn,
        uint256 reserveOut
    )
        internal
        view
        returns (uint256 amountOut, uint256 factoryFee, uint256 tradingFee)
    {
        _checkForSwapErrors(amountIn, reserveIn, reserveOut);

        uint256 currentKValue = _calculateKValue(reserveIn, reserveOut);

        (amountOut, factoryFee, tradingFee) = getAmountOut(
            amountIn,
            reserveIn,
            reserveOut
        );

        if (amountOut == 0) revert BoughtAmountTooLow();
        if (amountOut < minimumAmountOut) revert SlippageToleranceExceeded();

        uint256 newReserveIn = reserveIn + (amountIn - tradingFee - factoryFee);

        uint256 newReserveOut = reserveOut - amountOut;

        if (_calculateKValue(newReserveIn, newReserveOut) < currentKValue)
            revert DecreasesK();
    }

    /**
     * @dev Calculates the cumulative prices based on the provided native and token reserves.
     */
    function _updatePrices() private {
        (uint256 nativeReserve, uint256 tokenReserve) = getReserves();

        if (nativeReserve == 0 || tokenReserve == 0) revert InvalidReserves();

        uint32 blockTimestamp = uint32(block.timestamp % 2 ** 32);
        uint32 timeElapsed = blockTimestamp - blockTimestampLast; // Overflow is desired

        if (timeElapsed > 0 && nativeReserve != 0 && tokenReserve != 0) {
            // Simulate fixed-point precision using a scaling factor
            uint256 scalingFactor = 2 ** 112;

            // Calculate price ratios with scaling to simulate UQ112x112 precision
            // Reflects the price of token in native currency
            uint256 price0Ratio = (nativeReserve * scalingFactor) /
                tokenReserve;
            // Reflects the price of native currency in token
            uint256 price1Ratio = (tokenReserve * scalingFactor) /
                nativeReserve;

            // Update cumulative prices
            price0CumulativeLast += price0Ratio * timeElapsed;
            price1CumulativeLast += price1Ratio * timeElapsed;

            // Update last block timestamp
            blockTimestampLast = blockTimestamp;
        }

        emit PricesUpdated(
            price0CumulativeLast,
            price1CumulativeLast,
            blockTimestampLast
        );
    }

    /**
     * @dev Accrues fees to the contract.
     * @param factoryFee The amount of fees to be accrued.
     * @param native A boolean value indicating whether the fee is in native currency or not.
     */
    function _handleFactoryFees(uint256 factoryFee, bool native) internal {
        // Check if the factory contract is set
        if (address(factory) != address(0)) {
            address feeTo = factory.feeTo();
            uint256 distributionThreshold = factory.feeDistributionThreshold();

            // Accrue fees and distribute if threshold is reached
            if (feeTo != address(0)) {
                if (native) {
                    accruedNativeFactoryFees += factoryFee;
                } else {
                    accruedTokenFactoryFees += factoryFee;
                }

                _distributeFees(feeTo, distributionThreshold);
            }
        }
    }

    /**
     * @dev Distributes fees to a specified address if the distribution threshold is reached.
     * @param feeTo The address to which the fees will be distributed.
     * @param distributionThreshold The threshold at which fees will be distributed.
     */
    function _distributeFees(
        address feeTo,
        uint256 distributionThreshold
    ) internal {
        uint256 nativeFees = accruedNativeFactoryFees;
        uint256 tokenFees = accruedTokenFactoryFees;
        bool nativeDistributed = false;
        bool tokenDistributed = false;

        // Only distribute fees if either the native or token fees are greater than 0
        if (nativeFees == 0 && tokenFees == 0) return;

        // Distribute native fees if threshold is reached
        if (nativeFees > 0 && nativeFees >= distributionThreshold) {
            accruedNativeFactoryFees = 0;
            nativeDistributed = true;
        }

        // Distribute token fees if threshold is reached
        if (tokenFees > 0) {
            (uint256 nativeReserve, uint256 tokenReserve) = getReserves();

            uint256 nativeAmount = (tokenFees * nativeReserve) / tokenReserve;

            if (nativeAmount >= distributionThreshold) {
                if (tokenFees > getTokensInContract()) {
                    tokenFees = getTokensInContract();
                }
                accruedTokenFactoryFees = 0;
                tokenDistributed = true;
            }
        }

        if (nativeDistributed) _transferNative(feeTo, nativeFees);
        if (tokenDistributed) super._transfer(address(this), feeTo, tokenFees);

        // Emit event if fees are distributed
        if (nativeDistributed || tokenDistributed)
            emit FeesDistributed(feeTo, nativeFees, tokenFees);
    }

    /**
     * @dev Internal function to transfer native currency to a specified address.
     * @param to The address to transfer the native currency to.
     * @param amount The amount of native currency to transfer.
     * @notice If the transfer fails, the transaction will revert.
     */
    function _transferNative(address to, uint256 amount) internal {
        if (amount == 0) return;
        if (to == address(0)) revert InvalidAddress();

        if (amount > address(this).balance) {
            amount = address(this).balance;
        }
        (bool success, ) = payable(to).call{value: amount}("");
        if (!success) revert FailedToSendNativeCurrency();
    }

    /**
     * @dev Calculates the fee based on the given amount.
     * @param amount The amount for which the fee needs to be calculated.
     * @return flashswapFee The calculated fee.
     */
    function _calculateFlashswapFee(
        uint256 amount
    ) internal pure returns (uint256 flashswapFee) {
        flashswapFee = (amount * FLASHSWAP_FEE_RATE) / SCALE_FACTOR; // Fee calculation
    }

    /**
     * @dev Calculates the minimum amount out with slippage for an auto swap.
     * @param amount The input amount.
     * @param isNative A boolean indicating whether the input is in the native token or not.
     * @return amountOutMin The minimum amount out with slippage.
     */
    function _calculateAutoSwapSlippage(
        uint256 amount,
        bool isNative
    ) internal view returns (uint256 amountOutMin) {
        (uint256 nativeReserve, uint256 tokenReserve) = getReserves();
        (uint256 amountOut, , ) = getAmountOut(
            amount,
            isNative ? nativeReserve : tokenReserve,
            isNative ? tokenReserve : nativeReserve
        );
        amountOutMin = amountOut - (amountOut / 20); // 5% slippage
    }

    // Function to receive native
    /**
     * @dev Fallback function to receive native currency.
     * It calls the `swapNativeToToken` function with a minimum token out amount of 0 (i.e. infinite slippage).
     */
    receive() external payable {
        if (!_autoSwapIsPrevented()) {
            swapNativeToToken(
                _calculateAutoSwapSlippage(msg.value, true),
                block.timestamp + 3 minutes
            );
        }
    }
}

File 3 of 16 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Muldiv operation overflow.
     */
    error MathOverflowedMulDiv();

    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            return a / b;
        }

        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
     * denominator == 0.
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
     * Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0 = x * y; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            if (denominator <= prod1) {
                revert MathOverflowedMulDiv();
            }

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.

            uint256 twos = denominator & (0 - denominator);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
            // works in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
        }
    }

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}

File 4 of 16 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    uint256 private _status;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _status = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}

File 5 of 16 : IERC314Events.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

interface IERC314Events {
    event AddLiquidity(
        address indexed provider,
        address indexed toAddress,
        uint256 liquidityMinted,
        uint256 nativeAmount,
        uint256 tokenAmount
    );
    event RemoveLiquidity(
        address indexed provider,
        address indexed toAddress,
        uint256 liquidityBurned,
        uint256 nativeAmount,
        uint256 tokenAmount
    );
    event Swap(
        address indexed sender,
        uint256 amountTokenIn,
        uint256 amountNativeIn,
        uint256 amountTokenOut,
        uint256 amountNativeOut,
        bool flashSwap
    );
    event PricesUpdated(
        uint256 tokenPriceInNative,
        uint256 nativePriceInToken,
        uint32 blockTimestampLast
    );
    event OwnershipTransferred(
        address indexed previousOwner,
        address indexed newOwner
    );
    event FeesCollected(
        address indexed recipient,
        uint256 amountNative,
        uint256 amountToken
    );
    event FeesDistributed(
        address indexed feeTo,
        uint256 nativeAmount,
        uint256 tokenAmount
    );
}

File 6 of 16 : IERC314Errors.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

interface IERC314Errors {
    error AmountOfTokensLessThanMinimumRequired(
        uint256 amount,
        uint256 minimumAmount
    );
    error AmountMustBeGreaterThanZero();
    error YouHaveNoLiquidity();
    error InsufficientLiquidity();
    error InvalidReserves();
    error ContractIsNotInitialized();
    error InsufficientLiquidityMinted();
    error SwapNotEnabled();
    error DecreasesK();
    error TransactionExpired();
    error SlippageToleranceExceeded();
    error InvalidRecipient();
    error FailedToSendNativeCurrency();
    error NativeRepaymentFailed();
    error TokenRepaymentFailed();
    error Unauthorized(address sender);
    error SupplyAlreadyMinted();
    error InvalidOwner();
    error InvalidAddress();
    error InvalidFeeRate();
    error BoughtAmountTooLow();
    error NoFeesToClaim();
    error InvalidMaxWalletPercent();
    error MaxWalletAmountExceeded();
    error AlreadyInitialized();
}

File 7 of 16 : IBIFKN314CALLEE.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

interface IBIFKN314CALLEE {
    function BIFKN314CALL(
        address sender,
        uint256 amount0,
        uint256 amount1,
        bytes calldata data
    ) external;
}

File 8 of 16 : IBIFKN314Factory.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

interface IBIFKN314Factory {
    function feeTo() external view returns (address);

    function feeRate() external view returns (uint256);

    function feeToSetter() external view returns (address);

    function feeDistributionThreshold() external view returns (uint256);

    function deployBIFKN314(
        string memory tokenName,
        string memory tokenSymbol,
        uint256 totalSupply,
        address owner_,
        uint256 tradingFee,
        uint256 maxWalletPercent,
        string memory metadataURI
    )
        external
        payable
        returns (address contractAddress, address liquidityTokenAddress);

    function deployBIFKN314WithSalt(
        string memory tokenName,
        string memory tokenSymbol,
        uint256 totalSupply,
        address owner_,
        uint256 tradingFee,
        uint256 maxWalletPercent,
        string memory metadataURI,
        bytes32 salt
    )
        external
        payable
        returns (address contractAddress, address liquidityTokenAddress);

    function getDeterministicAddress(
        bytes32 salt
    ) external view returns (address clone);

    function calculateDeterministicAddress(
        uint256 occur,
        address desiredPrefix,
        uint8 bytesDesired,
        bytes32 startSalt
    ) external view returns (bytes32 salt);

    event TokenCreated(
        address indexed deployer,
        string name,
        string symbol,
        address ammAddress,
        address lpAddress,
        uint256 allAMMLength
    );

    event TokenRemoved(
        address indexed deployer,
        string name,
        string symbol,
        address ammAddress,
        address lpAddress,
        uint256 allAMMLength
    );

    event FeeDistributed(address indexed feeTo, uint256 nativeAmount);

    error InvalidAddress();
    error NameMustNotBeEmpty();
    error SymbolMustNotBeEmpty();
    error NameTooLong();
    error SymbolTooLong();
    error OnlyFeeToSetter(address sender);
    error InvalidTradingFee();
    error SupplyMustBeGreaterThanZero();
    error InsufficientDeploymentFee();
    error InvalidFeeRate();
    error InvalidMaxWalletPercent();
    error DistributionFailed();
    error ImplementationAlreadyDeployed();
    error PreviousFactoryNotSet();
    error InvalidRange();
    error OutOfBounds();
}

File 9 of 16 : PreventAutoSwap.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.20;

/**
 * @dev Contract module that helps prevent automatic swapping within a function call
 * for specific callers, allowing for finer control over when swapping should be prevented.
 *
 * This version uses a mapping to track the prevention status for each caller,
 * making it context-sensitive and allowing for certain operations to not affect others.
 */
abstract contract PreventAutoSwap {
    mapping(address => bool) private _autoSwapPreventedFor;

    /**
     * @dev Thrown when an operation tries to perform an auto-swap and it is prevented for the caller.
     */
    error AutoSwapPrevented();

    /**
     * @dev Prevents auto-swap for the caller of the function this modifier is applied to.
     * This approach allows differentiating between various operations and callers,
     * giving more control over the swapping mechanism.
     */
    modifier preventAutoSwap() {
        _preventAutoSwapBefore();
        _;
        _preventAutoSwapAfter();
    }

    /**
     * @dev Prevents automatic swapping before executing a transaction.
     * If the msg.sender has already prevented auto swapping, it reverts with an `AutoSwapPrevented` error.
     * Otherwise, it marks the transaction origin as prevented for auto swapping.
     */
    function _preventAutoSwapBefore() private {
        if (_autoSwapPreventedFor[msg.sender]) {
            revert AutoSwapPrevented();
        }
        _autoSwapPreventedFor[msg.sender] = true;
    }

    /**
     * @dev Internal function to prevent auto swap after a transaction.
     * @notice This function sets the `_autoSwapPreventedFor` mapping value for the `msg.sender` address to `false`.
     * @notice Auto swap refers to an automatic swapping of tokens that may occur during a transaction.
     * @notice By calling this function, the auto swap is prevented for the `msg.sender` address.
     * @notice This function is private and can only be called from within the contract.
     */
    function _preventAutoSwapAfter() private {
        _autoSwapPreventedFor[msg.sender] = false;
    }

    /**
     * @dev Returns true if auto swap is currently prevented for the caller.
     */
    function _autoSwapIsPrevented() internal view returns (bool) {
        return _autoSwapPreventedFor[msg.sender];
    }
}

File 10 of 16 : BIFKN314LP.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.20;

import "./BIFKNERC20.sol";

/**
 * @title BIFKN314LP
 * @dev Implementation of the liquidity provider (LP) token for the BIFKN314 AMM pool.
 */
contract BIFKN314LP is BIFKNERC20 {
    /**
     * @dev The address of the Automated Market Maker (AMM) contract.
     */
    address public immutable ammAddress;

    error Unauthorized(address sender);

    /**
     * @dev Modifier that allows only the owner (amm) to call the function.
     * If the caller is not the owner, it will revert with an `OnlyOwnerError` error.
     */
    modifier onlyOwner() {
        if (_msgSender() != ammAddress) revert Unauthorized(_msgSender());
        _;
    }

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor() BIFKNERC20() {
        ammAddress = _msgSender();
    }

    /**
     * @dev Initializes the contract with the given name and symbol.
     *
     * This function is called by the contract owner to initialize the contract.
     * It sets the name and symbol of the contract by calling the `initialize` function
     * of the parent contract.
     *
     * @param tokenName The name of the contract.
     * @param tokenSymbol The symbol of the contract.
     */
    function initialize(
        string memory tokenName,
        string memory tokenSymbol
    ) public override onlyOwner {
        super.initialize(tokenName, tokenSymbol);
    }

    /**
     * @dev Function to mint tokens
     *
     * Requirements:
     * - the caller must be the BIFKN314 contract.
     *
     * @param account The address that will receive the minted tokens.
     * @param amount The amount of tokens to mint.
     */
    function mint(address account, uint256 amount) public onlyOwner {
        super._mint(account, amount);
    }
}

File 11 of 16 : BIFKNERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.20;

import "./ERC20.sol";

/**
 * @title BIFKNERC20
 * @dev This contract represents the BIFKNERC20 token.
 */
contract BIFKNERC20 is ERC20 {
    /**
     * @dev The `DOMAIN_SEPARATOR` is a unique identifier for the contract domain.
     * It is used to prevent replay attacks and to ensure that the contract is interacting with the correct domain.
     */
    bytes32 public DOMAIN_SEPARATOR;

    /**
     * @dev The hash of the permit type used in the EIP-2612 permit function.
     */
    bytes32 public constant PERMIT_TYPEHASH =
        0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;

    /**
     * @dev A mapping that stores the nonces for each address.
     * Nonces are used to prevent replay attacks in certain operations.
     * The key of the mapping is the address and the value is the nonce.
     */
    mapping(address => uint256) public nonces;

    /**
     * @dev Error indicating that the name and symbol must not be empty.
     */
    error NameAndSymbolMustNotBeEmpty();

    /**
     * @dev Error indicating that the name and symbol of the ERC20 token have already been set.
     */
    error NameAndSymbolAlreadySet();

    /**
     * @dev Error indicating that the signature has expired for ERC2612.
     * @param deadline The timestamp representing the expiration deadline.
     */
    error ERC2612ExpiredSignature(uint256 deadline);
    /**
     * @dev Error indicating that the signer is invalid.
     * @param signer The address of the invalid signer.
     * @param owner The address of the token owner.
     */
    error ERC2612InvalidSigner(address signer, address owner);

    /**
     * @dev Constructor function for the BIFKNERC20 contract.
     * It initializes the ERC20 contract and the EIP712 contract.
     * It also sets the DOMAIN_SEPARATOR variable using the _domainSeparatorV4 function.
     */
    constructor() ERC20() {}

    /**
     * @dev Initializes the ERC20 token with the given name and symbol.
     * @param tokenName The name of the token.
     * @param tokenSymbol The symbol of the token.
     */
    function initialize(
        string memory tokenName,
        string memory tokenSymbol
    ) public virtual {
        if (bytes(tokenName).length == 0 || bytes(tokenSymbol).length == 0) {
            revert NameAndSymbolMustNotBeEmpty();
        }
        if (bytes(_name).length != 0 || bytes(_symbol).length != 0) {
            revert NameAndSymbolAlreadySet();
        }
        _name = tokenName;
        _symbol = tokenSymbol;

        DOMAIN_SEPARATOR = keccak256(
            abi.encode(
                keccak256(
                    "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
                ),
                keccak256(bytes(_name)),
                keccak256(bytes("1")),
                block.chainid,
                address(this)
            )
        );
    }

    /**
     * @dev Allows `owner` to approve `spender` to spend `value` tokens on their behalf using a signed permit.
     * @param owner The address of the token owner.
     * @param spender The address of the spender.
     * @param value The amount of tokens to be approved.
     * @param deadline The deadline timestamp for the permit.
     * @param v The recovery id of the permit signature.
     * @param r The r value of the permit signature.
     * @param s The s value of the permit signature.
     * Requirements:
     * - The permit must not be expired (deadline not reached).
     * - The permit signature must be valid.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external {
        if (deadline < block.timestamp) {
            revert ERC2612ExpiredSignature(deadline);
        }
        bytes32 digest = keccak256(
            abi.encodePacked(
                "\x19\x01",
                DOMAIN_SEPARATOR,
                keccak256(
                    abi.encode(
                        PERMIT_TYPEHASH,
                        owner,
                        spender,
                        value,
                        nonces[owner]++,
                        deadline
                    )
                )
            )
        );
        address recoveredAddress = ecrecover(digest, v, r, s);
        if (recoveredAddress == address(0) || recoveredAddress != owner) {
            revert ERC2612InvalidSigner(recoveredAddress, owner);
        }

        _approve(owner, spender, value);
    }

    /**
     * @dev Burns a specific amount of tokens from the caller's balance.
     * @param value The amount of tokens to be burned.
     */
    function burn(uint256 value) public virtual {
        _burn(_msgSender(), value);
    }

    /**
     * @dev Burns a specific amount of tokens from the specified account.
     *
     * Requirements:
     * - The caller must have an allowance for `account`'s tokens of at least `value`.
     *
     * Emits a {Transfer} event with `from` set to `account`.
     */
    function burnFrom(address account, uint256 value) public virtual {
        _spendAllowance(account, _msgSender(), value);
        _burn(account, value);
    }
}

File 12 of 16 : ERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)

pragma solidity 0.8.20;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";
import {IERC20Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.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 internal _name;
    string internal _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() {}

    /**
     * @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);
            }
        }
    }
}

File 13 of 16 : draft-IERC6093.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;

/**
 * @dev Standard ERC20 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
 */
interface IERC20Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC20InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC20InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     * @param allowance Amount of tokens a `spender` is allowed to operate with.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC20InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `spender` to be approved. Used in approvals.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC20InvalidSpender(address spender);
}

/**
 * @dev Standard ERC721 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
 */
interface IERC721Errors {
    /**
     * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
     * Used in balance queries.
     * @param owner Address of the current owner of a token.
     */
    error ERC721InvalidOwner(address owner);

    /**
     * @dev Indicates a `tokenId` whose `owner` is the zero address.
     * @param tokenId Identifier number of a token.
     */
    error ERC721NonexistentToken(uint256 tokenId);

    /**
     * @dev Indicates an error related to the ownership over a particular token. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param tokenId Identifier number of a token.
     * @param owner Address of the current owner of a token.
     */
    error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC721InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC721InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param tokenId Identifier number of a token.
     */
    error ERC721InsufficientApproval(address operator, uint256 tokenId);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC721InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC721InvalidOperator(address operator);
}

/**
 * @dev Standard ERC1155 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
 */
interface IERC1155Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     * @param tokenId Identifier number of a token.
     */
    error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC1155InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC1155InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param owner Address of the current owner of a token.
     */
    error ERC1155MissingApprovalForAll(address operator, address owner);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC1155InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC1155InvalidOperator(address operator);

    /**
     * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
     * Used in batch transfers.
     * @param idsLength Length of the array of token identifiers
     * @param valuesLength Length of the array of token amounts
     */
    error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}

File 14 of 16 : Context.sol
// 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;
    }
}

File 15 of 16 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 16 of 16 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 125
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "remappings": [],
  "evmVersion": "paris"
}

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"AmountMustBeGreaterThanZero","type":"error"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minimumAmount","type":"uint256"}],"name":"AmountOfTokensLessThanMinimumRequired","type":"error"},{"inputs":[],"name":"AutoSwapPrevented","type":"error"},{"inputs":[],"name":"BoughtAmountTooLow","type":"error"},{"inputs":[],"name":"ContractIsNotInitialized","type":"error"},{"inputs":[],"name":"DecreasesK","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"ERC2612ExpiredSignature","type":"error"},{"inputs":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC2612InvalidSigner","type":"error"},{"inputs":[],"name":"FailedToSendNativeCurrency","type":"error"},{"inputs":[],"name":"InsufficientLiquidity","type":"error"},{"inputs":[],"name":"InsufficientLiquidityMinted","type":"error"},{"inputs":[],"name":"InvalidAddress","type":"error"},{"inputs":[],"name":"InvalidFeeRate","type":"error"},{"inputs":[],"name":"InvalidMaxWalletPercent","type":"error"},{"inputs":[],"name":"InvalidOwner","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"InvalidReserves","type":"error"},{"inputs":[],"name":"MaxWalletAmountExceeded","type":"error"},{"inputs":[],"name":"NameAndSymbolAlreadySet","type":"error"},{"inputs":[],"name":"NameAndSymbolMustNotBeEmpty","type":"error"},{"inputs":[],"name":"NativeRepaymentFailed","type":"error"},{"inputs":[],"name":"NoFeesToClaim","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"SlippageToleranceExceeded","type":"error"},{"inputs":[],"name":"StillBonding","type":"error"},{"inputs":[],"name":"SupplyAlreadyMinted","type":"error"},{"inputs":[],"name":"SwapNotEnabled","type":"error"},{"inputs":[],"name":"TokenRepaymentFailed","type":"error"},{"inputs":[],"name":"TransactionExpired","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"YouHaveNoLiquidity","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":true,"internalType":"address","name":"toAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"liquidityMinted","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"AddLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountNative","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountToken","type":"uint256"}],"name":"FeesCollected","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"feeTo","type":"address"},{"indexed":false,"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"FeesDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenPriceInNative","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nativePriceInToken","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"blockTimestampLast","type":"uint32"}],"name":"PricesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":true,"internalType":"address","name":"toAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"liquidityBurned","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"RemoveLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountTokenIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountNativeIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountTokenOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountNativeOut","type":"uint256"},{"indexed":false,"internalType":"bool","name":"flashSwap","type":"bool"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"BASE_SWAP_RATE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEAD_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FLASHSWAP_FEE_RATE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_FEE_RATE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINIMUM_LIQUIDITY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SCALE_FACTOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accruedNativeFactoryFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accruedNativeTradingFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accruedTokenFactoryFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accruedTokenTradingFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountToken_","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"blockTimestampLast","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"burstFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"completeTheCurve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"curveComplete","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"contract IBIFKN314Factory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeCollector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountNativeOut","type":"uint256"},{"internalType":"uint256","name":"amountTokenOut","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"flashSwap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"outputAmount","type":"uint256"},{"internalType":"uint256","name":"inputReserve","type":"uint256"},{"internalType":"uint256","name":"outputReserve","type":"uint256"}],"name":"getAmountIn","outputs":[{"internalType":"uint256","name":"inputAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"inputAmount","type":"uint256"},{"internalType":"uint256","name":"inputReserve","type":"uint256"},{"internalType":"uint256","name":"outputReserve","type":"uint256"}],"name":"getAmountOut","outputs":[{"internalType":"uint256","name":"outputAmount","type":"uint256"},{"internalType":"uint256","name":"factoryFee","type":"uint256"},{"internalType":"uint256","name":"tradingFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getAmountsForLP","outputs":[{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReserves","outputs":[{"internalType":"uint256","name":"amountNative","type":"uint256"},{"internalType":"uint256","name":"amountToken","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTokensInContract","outputs":[{"internalType":"uint256","name":"tokenBalance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"tokenName","type":"string"},{"internalType":"string","name":"tokenSymbol","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"burstFactory_","type":"address"}],"name":"initializeBurstToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"initializeFactory","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isInitialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isMaxWalletExempt","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidityToken","outputs":[{"internalType":"contract BIFKN314LP","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxWalletEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxWalletPercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadataURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"price0CumulativeLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"price1CumulativeLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"feeCollector_","type":"address"}],"name":"setFeeCollector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setMaxWalletEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addressToChange","type":"address"},{"internalType":"bool","name":"isExempt","type":"bool"}],"name":"setMaxWalletExempt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxWalletPercent_","type":"uint256"}],"name":"setMaxWalletPercent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newURI","type":"string"}],"name":"setMetadataURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"totalSupply_","type":"uint256"},{"internalType":"address","name":"owner_","type":"address"},{"internalType":"uint256","name":"feeRate_","type":"uint256"},{"internalType":"uint256","name":"maxWalletPercent_","type":"uint256"},{"internalType":"string","name":"metadataURI_","type":"string"}],"name":"setSupplyAndMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setTradingEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"feeRate","type":"uint256"}],"name":"setTradingFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minimumTokensOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapNativeToToken","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokensSold","type":"uint256"},{"internalType":"uint256","name":"minimumNativeOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokenToNative","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tradingEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tradingFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

Block Transaction Gas Used Reward
view all blocks ##produced##

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.