ETH Price: $2,008.79 (-0.09%)

Contract

0x820c889D5749847217599B43ab86FcC91781019f
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

1 address found via
Transaction Hash
Method
Block
From
To
Set Fee To204022682024-07-28 3:09:47242 days ago1722136187IN
0x820c889D...91781019f
0 ETH0.000053862.0422857
Deploy BIFKN314203527362024-07-21 5:11:35249 days ago1721538695IN
0x820c889D...91781019f
0 ETH0.003152362.08827482
Deploy BIFKN314200334182024-06-06 14:35:35294 days ago1717684535IN
0x820c889D...91781019f
0 ETH0.0367724723.78329514
Set Fee To200298592024-06-06 2:38:47294 days ago1717641527IN
0x820c889D...91781019f
0 ETH0.0002926910.03223432

Latest 2 internal transactions

Advanced mode:
Parent Transaction Hash Method Block
From
To
0x3d602d80203527362024-07-21 5:11:35249 days ago1721538695
0x820c889D...91781019f
 Contract Creation0 ETH
0x3d602d80200334182024-06-06 14:35:35294 days ago1717684535
0x820c889D...91781019f
 Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
BIFKN314Factory

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 50 runs

Other Settings:
paris EvmVersion
File 1 of 19 : BIFKN314Factory.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/proxy/Clones.sol";
import "./interfaces/IBIFKN314Factory.sol";
import "./BIFKN314.sol";

/**
 * @title BIFKN314Factory
 * @dev The BIFKN314Factory contract deploys new instances of the BIFKN314 contract.
 * It also stores the details of the deployed BIFKN314 contracts and their corresponding LP tokens.
 * It allows the fee setter to set the feeTo address, the feeToSetter address, and the fee distribution threshold.
 * The contract is owned by the deployer and inherits the ReentrancyGuard and Ownable contracts.
 * The contract also implements the IBIFKN314Factory interface.
 * The contract also implements the IBIFKN314FeeHandler interface. Which enables the BIFKN314 contract to distribute fees.
 * The contract emits events for BIFKN314 deployment, feeTo address setting, feeToSetter address setting, and fee distribution threshold setting.
 * The contract also defines custom errors for invalid addresses, empty names, long names, empty symbols, long symbols, invalid fee setters, and unauthorized access.
 */

contract BIFKN314Factory is
    IBIFKN314Factory,
    ReentrancyGuard,
    Ownable(msg.sender)
{
    using Clones for address;
    /**
     * @dev Struct to store the information of a BIFKN314 token.
     * @param name The name of the BIFKN314 token.
     * @param symbol The symbol of the BIFKN314 token.
     * @param totalSupply The total supply of the BIFKN314 token.
     * @param tokenAddress The address of the BIFKN314 token.
     * @param lpAddress The address of the LP (Liquidity Provider) token.
     */
    struct TokenInfo {
        string name;
        string symbol;
        uint256 totalSupply;
        address tokenAddress;
        address lpAddress;
        address deployer;
    }

    /**
     * @dev Mapping to store the addresses of bifkn314 contracts deployed by each deployer.
     * The key of the mapping is the deployer's address, and the value is an array of bifkn314 contract addresses.
     */
    mapping(address deployer => address[] tokenAddresses)
        public tokenAddressesByDeployer;

    /**
     * @dev Mapping to store TokenInfo structs by BIFKN314 contract address.
     * tokenAddress => tokenInfo
     */
    mapping(address tokenAddress => TokenInfo tokenInfo)
        public tokenInfoByTokenAddress;

    /**
     * @dev An array that stores the addresses of all instances of the BIFKN314 contract.
     */
    address[] public allTokens;

    /**
     * @dev The feeRate variable represents the fee rate for a specific operation.
     * The default value is set to 10, which is equivalent to 0.1%.
     * It's based on a scale of 10000, where 10000 is equivalent to 100%.
     * The fee is calculated as (amount * feeRate) / 10000.
     * The fee is deducted from the amount and sent to the feeTo address.
     * So if the feeRate is 10, 0.1% of the amount will be deducted as a fee.
     */
    uint256 public feeRate = 10; // 0.1%

    /**
     * @dev The address variable `feeTo` represents the address where the fees will be sent to.
     */
    address public feeTo;

    /**
     * @dev The address of the fee setter for the BIFKN314Factory contract.
     */
    address public feeToSetter;

    /**
     * @dev The threshold for fee distribution.
     * If the fee is greater than or equal to this threshold, it will be distributed.
     * The default value is set to 1 ether. This should be set based on the chain's native token.
     */
    uint256 public feeDistributionThreshold = 1 ether;

    /**
     * @dev The deployment fee for deploying a new BIFKN314 contract.
     */
    uint256 public deploymentFee = 0 ether;

    /**
     * @dev The address of the BIFKN314 implementation contract.
     */
    address public bifkn314Implementation;

    /**
     * @dev Modifier to restrict access to the `onlyFeeToSetter` function.
     * It ensures that only the `feeToSetter` address can execute the function.
     * Reverts with an error message if the caller is not the `feeToSetter`.
     */
    modifier onlyFeeToSetter() {
        if (_msgSender() != feeToSetter) revert OnlyFeeToSetter(_msgSender());
        _;
    }

    /**
     * @dev Initializes the BIFKN314Factory contract with the specified fee setter and deployment fee.
     * @param deploymentFee_ The deployment fee to be set based on the chain's native token.
     */
    constructor(uint256 deploymentFee_, address bifkn314Implementation_) {
        if (bifkn314Implementation_ == address(0)) revert InvalidAddress();
        feeToSetter = msg.sender;
        feeTo = msg.sender;
        deploymentFee = deploymentFee_;

        bifkn314Implementation = bifkn314Implementation_;
    }

    /**
     * @dev Deploys a new BIFKN314 contract.
     * @param tokenName The name of the BIFKN314 contract.
     * @param tokenSymbol The symbol of the BIFKN314 contract.
     * @param owner_ The address of the owner of the BIFKN314 contract.
     * @param totalSupply The total supply of the BIFKN314 contract.
     * @param tradingFee The trading fee for the BIFKN314 contract.
     * @param maxWalletPercent The maximum wallet percentage for the BIFKN314 contract.
     * @param metadataURI The metadata URI for the BIFKN314 contract.
     */
    function deployBIFKN314(
        string memory tokenName,
        string memory tokenSymbol,
        uint256 totalSupply,
        address owner_,
        uint256 tradingFee,
        uint256 maxWalletPercent,
        string memory metadataURI
    )
        external
        payable
        nonReentrant
        returns (address contractAddress, address liquidityTokenAddress)
    {
        // check if the deployment fee is paid
        if (msg.value < deploymentFee) revert InsufficientDeploymentFee();
        // check the validity of the constructor parameters
        _checkConstructorParams(
            tokenName,
            tokenSymbol,
            owner_,
            totalSupply,
            tradingFee,
            maxWalletPercent
        );

        address sender = _msgSender();

        // Clone the BIFKN314 implementation
        address clone = bifkn314Implementation.clone();

        // Cast clone to BIFKN314 to interact with it
        BIFKN314 newToken = BIFKN314(payable(clone));
        newToken.initializeFactory(address(this));
        // Initialize the clone
        newToken.initialize(tokenName, tokenSymbol);
        newToken.setSupplyAndMint(
            totalSupply,
            owner_,
            tradingFee,
            maxWalletPercent,
            metadataURI
        );

        contractAddress = clone;
        liquidityTokenAddress = address(newToken.liquidityToken());

        // Store BIFKN314 details in the nested mapping
        TokenInfo memory newBifkn314TokenInfo = TokenInfo({
            name: tokenName,
            symbol: tokenSymbol,
            totalSupply: totalSupply,
            tokenAddress: contractAddress,
            lpAddress: liquidityTokenAddress,
            deployer: sender
        });

        tokenInfoByTokenAddress[contractAddress] = newBifkn314TokenInfo;
        tokenAddressesByDeployer[sender].push(contractAddress);

        // store the contract address
        allTokens.push(contractAddress);

        // transfer the deployment fee to the feeTo address
        _transferFee();

        emit TokenCreated(
            sender,
            tokenName,
            tokenSymbol,
            contractAddress,
            liquidityTokenAddress,
            allTokens.length
        );
    }

    /**
     * @dev Returns the length of the `allTokens` array.
     * @return The length of the `allTokens` array as a uint256 value.
     */
    function allTokensLength() public view returns (uint256) {
        return allTokens.length;
    }

    /**
     * @dev Returns an array of all BIFKN314 Tokens.
     * @return An array of addresses representing all BIFKN314 Tokens.
     */
    function getAllTokens() public view returns (address[] memory) {
        return allTokens;
    }

    /**
     * @dev Retrieves the array of BIFKN314 contract addresses deployed by a specific deployer.
     * @param deployer The address of the deployer.
     * @return An array of BIFKN314 contract addresses deployed by the specified deployer.
     */
    function getTokensByDeployer(
        address deployer
    ) public view returns (address[] memory) {
        return tokenAddressesByDeployer[deployer];
    }

    /**
     * @dev Sets the address to which fees will be sent.
     * Can only be called by the feeToSetter.
     * @param feeTo_ The address to set as the feeTo address.
     */
    function setFeeTo(address feeTo_) external onlyFeeToSetter {
        feeTo = feeTo_;
    }

    /**
     * @dev Sets the address of the fee setter.
     * Can only be called by the current fee setter.
     * @param feeToSetter_ The address of the new fee setter.
     */
    function setFeeToSetter(address feeToSetter_) external onlyFeeToSetter {
        if (feeToSetter_ == address(0)) revert InvalidAddress();
        feeToSetter = feeToSetter_;
    }

    /**
     * @dev Sets the fee rate for the contract. This is the fee rate for swaps on each BIFKN314 contract.
     * @param feeRate_ The new fee rate to be set.
     * Requirements:
     * - `feeRate_` must be less than or equal to 10.
     * Modifiers:
     * - `onlyFeeToSetter`: Only the fee to setter can call this function.
     */
    function setFeeRate(uint256 feeRate_) external onlyFeeToSetter {
        if (feeRate_ > 10) revert InvalidFeeRate();

        feeRate = feeRate_;
    }

    /**
     * @dev Sets the threshold for fee distribution.
     * Can only be called by the feeToSetter.
     * This pertains to the fee threshold on the BIFKN314 contracts
     * @param feeDistributionThreshold_ The new threshold for fee distribution.
     */
    function setFeeDistributionThreshold(
        uint256 feeDistributionThreshold_
    ) external onlyFeeToSetter {
        feeDistributionThreshold = feeDistributionThreshold_;
    }

    /**
     * @dev Sets the deployment fee for deploying a new BIFKN314 contract.
     * Can only be called by the feeToSetter.
     * @param deploymentFee_ The new deployment fee to be set based on the chain's native token.
     */
    function setDeploymentFee(uint256 deploymentFee_) external onlyOwner {
        deploymentFee = deploymentFee_;
    }

    /**
     * @dev Updates the implementation contract address for the BIFKN314Factory contract.
     * Can only be called by the contract owner.
     * @param newImplementation The address of the new implementation contract.
     */
    function updateImplementation(
        address newImplementation
    ) external onlyOwner {
        bifkn314Implementation = newImplementation;
    }

    /**
     * @dev Transfers the fees accumulated in the contract to the designated fee recipient.
     * @notice This function is internal and can only be called from within the contract.
     * @notice The fees are transferred as the balance of the contract to the `feeTo` address.
     * @notice If the transfer fails, a `WithdrawFailed` exception is thrown.
     */
    function _transferFee() internal {
        // if the deployment fee is 0, don't transfer
        // if the feeTo is not set, don't transfer
        if (deploymentFee == 0 || feeTo == address(0)) return;

        uint256 balance = address(this).balance;
        (bool success, ) = payable(feeTo).call{value: balance}("");
        if (!success) revert DistributionFailed();

        emit FeeDistributed(feeTo, balance);
    }

    /**
     * @dev Internal function to check the validity of constructor parameters.
     * @param tokenName The name of the token.
     * @param tokenSymbol The symbol of the token.
     * @param owner_ The address of the token owner.
     * @param totalSupply The total supply of the token.
     * @param tradingFee The trading fee for the token.
     * @param maxWalletPercent The maximum wallet percentage for the token.
     * @dev This function checks if the provided parameters meet the required conditions:
     * - The name and symbol must not be empty.
     * - The owner address must be a valid address (not zero address).
     * - The total supply must be greater than zero.
     * - The name must not exceed 50 characters.
     * - The symbol must not exceed 10 characters.
     * - The trading fee must be less than or equal to 500 (5%).
     * - The max wallet percent must be less than or equal to 10000 (100%).
     * @dev If any of the conditions are not met, the function reverts with the corresponding error message.
     */
    function _checkConstructorParams(
        string memory tokenName,
        string memory tokenSymbol,
        address owner_,
        uint256 totalSupply,
        uint256 tradingFee,
        uint256 maxWalletPercent
    ) internal pure {
        if (bytes(tokenName).length == 0) {
            revert NameMustNotBeEmpty();
        }
        if (bytes(tokenSymbol).length == 0) {
            revert SymbolMustNotBeEmpty();
        }
        if (owner_ == address(0)) {
            revert InvalidAddress();
        }
        if (totalSupply == 0) {
            revert SupplyMustBeGreaterThanZero();
        }
        if (bytes(tokenName).length > 50) {
            revert NameTooLong();
        }
        if (bytes(tokenSymbol).length > 10) {
            revert SymbolTooLong();
        }
        if (tradingFee > 500) {
            // 5%
            revert InvalidTradingFee();
        }
        if (maxWalletPercent > 10000) {
            // 100%
            revert InvalidMaxWalletPercent();
        }
    }
}

File 2 of 19 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 3 of 19 : 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 4 of 19 : Clones.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/Clones.sol)

pragma solidity ^0.8.20;

/**
 * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
 * deploying minimal proxy contracts, also known as "clones".
 *
 * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
 * > a minimal bytecode implementation that delegates all calls to a known, fixed address.
 *
 * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
 * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
 * deterministic method.
 */
library Clones {
    /**
     * @dev A clone instance deployment failed.
     */
    error ERC1167FailedCreateClone();

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create opcode, which should never revert.
     */
    function clone(address implementation) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
            instance := create(0, 0x09, 0x37)
        }
        if (instance == address(0)) {
            revert ERC1167FailedCreateClone();
        }
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create2 opcode and a `salt` to deterministically deploy
     * the clone. Using the same `implementation` and `salt` multiple time will revert, since
     * the clones cannot be deployed twice at the same address.
     */
    function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
            instance := create2(0, 0x09, 0x37, salt)
        }
        if (instance == address(0)) {
            revert ERC1167FailedCreateClone();
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(add(ptr, 0x38), deployer)
            mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
            mstore(add(ptr, 0x14), implementation)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
            mstore(add(ptr, 0x58), salt)
            mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
            predicted := keccak256(add(ptr, 0x43), 0x55)
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt
    ) internal view returns (address predicted) {
        return predictDeterministicAddress(implementation, salt, address(this));
    }
}

File 5 of 19 : 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 6 of 19 : 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);
}

File 7 of 19 : 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 8 of 19 : 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 9 of 19 : 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 10 of 19 : 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 "./interfaces/IERC314.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,
    IERC314
{
    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 private 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 public boolean variable that indicates whether the contract factory is initialized or not.
     */
    bool public factoryInitialized;

    /**
     * @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.
     */
    uint public price0CumulativeLast;

    /**
     * @dev Represents the last cumulative price of the token.
     */
    uint 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.
     * 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 {
        if (factoryInitialized) revert OwnerAlreadyInitialized();
        factoryInitialized = true;
        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 (recipient == address(this) && !_autoSwapIsPrevented()) {
            swapTokenToNative(
                amount,
                _calculateAutoSwapSlippage(amount, false),
                block.timestamp + 3 minutes
            );
            success = true;
        } else {
            _checkMaxWallet(recipient, amount);
            success = super.transfer(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 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();
        // check if contract is initialized
        // only owner can add liquidity before initialization
        if (!isInitialized && sender != owner) {
            revert ContractIsNotInitialized();
        }
        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) {
        (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();
        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) {
        (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();
        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 (
            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 Checks if the given address is a contract.
     * @param addressToCheck The address to check.
     * @return result A boolean value indicating whether the address is a contract.
     */
    function _isContract(
        address addressToCheck
    ) internal view returns (bool result) {
        uint32 size;
        // Inline assembly code to get the size of the code at _address
        assembly {
            size := extcodesize(addressToCheck)
        }
        // If size > 0, it's a contract
        result = (size > 0);
    }

    /**
     * @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 11 of 19 : 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 12 of 19 : 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 13 of 19 : 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 14 of 19 : 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 15 of 19 : 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);

    event TokenCreated(
        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();
}

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

interface IERC314 {
    function addLiquidity(
        uint256 amountToken,
        address recipient,
        uint256 deadline
    ) external payable returns (uint256 liquidity);

    function removeLiquidity(
        uint256 amount,
        address recipient,
        uint256 deadline
    ) external returns (uint256 nativeAmount, uint256 tokenAmount);

    function swapNativeToToken(
        uint256 minimumTokensOut,
        uint256 deadline
    ) external payable;

    function swapTokenToNative(
        uint256 tokensSold,
        uint256 minimumNativeOut,
        uint256 deadline
    ) external;

    // function flashSwap(
    //     address recipient,
    //     uint256 amountNativeOut,
    //     uint256 amountTokenOut,
    //     bytes calldata data
    // ) external;

    function getAmountOut(
        uint256 inputAmount,
        uint256 inputReserve,
        uint256 outputReserve
    )
        external
        view
        returns (uint256 outputAmount, uint256 factoryFee, uint256 tradingFee);

    function getAmountIn(
        uint256 outputAmount,
        uint256 inputReserve,
        uint256 outputReserve
    ) external view returns (uint256 inputAmount);

    function getTokensInContract() external view returns (uint256);

    function getReserves()
        external
        view
        returns (uint256 amountNative, uint256 amountERC20);

    function getAmountsForLP(
        uint256 amount
    ) external view returns (uint256 nativeAmount, uint256 tokenAmount);

    function setFeeCollector(address feeCollector) external;

    function setTradingFeeRate(uint256 feeRate) external;

    function claimFees() external;

    function transferOwnership(address newOwner) external;

    function renounceOwnership() external;
}

File 17 of 19 : 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 OwnerAlreadyInitialized();
}

File 18 of 19 : 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 19 of 19 : 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];
    }
}

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

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"uint256","name":"deploymentFee_","type":"uint256"},{"internalType":"address","name":"bifkn314Implementation_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"DistributionFailed","type":"error"},{"inputs":[],"name":"ERC1167FailedCreateClone","type":"error"},{"inputs":[],"name":"ImplementationAlreadyDeployed","type":"error"},{"inputs":[],"name":"InsufficientDeploymentFee","type":"error"},{"inputs":[],"name":"InvalidAddress","type":"error"},{"inputs":[],"name":"InvalidFeeRate","type":"error"},{"inputs":[],"name":"InvalidMaxWalletPercent","type":"error"},{"inputs":[],"name":"InvalidTradingFee","type":"error"},{"inputs":[],"name":"NameMustNotBeEmpty","type":"error"},{"inputs":[],"name":"NameTooLong","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"OnlyFeeToSetter","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"SupplyMustBeGreaterThanZero","type":"error"},{"inputs":[],"name":"SymbolMustNotBeEmpty","type":"error"},{"inputs":[],"name":"SymbolTooLong","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"feeTo","type":"address"},{"indexed":false,"internalType":"uint256","name":"nativeAmount","type":"uint256"}],"name":"FeeDistributed","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":true,"internalType":"address","name":"deployer","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"string","name":"symbol","type":"string"},{"indexed":false,"internalType":"address","name":"ammAddress","type":"address"},{"indexed":false,"internalType":"address","name":"lpAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"allAMMLength","type":"uint256"}],"name":"TokenCreated","type":"event"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allTokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allTokensLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bifkn314Implementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"tokenName","type":"string"},{"internalType":"string","name":"tokenSymbol","type":"string"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"address","name":"owner_","type":"address"},{"internalType":"uint256","name":"tradingFee","type":"uint256"},{"internalType":"uint256","name":"maxWalletPercent","type":"uint256"},{"internalType":"string","name":"metadataURI","type":"string"}],"name":"deployBIFKN314","outputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"address","name":"liquidityTokenAddress","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"deploymentFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeDistributionThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeTo","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeToSetter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"deployer","type":"address"}],"name":"getTokensByDeployer","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"deploymentFee_","type":"uint256"}],"name":"setDeploymentFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"feeDistributionThreshold_","type":"uint256"}],"name":"setFeeDistributionThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"feeRate_","type":"uint256"}],"name":"setFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"feeTo_","type":"address"}],"name":"setFeeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"feeToSetter_","type":"address"}],"name":"setFeeToSetter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"deployer","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenAddressesByDeployer","outputs":[{"internalType":"address","name":"tokenAddresses","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"tokenInfoByTokenAddress","outputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"lpAddress","type":"address"},{"internalType":"address","name":"deployer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"updateImplementation","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6080604052600a600555670de0b6b3a7640000600855600060095534801561002657600080fd5b5060405161159838038061159883398101604081905261004591610136565b6001600055338061007057604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b610079816100e4565b506001600160a01b0381166100a15760405163e6c4247b60e01b815260040160405180910390fd5b60078054336001600160a01b03199182168117909255600680548216909217909155600992909255600a80549092166001600160a01b0391909116179055610173565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000806040838503121561014957600080fd5b825160208401519092506001600160a01b038116811461016857600080fd5b809150509250929050565b611416806101826000396000f3fe6080604052600436106101155760003560e01c80638da5cb5b1161009b5780638da5cb5b146102ae578063978bbdb9146102cc578063a2e74af6146102f0578063aceddb2614610310578063d002462b14610330578063dbb80e4214610350578063ecc4873514610365578063ef973d4714610385578063f2cff57f1461039b578063f2fde38b146103b1578063f46901ed146103d157600080fd5b8063017e7e581461011a578063025b22bc14610150578063094b7415146101725780632a5c792a146101925780633eef361a146101b457806344b0e9b5146101d457806345596e2e146101f4578063634282af146102145780636810c12114610234578063715018a614610267578063720fcb1e1461027c575b600080fd5b34801561012657600080fd5b5060065461013a906001600160a01b031681565b6040516101479190610ef0565b60405180910390f35b34801561015c57600080fd5b5061017061016b366004610f19565b6103f1565b005b34801561017e57600080fd5b5060075461013a906001600160a01b031681565b34801561019e57600080fd5b506101a761041b565b6040516101479190610f3d565b3480156101c057600080fd5b5061013a6101cf366004610f8a565b61047d565b3480156101e057600080fd5b506101706101ef366004610fb6565b6104b5565b34801561020057600080fd5b5061017061020f366004610fb6565b6104fa565b34801561022057600080fd5b5061013a61022f366004610fb6565b610542565b610247610242366004611072565b61056c565b604080516001600160a01b03938416815292909116602083015201610147565b34801561027357600080fd5b50610170610902565b34801561028857600080fd5b5061029c610297366004610f19565b610916565b60405161014796959493929190611172565b3480156102ba57600080fd5b506001546001600160a01b031661013a565b3480156102d857600080fd5b506102e260055481565b604051908152602001610147565b3480156102fc57600080fd5b5061017061030b366004610f19565b610a6a565b34801561031c57600080fd5b50600a5461013a906001600160a01b031681565b34801561033c57600080fd5b5061017061034b366004610fb6565b610ad4565b34801561035c57600080fd5b506004546102e2565b34801561037157600080fd5b506101a7610380366004610f19565b610ae1565b34801561039157600080fd5b506102e260085481565b3480156103a757600080fd5b506102e260095481565b3480156103bd57600080fd5b506101706103cc366004610f19565b610b57565b3480156103dd57600080fd5b506101706103ec366004610f19565b610b95565b6103f9610bd8565b600a80546001600160a01b0319166001600160a01b0392909216919091179055565b6060600480548060200260200160405190810160405280929190818152602001828054801561047357602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610455575b5050505050905090565b6002602052816000526040600020818154811061049957600080fd5b6000918252602090912001546001600160a01b03169150829050565b6007546001600160a01b0316336001600160a01b0316146104f557335b604051639dae072d60e01b81526004016104ec9190610ef0565b60405180910390fd5b600855565b6007546001600160a01b0316336001600160a01b03161461051b57336104d2565b600a81111561053d57604051630adad23360e31b815260040160405180910390fd5b600555565b6004818154811061055257600080fd5b6000918252602090912001546001600160a01b0316905081565b600080610577610c05565b60095434101561059a576040516354605d0160e11b815260040160405180910390fd5b6105a88989888a8989610c2f565b600a5433906000906105c2906001600160a01b0316610d4f565b6040516329c51f8760e11b815290915081906001600160a01b0382169063538a3f0e906105f3903090600401610ef0565b600060405180830381600087803b15801561060d57600080fd5b505af1158015610621573d6000803e3d6000fd5b505060405163266c45bb60e11b81526001600160a01b0384169250634cd88b769150610653908f908f906004016111c8565b600060405180830381600087803b15801561066d57600080fd5b505af1158015610681573d6000803e3d6000fd5b5050604051638b19d6cf60e01b81526001600160a01b0384169250638b19d6cf91506106b9908d908d908d908d908d906004016111f6565b600060405180830381600087803b1580156106d357600080fd5b505af11580156106e7573d6000803e3d6000fd5b50505050819450806001600160a01b03166343cd8f7e6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561072c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107509190611234565b6040805160c0810182528e815260208082018f90528183018e90526001600160a01b03808a1660608401819052818616608085015290881660a084015260009081526003909152919091208151929650909182919081906107b190826112d6565b50602082015160018201906107c690826112d6565b5060408281015160028381019190915560608401516003840180546001600160a01b03199081166001600160a01b039384161790915560808601516004808701805484169285169290921790915560a090960151600590950180548216958316959095179094558881166000908152602092835292832080546001818101835591855292842090920180548516918c16918217905584549182018555939091527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b018054909116909117905561089a610dc1565b836001600160a01b03167f8da3026c0bd0173206f3792eaad7438d7efbbb4f46934f355d09d4ba0d184ee28e8e89896004805490506040516108e0959493929190611396565b60405180910390a2505050506108f66001600055565b97509795505050505050565b61090a610bd8565b6109146000610e9e565b565b60036020526000908152604090208054819061093190611251565b80601f016020809104026020016040519081016040528092919081815260200182805461095d90611251565b80156109aa5780601f1061097f576101008083540402835291602001916109aa565b820191906000526020600020905b81548152906001019060200180831161098d57829003601f168201915b5050505050908060010180546109bf90611251565b80601f01602080910402602001604051908101604052809291908181526020018280546109eb90611251565b8015610a385780601f10610a0d57610100808354040283529160200191610a38565b820191906000526020600020905b815481529060010190602001808311610a1b57829003601f168201915b505050600284015460038501546004860154600590960154949591946001600160a01b03918216945091811692501686565b6007546001600160a01b0316336001600160a01b031614610a8b57336104d2565b6001600160a01b038116610ab25760405163e6c4247b60e01b815260040160405180910390fd5b600780546001600160a01b0319166001600160a01b0392909216919091179055565b610adc610bd8565b600955565b6001600160a01b038116600090815260026020908152604091829020805483518184028101840190945280845260609392830182828015610b4b57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610b2d575b50505050509050919050565b610b5f610bd8565b6001600160a01b038116610b89576000604051631e4fbdf760e01b81526004016104ec9190610ef0565b610b9281610e9e565b50565b6007546001600160a01b0316336001600160a01b031614610bb657336104d2565b600680546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b03163314610914573360405163118cdaa760e01b81526004016104ec9190610ef0565b600260005403610c2857604051633ee5aeb560e01b815260040160405180910390fd5b6002600055565b8551600003610c515760405163a1127c7d60e01b815260040160405180910390fd5b8451600003610c735760405163a876bbfb60e01b815260040160405180910390fd5b6001600160a01b038416610c9a5760405163e6c4247b60e01b815260040160405180910390fd5b82600003610cbb576040516347fc732760e11b815260040160405180910390fd5b603286511115610cde5760405163680b6caf60e01b815260040160405180910390fd5b600a85511115610d0157604051631124f78b60e01b815260040160405180910390fd5b6101f4821115610d24576040516348624fcb60e01b815260040160405180910390fd5b612710811115610d47576040516326dd075560e01b815260040160405180910390fd5b505050505050565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008260601b60e81c176000526e5af43d82803e903d91602b57fd5bf38260781b17602052603760096000f090506001600160a01b038116610dbc576040516330be1a3d60e21b815260040160405180910390fd5b919050565b6009541580610dd957506006546001600160a01b0316155b15610de057565b60065460405147916000916001600160a01b039091169083908381818185875af1925050503d8060008114610e31576040519150601f19603f3d011682016040523d82523d6000602084013e610e36565b606091505b5050905080610e585760405163185f9d0960e01b815260040160405180910390fd5b6006546040518381526001600160a01b03909116907f6c461460f28af1386f23dc4c0c7f4e2e54f0db320a8edc08803e4b787f6db3259060200160405180910390a25050565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b0391909116815260200190565b6001600160a01b0381168114610b9257600080fd5b600060208284031215610f2b57600080fd5b8135610f3681610f04565b9392505050565b6020808252825182820181905260009190848201906040850190845b81811015610f7e5783516001600160a01b031683529284019291840191600101610f59565b50909695505050505050565b60008060408385031215610f9d57600080fd5b8235610fa881610f04565b946020939093013593505050565b600060208284031215610fc857600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112610ff657600080fd5b813567ffffffffffffffff8082111561101157611011610fcf565b604051601f8301601f19908116603f0116810190828211818310171561103957611039610fcf565b8160405283815286602085880101111561105257600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600080600060e0888a03121561108d57600080fd5b873567ffffffffffffffff808211156110a557600080fd5b6110b18b838c01610fe5565b985060208a01359150808211156110c757600080fd5b6110d38b838c01610fe5565b975060408a0135965060608a013591506110ec82610f04565b9094506080890135935060a0890135925060c0890135908082111561111057600080fd5b5061111d8a828b01610fe5565b91505092959891949750929550565b6000815180845260005b8181101561115257602081850181015186830182015201611136565b506000602082860101526020601f19601f83011685010191505092915050565b60c08152600061118560c083018961112c565b8281036020840152611197818961112c565b604084019790975250506001600160a01b039384166060820152918316608083015290911660a09091015292915050565b6040815260006111db604083018561112c565b82810360208401526111ed818561112c565b95945050505050565b85815260018060a01b038516602082015283604082015282606082015260a06080820152600061122960a083018461112c565b979650505050505050565b60006020828403121561124657600080fd5b8151610f3681610f04565b600181811c9082168061126557607f821691505b60208210810361128557634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156112d157600081815260208120601f850160051c810160208610156112b25750805b601f850160051c820191505b81811015610d47578281556001016112be565b505050565b815167ffffffffffffffff8111156112f0576112f0610fcf565b611304816112fe8454611251565b8461128b565b602080601f83116001811461133957600084156113215750858301515b600019600386901b1c1916600185901b178555610d47565b600085815260208120601f198616915b8281101561136857888601518255948401946001909101908401611349565b50858210156113865787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60a0815260006113a960a083018861112c565b82810360208401526113bb818861112c565b6001600160a01b0396871660408501529490951660608301525060800152939250505056fea264697066735822122042381696482a5a4c6c25ae284c2ed4c31917b7899de0f119199f3d51aaa5724364736f6c634300081400330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba8deefe84adbfbad2278665e90237a819795bc9

Deployed Bytecode

0x6080604052600436106101155760003560e01c80638da5cb5b1161009b5780638da5cb5b146102ae578063978bbdb9146102cc578063a2e74af6146102f0578063aceddb2614610310578063d002462b14610330578063dbb80e4214610350578063ecc4873514610365578063ef973d4714610385578063f2cff57f1461039b578063f2fde38b146103b1578063f46901ed146103d157600080fd5b8063017e7e581461011a578063025b22bc14610150578063094b7415146101725780632a5c792a146101925780633eef361a146101b457806344b0e9b5146101d457806345596e2e146101f4578063634282af146102145780636810c12114610234578063715018a614610267578063720fcb1e1461027c575b600080fd5b34801561012657600080fd5b5060065461013a906001600160a01b031681565b6040516101479190610ef0565b60405180910390f35b34801561015c57600080fd5b5061017061016b366004610f19565b6103f1565b005b34801561017e57600080fd5b5060075461013a906001600160a01b031681565b34801561019e57600080fd5b506101a761041b565b6040516101479190610f3d565b3480156101c057600080fd5b5061013a6101cf366004610f8a565b61047d565b3480156101e057600080fd5b506101706101ef366004610fb6565b6104b5565b34801561020057600080fd5b5061017061020f366004610fb6565b6104fa565b34801561022057600080fd5b5061013a61022f366004610fb6565b610542565b610247610242366004611072565b61056c565b604080516001600160a01b03938416815292909116602083015201610147565b34801561027357600080fd5b50610170610902565b34801561028857600080fd5b5061029c610297366004610f19565b610916565b60405161014796959493929190611172565b3480156102ba57600080fd5b506001546001600160a01b031661013a565b3480156102d857600080fd5b506102e260055481565b604051908152602001610147565b3480156102fc57600080fd5b5061017061030b366004610f19565b610a6a565b34801561031c57600080fd5b50600a5461013a906001600160a01b031681565b34801561033c57600080fd5b5061017061034b366004610fb6565b610ad4565b34801561035c57600080fd5b506004546102e2565b34801561037157600080fd5b506101a7610380366004610f19565b610ae1565b34801561039157600080fd5b506102e260085481565b3480156103a757600080fd5b506102e260095481565b3480156103bd57600080fd5b506101706103cc366004610f19565b610b57565b3480156103dd57600080fd5b506101706103ec366004610f19565b610b95565b6103f9610bd8565b600a80546001600160a01b0319166001600160a01b0392909216919091179055565b6060600480548060200260200160405190810160405280929190818152602001828054801561047357602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610455575b5050505050905090565b6002602052816000526040600020818154811061049957600080fd5b6000918252602090912001546001600160a01b03169150829050565b6007546001600160a01b0316336001600160a01b0316146104f557335b604051639dae072d60e01b81526004016104ec9190610ef0565b60405180910390fd5b600855565b6007546001600160a01b0316336001600160a01b03161461051b57336104d2565b600a81111561053d57604051630adad23360e31b815260040160405180910390fd5b600555565b6004818154811061055257600080fd5b6000918252602090912001546001600160a01b0316905081565b600080610577610c05565b60095434101561059a576040516354605d0160e11b815260040160405180910390fd5b6105a88989888a8989610c2f565b600a5433906000906105c2906001600160a01b0316610d4f565b6040516329c51f8760e11b815290915081906001600160a01b0382169063538a3f0e906105f3903090600401610ef0565b600060405180830381600087803b15801561060d57600080fd5b505af1158015610621573d6000803e3d6000fd5b505060405163266c45bb60e11b81526001600160a01b0384169250634cd88b769150610653908f908f906004016111c8565b600060405180830381600087803b15801561066d57600080fd5b505af1158015610681573d6000803e3d6000fd5b5050604051638b19d6cf60e01b81526001600160a01b0384169250638b19d6cf91506106b9908d908d908d908d908d906004016111f6565b600060405180830381600087803b1580156106d357600080fd5b505af11580156106e7573d6000803e3d6000fd5b50505050819450806001600160a01b03166343cd8f7e6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561072c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107509190611234565b6040805160c0810182528e815260208082018f90528183018e90526001600160a01b03808a1660608401819052818616608085015290881660a084015260009081526003909152919091208151929650909182919081906107b190826112d6565b50602082015160018201906107c690826112d6565b5060408281015160028381019190915560608401516003840180546001600160a01b03199081166001600160a01b039384161790915560808601516004808701805484169285169290921790915560a090960151600590950180548216958316959095179094558881166000908152602092835292832080546001818101835591855292842090920180548516918c16918217905584549182018555939091527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b018054909116909117905561089a610dc1565b836001600160a01b03167f8da3026c0bd0173206f3792eaad7438d7efbbb4f46934f355d09d4ba0d184ee28e8e89896004805490506040516108e0959493929190611396565b60405180910390a2505050506108f66001600055565b97509795505050505050565b61090a610bd8565b6109146000610e9e565b565b60036020526000908152604090208054819061093190611251565b80601f016020809104026020016040519081016040528092919081815260200182805461095d90611251565b80156109aa5780601f1061097f576101008083540402835291602001916109aa565b820191906000526020600020905b81548152906001019060200180831161098d57829003601f168201915b5050505050908060010180546109bf90611251565b80601f01602080910402602001604051908101604052809291908181526020018280546109eb90611251565b8015610a385780601f10610a0d57610100808354040283529160200191610a38565b820191906000526020600020905b815481529060010190602001808311610a1b57829003601f168201915b505050600284015460038501546004860154600590960154949591946001600160a01b03918216945091811692501686565b6007546001600160a01b0316336001600160a01b031614610a8b57336104d2565b6001600160a01b038116610ab25760405163e6c4247b60e01b815260040160405180910390fd5b600780546001600160a01b0319166001600160a01b0392909216919091179055565b610adc610bd8565b600955565b6001600160a01b038116600090815260026020908152604091829020805483518184028101840190945280845260609392830182828015610b4b57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610b2d575b50505050509050919050565b610b5f610bd8565b6001600160a01b038116610b89576000604051631e4fbdf760e01b81526004016104ec9190610ef0565b610b9281610e9e565b50565b6007546001600160a01b0316336001600160a01b031614610bb657336104d2565b600680546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b03163314610914573360405163118cdaa760e01b81526004016104ec9190610ef0565b600260005403610c2857604051633ee5aeb560e01b815260040160405180910390fd5b6002600055565b8551600003610c515760405163a1127c7d60e01b815260040160405180910390fd5b8451600003610c735760405163a876bbfb60e01b815260040160405180910390fd5b6001600160a01b038416610c9a5760405163e6c4247b60e01b815260040160405180910390fd5b82600003610cbb576040516347fc732760e11b815260040160405180910390fd5b603286511115610cde5760405163680b6caf60e01b815260040160405180910390fd5b600a85511115610d0157604051631124f78b60e01b815260040160405180910390fd5b6101f4821115610d24576040516348624fcb60e01b815260040160405180910390fd5b612710811115610d47576040516326dd075560e01b815260040160405180910390fd5b505050505050565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008260601b60e81c176000526e5af43d82803e903d91602b57fd5bf38260781b17602052603760096000f090506001600160a01b038116610dbc576040516330be1a3d60e21b815260040160405180910390fd5b919050565b6009541580610dd957506006546001600160a01b0316155b15610de057565b60065460405147916000916001600160a01b039091169083908381818185875af1925050503d8060008114610e31576040519150601f19603f3d011682016040523d82523d6000602084013e610e36565b606091505b5050905080610e585760405163185f9d0960e01b815260040160405180910390fd5b6006546040518381526001600160a01b03909116907f6c461460f28af1386f23dc4c0c7f4e2e54f0db320a8edc08803e4b787f6db3259060200160405180910390a25050565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b0391909116815260200190565b6001600160a01b0381168114610b9257600080fd5b600060208284031215610f2b57600080fd5b8135610f3681610f04565b9392505050565b6020808252825182820181905260009190848201906040850190845b81811015610f7e5783516001600160a01b031683529284019291840191600101610f59565b50909695505050505050565b60008060408385031215610f9d57600080fd5b8235610fa881610f04565b946020939093013593505050565b600060208284031215610fc857600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112610ff657600080fd5b813567ffffffffffffffff8082111561101157611011610fcf565b604051601f8301601f19908116603f0116810190828211818310171561103957611039610fcf565b8160405283815286602085880101111561105257600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600080600060e0888a03121561108d57600080fd5b873567ffffffffffffffff808211156110a557600080fd5b6110b18b838c01610fe5565b985060208a01359150808211156110c757600080fd5b6110d38b838c01610fe5565b975060408a0135965060608a013591506110ec82610f04565b9094506080890135935060a0890135925060c0890135908082111561111057600080fd5b5061111d8a828b01610fe5565b91505092959891949750929550565b6000815180845260005b8181101561115257602081850181015186830182015201611136565b506000602082860101526020601f19601f83011685010191505092915050565b60c08152600061118560c083018961112c565b8281036020840152611197818961112c565b604084019790975250506001600160a01b039384166060820152918316608083015290911660a09091015292915050565b6040815260006111db604083018561112c565b82810360208401526111ed818561112c565b95945050505050565b85815260018060a01b038516602082015283604082015282606082015260a06080820152600061122960a083018461112c565b979650505050505050565b60006020828403121561124657600080fd5b8151610f3681610f04565b600181811c9082168061126557607f821691505b60208210810361128557634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156112d157600081815260208120601f850160051c810160208610156112b25750805b601f850160051c820191505b81811015610d47578281556001016112be565b505050565b815167ffffffffffffffff8111156112f0576112f0610fcf565b611304816112fe8454611251565b8461128b565b602080601f83116001811461133957600084156113215750858301515b600019600386901b1c1916600185901b178555610d47565b600085815260208120601f198616915b8281101561136857888601518255948401946001909101908401611349565b50858210156113865787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60a0815260006113a960a083018861112c565b82810360208401526113bb818861112c565b6001600160a01b0396871660408501529490951660608301525060800152939250505056fea264697066735822122042381696482a5a4c6c25ae284c2ed4c31917b7899de0f119199f3d51aaa5724364736f6c63430008140033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba8deefe84adbfbad2278665e90237a819795bc9

-----Decoded View---------------
Arg [0] : deploymentFee_ (uint256): 0
Arg [1] : bifkn314Implementation_ (address): 0xbA8DeEFe84AdBFBAD2278665e90237a819795BC9

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [1] : 000000000000000000000000ba8deefe84adbfbad2278665e90237a819795bc9


Block Transaction Difficulty 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
Loading...
Loading
[ 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.