// 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 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 immutable 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();
address factoryAddress = sender;
// if the sender is not a contract, set the factory address to address(0)
// This will disable fee distribution.
// This is useful for testing and for EOA deployments
// where the factory contract is not available.
if (!_isContract(sender)) factoryAddress = address(0);
factory = IBIFKN314Factory(factoryAddress);
_transferOwnership(sender);
}
/**
* @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
);
}
}
}
// 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);
}
}
// 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);
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (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);
}
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
interface IBIFKN314CALLEE {
function BIFKN314CALL(
address sender,
uint256 amount0,
uint256 amount1,
bytes calldata data
) external;
}
// 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();
}
// 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);
}
// 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);
}
// 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;
}
// 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();
}
// 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
);
}
// 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;
}
}
// 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];
}
}
// 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;
}
}
// 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);
}
{
"compilationTarget": {
"contracts/BIFKN314.sol": "BIFKN314"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 50
},
"remappings": []
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AmountMustBeGreaterThanZero","type":"error"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minimumAmount","type":"uint256"}],"name":"AmountOfTokensLessThanMinimumRequired","type":"error"},{"inputs":[],"name":"AutoSwapPrevented","type":"error"},{"inputs":[],"name":"BoughtAmountTooLow","type":"error"},{"inputs":[],"name":"ContractIsNotInitialized","type":"error"},{"inputs":[],"name":"DecreasesK","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"ERC2612ExpiredSignature","type":"error"},{"inputs":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC2612InvalidSigner","type":"error"},{"inputs":[],"name":"FailedToSendNativeCurrency","type":"error"},{"inputs":[],"name":"InsufficientLiquidity","type":"error"},{"inputs":[],"name":"InsufficientLiquidityMinted","type":"error"},{"inputs":[],"name":"InvalidAddress","type":"error"},{"inputs":[],"name":"InvalidFeeRate","type":"error"},{"inputs":[],"name":"InvalidMaxWalletPercent","type":"error"},{"inputs":[],"name":"InvalidOwner","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"InvalidReserves","type":"error"},{"inputs":[],"name":"MaxWalletAmountExceeded","type":"error"},{"inputs":[],"name":"NameAndSymbolAlreadySet","type":"error"},{"inputs":[],"name":"NameAndSymbolMustNotBeEmpty","type":"error"},{"inputs":[],"name":"NativeRepaymentFailed","type":"error"},{"inputs":[],"name":"NoFeesToClaim","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"SlippageToleranceExceeded","type":"error"},{"inputs":[],"name":"SupplyAlreadyMinted","type":"error"},{"inputs":[],"name":"SwapNotEnabled","type":"error"},{"inputs":[],"name":"TokenRepaymentFailed","type":"error"},{"inputs":[],"name":"TransactionExpired","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"YouHaveNoLiquidity","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":true,"internalType":"address","name":"toAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"liquidityMinted","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"AddLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountNative","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountToken","type":"uint256"}],"name":"FeesCollected","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"feeTo","type":"address"},{"indexed":false,"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"FeesDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenPriceInNative","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nativePriceInToken","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"blockTimestampLast","type":"uint32"}],"name":"PricesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":true,"internalType":"address","name":"toAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"liquidityBurned","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"RemoveLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountTokenIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountNativeIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountTokenOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountNativeOut","type":"uint256"},{"indexed":false,"internalType":"bool","name":"flashSwap","type":"bool"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"BASE_SWAP_RATE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FLASHSWAP_FEE_RATE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_FEE_RATE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINIMUM_LIQUIDITY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SCALE_FACTOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accruedNativeFactoryFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accruedNativeTradingFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accruedTokenFactoryFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accruedTokenTradingFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountToken_","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"blockTimestampLast","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"contract IBIFKN314Factory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeCollector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountNativeOut","type":"uint256"},{"internalType":"uint256","name":"amountTokenOut","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"flashSwap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"outputAmount","type":"uint256"},{"internalType":"uint256","name":"inputReserve","type":"uint256"},{"internalType":"uint256","name":"outputReserve","type":"uint256"}],"name":"getAmountIn","outputs":[{"internalType":"uint256","name":"inputAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"inputAmount","type":"uint256"},{"internalType":"uint256","name":"inputReserve","type":"uint256"},{"internalType":"uint256","name":"outputReserve","type":"uint256"}],"name":"getAmountOut","outputs":[{"internalType":"uint256","name":"outputAmount","type":"uint256"},{"internalType":"uint256","name":"factoryFee","type":"uint256"},{"internalType":"uint256","name":"tradingFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getAmountsForLP","outputs":[{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReserves","outputs":[{"internalType":"uint256","name":"amountNative","type":"uint256"},{"internalType":"uint256","name":"amountToken","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTokensInContract","outputs":[{"internalType":"uint256","name":"tokenBalance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"tokenName","type":"string"},{"internalType":"string","name":"tokenSymbol","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isInitialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isMaxWalletExempt","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidityToken","outputs":[{"internalType":"contract BIFKN314LP","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxWalletEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxWalletPercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadataURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"price0CumulativeLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"price1CumulativeLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"feeCollector_","type":"address"}],"name":"setFeeCollector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setMaxWalletEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addressToChange","type":"address"},{"internalType":"bool","name":"isExempt","type":"bool"}],"name":"setMaxWalletExempt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxWalletPercent_","type":"uint256"}],"name":"setMaxWalletPercent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newURI","type":"string"}],"name":"setMetadataURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"totalSupply_","type":"uint256"},{"internalType":"address","name":"owner_","type":"address"},{"internalType":"uint256","name":"feeRate_","type":"uint256"},{"internalType":"uint256","name":"maxWalletPercent_","type":"uint256"},{"internalType":"string","name":"metadataURI_","type":"string"}],"name":"setSupplyAndMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setTradingEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"feeRate","type":"uint256"}],"name":"setTradingFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minimumTokensOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapNativeToToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokensSold","type":"uint256"},{"internalType":"uint256","name":"minimumNativeOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokenToNative","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tradingEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tradingFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]