Contract Source Code:
/*
█▀ █▀█ █▄░█ █ █▀▀ █▀▀ ▄▀█ █▀▀ ▀█▀ █▀█ █▀█ █▄█
▄█ █▄█ █░▀█ █ █▄▄ █▀░ █▀█ █▄▄ ░█░ █▄█ █▀▄ ░█░
Trade on SonicFactory and have fun!
Web: https://sonicfactory.fun/
*/
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "./interfaces/IERC20.sol";
import "./interfaces/IIncubatorToken.sol";
import "./interfaces/IIncubatorPair.sol";
import "./interfaces/IUniswapV2Router.sol";
import "./interfaces/IUniswapV2Factory.sol";
import "./Ownable.sol";
import "./Token/Token.sol";
contract Incubator is Ownable {
uint8 private _PAUSED;
uint8 private _initialized;
uint8 private constant _DECIMALS = 18;
uint24 private _SWAP_FEE;
uint24 private _REFERRAL_FEE;
uint24 private _ESCAPE_FEE;
uint24 private _ESCAPE_CREATOR_FEE;
uint24 private _TOKEN_INITIAL_PERCENT;
uint112 private _ETH_RESERVE_VIRTUAL_INITIAL;
uint112 private _ETH_RESERVE_ESCAPE_TARGET;
uint256 private _CREATION_FEE;
uint256 private constant _TOTAL_SUPPLY = 1_000_000_000 ether;
address private _AUTHORIZED;
address private _TREASURY;
address private _ROUTER_INCUBATOR;
address private _WETH_INCUBATOR;
address[] private _tokenList;
address[] private _unauthorizedList;
mapping(address => TokenData) private _tokenData;
mapping(address => RouterData) private _routerData;
mapping(address => bool) private _creatorData;
mapping(address => address) private _pairData;
struct TokenData {
bytes32 salt;
uint24 maxBalance;
uint24 fee;
uint24 tax;
uint24 ref;
uint32 creation;
uint32 launch;
uint32 escaped;
uint112 ethReserveEscapeTarget;
uint112 ethReserveVirtualInitial;
uint112 ethReserveEscaped;
uint112 tokenReserveInitial;
uint256 tokenReserveEscaped;
uint256 initialSupply;
uint256 creationFee;
uint256 escapeFee;
address creator;
address referral;
address routerIncubator;
address pairIncubator;
address routerFinal;
bool autoEscape;
}
struct TokenDataView {
string name;
string symbol;
uint8 decimals;
uint24 maxBalance;
uint24 fee;
uint24 tax;
uint24 ref;
uint24 holders;
uint32 creation;
uint32 launch;
uint32 escaped;
uint112 ethReserveEscapeTarget;
uint112 ethReserveEscaped;
uint112 ethReserveVirtualInitial;
uint112 ethReserve;
uint112 tokenReserveInitial;
uint112 tokenReserve;
uint256 tokenReserveEscaped;
uint256 initialSupply;
uint256 totalSupply;
uint256 creationFee;
uint256 escapeFee;
address creator;
address referral;
address routerIncubator;
address pairIncubator;
address routerFinal;
bool autoEscape;
}
struct RouterData {
bool exists;
bool enabled;
}
struct TokenListView {
address token;
address creator;
bytes32 salt;
}
struct currentStatusView {
address routerIncubator;
uint8 paused;
uint8 decimals;
uint24 swapFee;
uint24 referralFee;
uint24 escapeFee;
uint24 escapeCreatorFee;
uint24 tokenInitialPercent;
uint112 ethReserveVirtualInitial;
uint112 ethReserveEscapeTarget;
uint256 creationFee;
uint256 totalSupply;
}
event TokenDeployed(address indexed token, address indexed creator, bytes32 salt);
event TokenEscaped(address indexed token, uint32 escapeTime, uint112 ethReserveEscaped, uint256 tokenReserveEscaped, uint256 escapeFee);
event TokenTraded(address indexed token, uint32 tradeTime, address indexed user, bool buy, uint112 ethReserve, uint112 tokenReserve, uint256 ethAmount, uint256 tokenAmount, uint256 feeAmount, uint256 taxAmount, uint256 refAmount);
event WithdrawnETH(address indexed to, uint256 value);
event WithdrawnERC20(address token, address indexed to, uint256 value);
error ErrorPaused();
error ErrorReferral();
error ErrorTransfer(address to, uint256 value);
error ErrorRouterUnavailable(address router);
error ErrorTokenMinimumValue(uint256 value);
error ErrorUnknownToken(address token);
error ErrorUnescapedToken(address token);
error ErrorTokenMaxBalance(uint24 percent);
error ErrorTokenTax(uint24 percent);
error ErrorTokenLiquidity(uint256 tokenAmount, uint256 ethAmount);
error ErrorInvalidRange();
modifier onlyOwnerOrAuthorized() {
if (msg.sender != _owner && msg.sender != _AUTHORIZED) { revert ErrorUnauthorized(msg.sender); }
_;
}
modifier isToken(address token) {
if (_tokenData[token].creator == address(0)) { revert ErrorUnknownToken(token); }
_;
}
modifier isPairOfToken() {
if (_pairData[msg.sender] == address(0)) { revert ErrorUnauthorized(msg.sender); }
_;
}
constructor() payable {}
function initialize() external {
require(_initialized == 0);
_SWAP_FEE = 1_000; // 1%
_REFERRAL_FEE = 20_000; // 20% of _SWAP_FEE
_ESCAPE_FEE = 5_000; // 5%
_ESCAPE_CREATOR_FEE = 50_000; // 50% of _ESCAPE_FEE
_TOKEN_INITIAL_PERCENT = 100_000; // 100%
_ETH_RESERVE_VIRTUAL_INITIAL = 0.8 ether;
_ETH_RESERVE_ESCAPE_TARGET = 3.8 ether;
_transferOwnership(msg.sender);
_initialized = 1;
}
function setPaused(bool status) external onlyOwner {
_PAUSED = status ? 1 : 0;
}
function setAuthorized(address authorized) external onlyOwner {
_AUTHORIZED = authorized;
}
function setFees(uint256 creationFee, uint24 swapFee, uint24 referralFee, uint24 escapeFee, uint24 escapeCreatorFee) external onlyOwner {
require(swapFee <= 5_000); // Max. 5%
require(referralFee <= 50_000); // Max. 50% of swapFee
require(escapeFee <= 25_000); // Max. 25%
require(escapeCreatorFee <= 100_000); // Max. 100% of escapeFee
_CREATION_FEE = creationFee;
_SWAP_FEE = swapFee;
_REFERRAL_FEE = referralFee;
_ESCAPE_FEE = escapeFee;
_ESCAPE_CREATOR_FEE = escapeCreatorFee;
}
function setTokenReserves(uint24 percent) external onlyOwner {
require(percent >= 50_000 && percent <= 100_000); // 50% to 100%
_TOKEN_INITIAL_PERCENT = percent;
}
function setEthReserves(uint112 ethReserveVirtualInitial, uint112 ethReserveEscapeTarget) external onlyOwner {
_ETH_RESERVE_VIRTUAL_INITIAL = ethReserveVirtualInitial;
_ETH_RESERVE_ESCAPE_TARGET = ethReserveEscapeTarget;
}
function setRouterIncubator(address router) external onlyOwner {
_ROUTER_INCUBATOR = router;
_WETH_INCUBATOR = IUniswapV2Router(router).WETH();
}
function setRouterFinal(address router, bool enabled, address[] calldata related) external onlyOwner {
RouterData storage _router = _routerData[router];
_router.enabled = enabled;
if (!_router.exists) {
_router.exists = true;
_unauthorizedList.push(router);
unchecked {
uint256 cnt = related.length;
for (uint256 i; i < cnt; i++) { _unauthorizedList.push(related[i]); }
}
}
}
function listTokens(uint256 offset, uint256 limit) external view returns (TokenListView[] memory) {
uint256 cnt = _tokenList.length;
uint256 total;
unchecked {
total = (offset + limit > cnt) ? (cnt - offset) : limit;
if (total > cnt) { revert ErrorInvalidRange(); }
}
TokenListView[] memory data = new TokenListView[](total);
unchecked {
uint256 j;
uint256 max = offset + total;
for (uint256 i = offset; i < max; i++) {
address token = _tokenList[i];
TokenData storage tokenData = _tokenData[token];
data[j++] = TokenListView(token, tokenData.creator, tokenData.salt);
}
}
return data;
}
function getTokenData(address token) public view isToken(token) returns (TokenDataView memory data) {
TokenData storage tokenData = _tokenData[token];
data.name = IERC20(token).name();
data.symbol = IERC20(token).symbol();
data.decimals = IERC20(token).decimals();
data.creator = tokenData.creator;
data.referral = tokenData.referral;
data.creation = tokenData.creation;
data.launch = tokenData.launch;
data.maxBalance = tokenData.maxBalance;
data.fee = tokenData.fee;
data.tax = tokenData.tax;
data.ref = tokenData.ref;
data.holders = IIncubatorToken(token).totalHolders();
data.routerIncubator = tokenData.routerIncubator;
data.pairIncubator = tokenData.pairIncubator;
data.routerFinal = tokenData.routerFinal;
data.escaped = tokenData.escaped;
data.initialSupply = tokenData.initialSupply;
data.totalSupply = IERC20(token).totalSupply();
data.ethReserveEscapeTarget = tokenData.ethReserveEscapeTarget;
data.ethReserveVirtualInitial = tokenData.ethReserveVirtualInitial;
data.tokenReserveInitial = tokenData.tokenReserveInitial;
data.creationFee = tokenData.creationFee;
data.escapeFee = tokenData.escapeFee;
data.autoEscape = tokenData.autoEscape;
if (tokenData.escaped == 0) {
data.ethReserve = uint112(IERC20(_WETH_INCUBATOR).balanceOf(tokenData.pairIncubator));
data.tokenReserve = uint112(IERC20(token).balanceOf(tokenData.pairIncubator));
} else {
data.ethReserveEscaped = tokenData.ethReserveEscaped;
data.tokenReserveEscaped = tokenData.tokenReserveEscaped;
}
}
function deployToken(bytes32 _salt, string memory _name, string memory _symbol, uint24 _maxBalance, uint24 _tax, uint32 _launch, address _routerFinal, bool _autoEscape, address _referral) external payable returns (address token) {
if (_PAUSED == 1) { revert ErrorPaused(); }
if (!_routerData[_routerFinal].enabled) { revert ErrorRouterUnavailable(_routerFinal); }
if (_referral != address(0) && (_referral == msg.sender || !_creatorData[_referral])) { revert ErrorReferral(); }
uint256 value = msg.value;
if (value < _CREATION_FEE) { revert ErrorTokenMinimumValue(_CREATION_FEE); }
if (_maxBalance < 100 && _maxBalance > 100_000) { revert ErrorTokenMaxBalance(_maxBalance); } // Min. 0.1%
if (_tax > 10_000) { revert ErrorTokenTax(_tax); } // Max. 10%
Token _token = new Token{ salt: _salt }(address(this), msg.sender, _name, _symbol, _DECIMALS, _TOTAL_SUPPLY);
token = address(_token);
TokenData storage tokenData = _tokenData[token];
tokenData.creator = msg.sender;
tokenData.salt = _salt;
tokenData.referral = _referral;
tokenData.creation = _timestamp();
tokenData.maxBalance = _maxBalance;
tokenData.fee = _SWAP_FEE;
tokenData.tax = _tax;
tokenData.launch = _launch > _timestamp() ? _launch : _timestamp();
tokenData.ref = _referral == address(0) ? uint24(0) : _REFERRAL_FEE;
tokenData.initialSupply = _TOTAL_SUPPLY;
tokenData.routerIncubator = _ROUTER_INCUBATOR;
tokenData.pairIncubator = IUniswapV2Factory(IUniswapV2Router(_ROUTER_INCUBATOR).factory()).createPair(token, _WETH_INCUBATOR);
tokenData.tokenReserveInitial = uint112(_percentage(_TOTAL_SUPPLY, uint256(_TOKEN_INITIAL_PERCENT)));
tokenData.ethReserveVirtualInitial = _ETH_RESERVE_VIRTUAL_INITIAL;
tokenData.ethReserveEscapeTarget = _ETH_RESERVE_ESCAPE_TARGET;
tokenData.routerFinal = _routerFinal;
tokenData.autoEscape = _autoEscape;
_tokenList.push(token);
_pairData[tokenData.pairIncubator] = token;
if (!_creatorData[tokenData.creator]) { _creatorData[tokenData.creator] = true; }
if (_CREATION_FEE > 0) {
tokenData.creationFee = _CREATION_FEE;
if (_TREASURY != address(0)) {
(bool success,) = _TREASURY.call{ value: tokenData.creationFee }("");
if (!success) { revert ErrorTransfer(_TREASURY, tokenData.creationFee); }
}
unchecked {
value -= _CREATION_FEE;
}
}
IIncubatorToken(token).initialize(tokenData.routerIncubator, tokenData.pairIncubator, tokenData.maxBalance, tokenData.tax, tokenData.launch, _unauthorizedList);
IERC20(token).transfer(tokenData.pairIncubator, uint256(tokenData.tokenReserveInitial));
emit TokenDeployed(token, tokenData.creator, _salt);
IIncubatorPair(tokenData.pairIncubator).initializePair(tokenData.creator, _SWAP_FEE, _tax, tokenData.ref, tokenData.launch, tokenData.tokenReserveInitial, _ETH_RESERVE_VIRTUAL_INITIAL, _ETH_RESERVE_ESCAPE_TARGET, _WETH_INCUBATOR, tokenData.referral, tokenData.autoEscape);
if (value > 0) {
address[] memory path = new address[](2);
path[0] = _WETH_INCUBATOR;
path[1] = token;
IUniswapV2Router(tokenData.routerIncubator).swapExactETHForTokensSupportingFeeOnTransferTokens{ value: value }(0, path, tokenData.creator, _timestamp());
}
}
function pairSwap(address user, bool buy, uint112 ethReserve, uint112 tokenReserve, uint256 ethAmount, uint256 tokenAmount, uint256 feeAmount, uint256 taxAmount, uint256 refAmount) external isPairOfToken() {
address token = _pairData[msg.sender];
if (_TREASURY != address(0) && feeAmount > 0) {
(bool success,) = _TREASURY.call{ value: feeAmount }("");
if (!success) { revert ErrorTransfer(_TREASURY, feeAmount); }
}
emit TokenTraded(token, _timestamp(), user, buy, ethReserve, tokenReserve, ethAmount, tokenAmount, feeAmount, taxAmount, refAmount);
}
function tokenEscape(uint256 amount) external payable isPairOfToken() {
address token = _pairData[msg.sender];
uint256 value = msg.value;
uint256 balance = IERC20(token).balanceOf(address(this));
TokenData storage tokenData = _tokenData[token];
tokenData.escaped = _timestamp();
tokenData.tokenReserveEscaped = amount;
tokenData.ethReserveEscaped = uint112(value);
if (_ESCAPE_FEE > 0) {
tokenData.escapeFee = _percentage(value, uint256(_ESCAPE_FEE));
unchecked {
value -= tokenData.escapeFee;
}
{ // scope to avoid "stack too deep" error
uint256 creatorFee;
uint256 escapeFee;
unchecked {
creatorFee = _percentage(tokenData.escapeFee, uint256(_ESCAPE_CREATOR_FEE));
escapeFee = tokenData.escapeFee - creatorFee;
}
if (_TREASURY != address(0)) {
(bool txTreasuryFee,) = _TREASURY.call{ value: escapeFee }("");
if (!txTreasuryFee) { revert ErrorTransfer(_TREASURY, escapeFee); }
}
(bool txCreatorFee,) = tokenData.creator.call{ value: creatorFee }("");
if (!txCreatorFee) { revert ErrorTransfer(tokenData.creator, creatorFee); }
}
}
IIncubatorToken(token).escape();
if (_AUTHORIZED != address(0)) {
IERC20(token).transfer(_AUTHORIZED, balance);
(bool success,) = _AUTHORIZED.call{ value: value }("");
if (!success) { revert ErrorTransfer(_AUTHORIZED, value); }
}
emit TokenEscaped(token, tokenData.escaped, tokenData.ethReserveEscaped, tokenData.tokenReserveEscaped, tokenData.escapeFee);
}
function currentStatus() external view returns (currentStatusView memory data) {
data.paused = _PAUSED;
data.decimals = _DECIMALS;
data.swapFee = _SWAP_FEE;
data.referralFee = _REFERRAL_FEE;
data.escapeFee = _ESCAPE_FEE;
data.escapeCreatorFee = _ESCAPE_CREATOR_FEE;
data.tokenInitialPercent = _TOKEN_INITIAL_PERCENT;
data.ethReserveVirtualInitial = _ETH_RESERVE_VIRTUAL_INITIAL;
data.ethReserveEscapeTarget = _ETH_RESERVE_ESCAPE_TARGET;
data.creationFee = _CREATION_FEE;
data.totalSupply = _TOTAL_SUPPLY;
data.routerIncubator = _ROUTER_INCUBATOR;
}
function setTreasury(address treasury) external onlyOwner {
_TREASURY = treasury;
}
function withdrawETH(address to, uint256 value) external onlyOwnerOrAuthorized {
(bool success,) = to.call{ value: value }("");
if (!success) { revert ErrorTransfer(to, value); }
emit WithdrawnETH(to, value);
}
function withdrawERC20(address token, address to, uint256 value) external onlyOwnerOrAuthorized {
IERC20(token).transfer(to, value);
emit WithdrawnERC20(token, to, value);
}
function _timestamp() private view returns (uint32) {
unchecked {
return uint32(block.timestamp % 2**32);
}
}
function _percentage(uint256 value, uint256 bps) private pure returns (uint256) {
unchecked {
return (value * bps) / 100_000;
}
}
receive() external payable {}
}
/*
█▀ █▀█ █▄░█ █ █▀▀ █▀▀ ▄▀█ █▀▀ ▀█▀ █▀█ █▀█ █▄█
▄█ █▄█ █░▀█ █ █▄▄ █▀░ █▀█ █▄▄ ░█░ █▄█ █▀▄ ░█░
Trade on SonicFactory and have fun!
Web: https://sonicfactory.fun/
*/
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "./ERC20.sol";
contract Token is ERC20 {
address private immutable _creator;
address private _owner;
address private _router;
address private _pair;
bool private _escaped;
bool private _initialized;
uint24 private _maxBalance;
uint24 private _tax;
uint32 private _launch;
mapping(address => bool) private _unauthorized;
struct HolderView {
address holder;
uint256 balance;
}
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
error ErrorUnauthorized(address sender);
error ErrorAlreadyInitialized();
error ErrorUnapprovable();
error ErrorMaxBalanceExceeded();
error ErrorInvalidRecipient(address to);
error ErrorInvalidRange();
modifier onlyOwner() {
if (msg.sender != _owner) { revert ErrorUnauthorized(msg.sender); }
_;
}
constructor(address _owner_, address _creator_, string memory _name_, string memory _symbol_, uint8 _decimals_, uint256 _totalSupply_) ERC20(_name_, _symbol_, _decimals_) payable {
_creator = _creator_;
_owner = _owner_;
_mint(_owner_, _totalSupply_);
}
function initialize(address _router_, address _pair_, uint24 _maxBalance_, uint24 _tax_, uint32 _launch_, address[] calldata _unauthorized_) external onlyOwner {
if (_initialized) { revert ErrorAlreadyInitialized(); }
unchecked {
uint256 cnt = _unauthorized_.length;
for (uint256 i; i < cnt; i++) { _unauthorized[_unauthorized_[i]] = true; }
}
_router = _router_;
_pair = _pair_;
_maxBalance = _maxBalance_;
_tax = _tax_;
_launch = _launch_;
_initialized = true;
}
function owner() external view returns (address) {
return _owner;
}
/// @notice Returns the creator address
function creator() external view returns (address) {
return _creator;
}
function approve(address spender, uint256 value) public override returns (bool) {
if (!_escaped && spender != _router) { revert ErrorUnapprovable(); }
return super.approve(spender, value);
}
function permit(address owner_, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public override {
if (!_escaped && spender != _router) { revert ErrorUnapprovable(); }
super.permit(owner_, spender, value, deadline, v, r, s);
}
function _transferCheck(address from, address to, uint256 value) private view {
if (_escaped || ((from == _owner && to == _pair) || ((!_escaped && to == _owner) || value == 0 || to == address(0xdEaD) || to == _router || to == _pair))) { return; }
if (!_escaped) {
if (_unauthorized[to]) { revert ErrorInvalidRecipient(to); }
unchecked {
if (_maxBalance == 100_000 || _balance[to] + value <= _percentage(_totalSupply, uint256(_maxBalance))) { return; }
}
}
revert ErrorMaxBalanceExceeded();
}
function transfer(address to, uint256 value) external virtual override returns (bool) {
_transfer(msg.sender, to, value);
return true;
}
function _transfer(address from, address to, uint256 value) internal virtual override {
_transferCheck(from, to, value);
super._transfer(from, to, value);
}
function transferFrom(address from, address to, uint256 value) public override returns (bool) {
if (!_escaped && msg.sender == _router && to == _pair && _allowance[from][_router] != type(uint256).max) { super._approve(from, _router, type(uint256).max, false); }
_transferCheck(from, to, value);
return super.transferFrom(from, to, value);
}
function totalHolders() external view returns (uint24 total) {
return _totalHolders;
}
function holders(uint256 offset, uint256 limit) public view returns (HolderView[] memory) {
if (offset >= _totalHolders) { revert ErrorInvalidRange(); }
unchecked {
if (offset + limit > _totalHolders) { limit = _totalHolders - offset; }
}
HolderView[] memory list = new HolderView[](limit);
unchecked {
uint256 j;
for (uint256 i = offset; j < limit; i++) {
address holder = _holders[i];
if (holder == address(0xdEaD) || _balance[holder] == 0) { continue; }
list[j].holder = holder;
list[j].balance = _balance[holder];
++j;
}
}
return list;
}
function maxBalance() external view returns (uint24) {
return _maxBalance;
}
function tax() external view returns (uint24) {
return _tax;
}
function launch() external view returns (uint32) {
return _launch;
}
/// @notice Returns True if token has reached the target MC and is now tradeable on a public DEX
function escaped() external view returns (bool) {
return _escaped;
}
function escape() external onlyOwner {
if (_escaped) { revert ErrorUnauthorized(msg.sender); }
if (_maxBalance < 100_000) { _maxBalance = 100_000; } // 100%
address _previousOwner = _owner;
delete _tax;
delete _owner;
delete _router;
delete _pair;
_escaped = true;
emit OwnershipTransferred(_previousOwner, _owner);
}
function _percentage(uint256 value, uint256 bps) private pure returns (uint256) {
unchecked {
return (value * bps) / 100_000;
}
}
function _timestamp() private view returns (uint32) {
unchecked {
return uint32(block.timestamp % 2**32);
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
abstract contract Ownable {
address internal _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
error ErrorUnauthorized(address sender);
modifier onlyOwner() {
if (msg.sender != _owner) { revert ErrorUnauthorized(msg.sender); }
_;
}
function renounceOwnership() external onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) external onlyOwner {
require(newOwner != address(0));
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
function owner() external view returns (address) {
return _owner;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
interface IUniswapV2Factory {
function createPair(address tokenA, address tokenB) external returns (address pair);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
interface IUniswapV2Router {
function WETH() external pure returns (address);
function factory() external pure returns (address);
function addLiquidityETH(address token, uint256 amountTokenDesired, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline) external payable returns (uint256 amountToken, uint256 amountETH, uint256 liquidity);
function swapExactETHForTokensSupportingFeeOnTransferTokens(uint256 amountOutMin, address[] calldata path, address to, uint256 deadline) external payable;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
interface IIncubatorPair {
function initializePair(address creator, uint24 fee, uint24 tax, uint24 ref, uint32 launch, uint112 tokenInitialReserve, uint112 ethInitialVirtualReserve, uint112 ethReserveEscapeTarget, address WETH, address referral, bool autoEscape) external;
function getTraderData(address user) external view returns (uint32 lastActivity, uint32 buys, uint32 sells, uint256 buy_volume, uint256 sell_volume);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
interface IIncubatorToken {
function totalHolders() external view returns (uint24);
function initialize(address router, address pair, uint24 maxBalance, uint24 tax, uint32 launch, address[] calldata unauthorized) external;
function escape() external;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
interface IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
function balanceOf(address account) external view returns (uint256);
function totalSupply() external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function approve(address spender, uint256 value) external returns (bool);
function burn(uint256 value) external returns (bool);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
abstract contract ERC20 {
uint8 private immutable _decimals;
uint24 internal _totalHolders;
uint256 internal _totalSupply;
string private _name;
string private _symbol;
bytes32 public immutable DOMAIN_SEPARATOR;
bytes32 private constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
address[] internal _holders;
mapping(address => uint256) private _nonces;
mapping(address => uint256) internal _balance;
mapping(address => mapping(address => uint256)) internal _allowance;
mapping(address => bool) internal _holderData;
event Approval(address indexed owner, address indexed spender, uint256 value);
event Transfer(address indexed from, address indexed to, uint256 value);
error ERC20InvalidApprover(address owner);
error ERC20InvalidSpender(address spender);
error ERC20InvalidSender(address sender);
error ERC20InvalidReceiver(address to);
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 value);
error ERC20InsufficientBalance(address owner, uint256 balance, uint256 value);
error ERC2612ExpiredSignature(uint256 deadline);
error ERC2612InvalidSigner(address signer, address owner);
constructor(string memory _name_, string memory _symbol_, uint8 _decimals_) {
_name = _name_;
_symbol = _symbol_;
_decimals = _decimals_;
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)));
}
function name() external view returns (string memory) {
return _name;
}
function symbol() external view returns (string memory) {
return _symbol;
}
function decimals() external view returns (uint8) {
return _decimals;
}
function totalSupply() external view returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) external view returns (uint256) {
return _balance[account];
}
function allowance(address owner, address spender) public view returns (uint256) {
return _allowance[owner][spender];
}
function approve(address spender, uint256 value) public virtual returns (bool) {
_approve(msg.sender, spender, value, true);
return true;
}
function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public virtual {
if (block.timestamp > deadline) { revert ERC2612ExpiredSignature(deadline); }
unchecked {
address signer = ecrecover(keccak256(abi.encodePacked(hex"1901", DOMAIN_SEPARATOR, keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, _nonces[owner]++, deadline)))), v, r, s);
if (signer != owner) { revert ERC2612InvalidSigner(signer, owner); }
}
_approve(owner, spender, value, true);
}
function nonces(address owner) external view returns (uint256) {
return _nonces[owner];
}
function transfer(address to, uint256 value) external virtual returns (bool) {
_transfer(msg.sender, to, value);
return true;
}
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
if (value > 0) {
address spender = msg.sender;
uint256 allowed = allowance(from, spender);
if (allowed < value) { revert ERC20InsufficientAllowance(to, allowed, value); }
if (allowed != type(uint256).max) {
unchecked {
_approve(from, spender, allowed - value, false);
}
}
}
_transfer(from, to, value);
return true;
}
function burn(uint256 value) external returns (bool) {
_transfer(msg.sender, address(0xdEaD), value);
return true;
}
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal {
if (owner == address(0)) { revert ERC20InvalidApprover(owner); }
if (spender == address(0)) { revert ERC20InvalidSpender(spender); }
_allowance[owner][spender] = value;
if (emitEvent) { emit Approval(owner, spender, value); }
}
function _transfer(address from, address to, uint256 value) internal virtual {
if (from == address(0)) { revert ERC20InvalidSender(from); }
if (to == address(0) || to == address(this)) { revert ERC20InvalidReceiver(to); }
if (_balance[from] < value) { revert ERC20InsufficientBalance(from, _balance[from], value); }
if (value > 0) {
unchecked {
_balance[from] -= value;
if (_balance[from] == 0) { --_totalHolders; }
if (to == address(0xdEaD)) {
_totalSupply -= value;
} else {
if (_balance[to] == 0) { ++_totalHolders; }
_balance[to] += value;
if (!_holderData[to]) {
_holderData[to] = true;
_holders.push(to);
}
}
}
}
emit Transfer(from, to, value);
}
function _mint(address to, uint256 value) internal {
if (to == address(0) || to == address(0xdEaD)) { revert ERC20InvalidReceiver(to); }
unchecked {
if (_balance[to] == 0) { ++_totalHolders; }
_totalSupply += value;
_balance[to] += value;
if (!_holderData[to]) {
_holderData[to] = true;
_holders.push(to);
}
}
emit Transfer(address(0), to, value);
}
}