Factory

Description:

Multi-signature wallet contract requiring multiple confirmations for transaction execution.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "src/v2/Factory.sol": {
      "content": "
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import './Indexer.sol';
import './FactoryConveyor.sol' ;
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";


contract Factory is ReentrancyGuard {
    struct TokenInfo {
        address tokenAddress;
        string name;
        string symbol;
        address deployer;
        uint256 time;
        string metadata;
        uint256 marketCapInETH;
        uint256 nftId;
        uint256 totalFeesGenerated;
    }

    IIndexer public indexer;

    mapping(uint256 => TokenInfo) public deployedTokens;
    mapping(address => TokenInfo) public tokenInfoByAddress;
    uint256 public tokenCount;
    uint256 public ethFeeGenerated;

    address public platformController;
    bool public deployCoinEnabled;
    uint256 private itemsPerPage = 500;

    mapping(address => address[]) public deployerTokens;
    mapping(address => uint256) public tokenFeesGenerated;
    mapping(address => uint256) public tokenFeesClaimed;
    mapping(address => uint256) public tokenToNFTId;
    mapping(address => address) public tokenToPool;
    mapping(address => address) public tokenCreators;

    struct LiquidityConfig {
        uint160 sqrtPriceX96;
        int24 tickLower;
        int24 tickUpper;
        uint256 amount0Desired;
        uint256 amount1Desired;
        uint256 virtualAmount;
        uint256 penaltyMultiplier;
    }

    mapping(uint256 => LiquidityConfig) public liquidityConfigs;
    uint256 public liquidityConfigCount;

    address public constant POSITION_MANAGER = UNISWAP_V3_POSITION_MANAGER;
    address public constant WETH = WETH_ADDRESS;
    address public constant SWAP_ROUTER = UNISWAP_V3_SWAP_ROUTER;
    address public FACTORY = UNISWAP_V3_FACTORY;

    uint24 private constant FEE_TIER = FEE_TIER_10000;

    address public buybackPool;
    address public devAddress;
    address public buybackToken;

    FactoryConveyor public conveyor;

    constructor(address _indexer, address _buybackPool, address _devAddress) {
        platformController = tx.origin;
        indexer = IIndexer(_indexer);

        liquidityConfigs[0] = LiquidityConfig({
           sqrtPriceX96: 175983911958351096399483062,
            tickLower: 122200,
            tickUpper: -53000,
            amount0Desired: 1000000000000000000000000,
            amount1Desired: 0,
            virtualAmount: 0,
            penaltyMultiplier: 100
        });
        liquidityConfigs[1] = LiquidityConfig({
            sqrtPriceX96: 555759188024637249212569346,
            tickLower: 99200,
            tickUpper: -30000,
            amount0Desired: 1000000000000000000000000,
            amount1Desired: 0,
            virtualAmount: 0,
            penaltyMultiplier: 100
        });
        liquidityConfigs[2] = LiquidityConfig({
            sqrtPriceX96: 1755093813046398424555436057,
            tickLower: 76000,
            tickUpper: -6800,
            amount0Desired: 1000000000000000000000000,
            amount1Desired: 0,
            virtualAmount: 0,
            penaltyMultiplier: 100
        });
        liquidityConfigCount = 3;

        if (_buybackPool != address(0)) {
            buybackPool = _buybackPool;
        }
        if (_devAddress != address(0)) {
            devAddress = _devAddress;
        }
    }

    receive() external payable {}

    function setConveyor(address _conveyor) external {
        if (msg.sender != platformController) revert NotController();
        conveyor = FactoryConveyor(_conveyor);
        indexer.authorizeAddress(_conveyor);
        conveyor.setIndexer(address(indexer));
    }

    function setBuybackPool(address pool) external {
        if (msg.sender != platformController) revert NotController();
        require(pool != address(0), "Pool is zero");
        buybackPool = pool;
    }
    function setDevAddress(address _devAddress) external {
        if (msg.sender != platformController) revert NotController();
        require(_devAddress != address(0), "Dev address is zero");
        devAddress = _devAddress;
    }

    function setIndexer(address _newIndexer) external {
        if (msg.sender != platformController) revert NotController();
        indexer = IIndexer(_newIndexer);
        if (address(conveyor) != address(0)) {
            conveyor.setIndexer(_newIndexer);
        }
    }

    function setFactory(address _factory) external {
        if (msg.sender != platformController) revert NotController();
        FACTORY = _factory;
    }

    function deployAgent(
        string memory _name,
        string memory _symbol,
        string memory _metadata,
        bytes32 saltSeed,
        uint256 configId
    ) public payable nonReentrant returns (uint256 tokensReceived) {
        if (!deployCoinEnabled) revert DeploymentDisabled();
        if (configId >= liquidityConfigCount) revert InvalidConfigId();
        require(address(conveyor) != address(0), "Conveyor not set");

        (bytes32 chosenSalt, address predicted) = conveyor.findSaltTokenLTWETH(
            _name,
            _symbol,
            saltSeed
        );

        (address coinAddress, address predicted2) = conveyor.deployToken(
            _name,
            _symbol,
            chosenSalt,
            msg.sender
        );
        require(
            coinAddress == predicted && predicted2 == predicted,
            "Predicted mismatch"
        );

        tokenCreators[coinAddress] = msg.sender;
        _setupLiquidity(coinAddress, configId);
        tokensReceived = _handleInitialBuy(coinAddress, configId);
        _storeTokenInfo(coinAddress, _name, _symbol, _metadata);

        return tokensReceived;
    }

    function _setupLiquidity(address coinAddress, uint256 configId) internal {
        provideLiquidity(coinAddress, WETH, configId);
    }

    function _toHex(bytes memory buffer) public pure returns (string memory) {
        // Fixed buffer size for hexadecimal convertion
        bytes memory converted = new bytes(buffer.length * 2);

        bytes memory _base = "0123456789abcdef";

        for (uint256 i = 0; i < buffer.length; i++) {
            converted[i * 2] = _base[uint8(buffer[i]) / _base.length];
            converted[i * 2 + 1] = _base[uint8(buffer[i]) % _base.length];
        }

        return string(abi.encodePacked("0x", converted));
    }

    function _handleInitialBuy(
        address coinAddress,
        uint256 /* configId */
    ) internal returns (uint256) {
        if (msg.value == 0) return 0;

        // 0) Preflight: ensure the router will target the same pool we created
        address expected = IUniswapV3Factory(FACTORY).getPool(
            coinAddress,
            WETH,
            FEE_TIER
        );
        require(expected != address(0), "initial buy: pool not found for fee");
        require(
            expected == tokenToPool[coinAddress],
            "initial buy: router/factory pool mismatch"
        );
        require(expected.code.length > 0, "initial buy: pool has no code");
        require(
            IUniswapV3PoolState(expected).liquidity() > 0,
            "initial buy: pool has zero active liquidity"
        );

        // 1) Wrap ETH -> WETH locally
        IWETH(WETH).deposit{value: msg.value}();

        // 2) Approve router if needed
        if (IERC20(WETH).allowance(address(this), SWAP_ROUTER) < msg.value) {
            IERC20(WETH).approve(SWAP_ROUTER, type(uint256).max);
        }

        // 3) Swap WETH -> token (no native value forwarded)
        ISwapRouter02.ExactInputSingleParams memory params = ISwapRouter02
            .ExactInputSingleParams({
                tokenIn: WETH,
                tokenOut: coinAddress,
                fee: FEE_TIER,
                recipient: address(this),
                amountIn: msg.value,
                amountOutMinimum: 0,
                sqrtPriceLimitX96: 0
            });

        uint256 amountOut;
        try ISwapRouter02(SWAP_ROUTER).exactInputSingle(params) returns (
            uint256 out
        ) {
            amountOut = out;
        } catch Error(string memory reason) {
            revert(string.concat("initial buy swap failed: ", reason));
        } catch (bytes memory data) {
            // data may be empty when the router called a non-existent pool
            // _toHex(data) already has a 0x prefix; don't add another
            revert(
                string.concat("initial buy swap failed (raw): ", _toHex(data))
            );
        }

        // 4) Send the bought tokens to the deployer
        IERC20(coinAddress).transfer(msg.sender, amountOut);

        // 5) Analytics/event
        indexer.emitTokenPurchased(
            msg.sender,
            coinAddress,
            msg.value,
            amountOut
        );

        return amountOut;
    }

    function _storeTokenInfo(
        address coinAddress,
        string memory name,
        string memory symbol,
        string memory metadata
    ) internal {
        TokenInfo memory newTokenInfo = TokenInfo({
            tokenAddress: coinAddress,
            name: name,
            symbol: symbol,
            deployer: msg.sender,
            time: block.timestamp,
            metadata: metadata,
            marketCapInETH: 0,
            nftId: tokenToNFTId[coinAddress],
            totalFeesGenerated: 0
        });

        deployedTokens[tokenCount] = newTokenInfo;
        tokenInfoByAddress[coinAddress] = newTokenInfo;
        deployerTokens[msg.sender].push(coinAddress);
        unchecked {
            ++tokenCount;
        }
    }

    function getPenalty(uint256 ethAmount) public pure returns (uint256) {
        if (ethAmount < 0.05 ether) return 0;
        if (ethAmount >= 0.30 ether) return 5000;
        uint256 slope = 18000;
        uint256 delta = ethAmount - 0.05 ether;
        return 500 + (delta * slope) / 1 ether;
    }

    function getAllTokensByDeployer(
        address _deployer
    ) public view returns (address[] memory) {
        return deployerTokens[_deployer];
    }

    function getDeploysByPage(
        uint256 page,
        uint256 order
    ) public view returns (TokenInfo[] memory) {
        if (tokenCount == 0) revert NoTokensDeployed();

        uint256 totalPages = (tokenCount + itemsPerPage - 1) / itemsPerPage;
        if (page >= totalPages) revert PageOutOfRange();

        uint256 start;
        uint256 end;
        uint256 j;

        if (order == 0) {
            start = tokenCount > (page + 1) * itemsPerPage
                ? tokenCount - (page + 1) * itemsPerPage
                : 0;
            end = tokenCount - page * itemsPerPage;
            if (end > tokenCount) end = tokenCount;
        } else {
            start = page * itemsPerPage;
            end = start + itemsPerPage;
            if (end > tokenCount) end = tokenCount;
        }

        TokenInfo[] memory tokens = new TokenInfo[](end - start);

        for (uint256 i = start; i < end; ) {
            uint256 index = order == 0 ? end - 1 - (i - start) : i;
            TokenInfo memory info = deployedTokens[index];

            uint256 marketCap = getTokenMarketCap(info.tokenAddress);

            tokens[j++] = TokenInfo({
                tokenAddress: info.tokenAddress,
                name: info.name,
                symbol: info.symbol,
                deployer: info.deployer,
                time: info.time,
                metadata: info.metadata,
                marketCapInETH: marketCap,
                nftId: info.nftId,
                totalFeesGenerated: tokenFeesGenerated[info.tokenAddress]
            });
            unchecked {
                ++i;
            }
        }

        return tokens;
    }

    function toggleDeployCoin() external {
        if (msg.sender != platformController) revert NotController();
        deployCoinEnabled = !deployCoinEnabled;
    }

    function setItemsPerPage(uint256 _itemsPerPage) external {
        if (msg.sender != platformController) revert NotController();
        if (_itemsPerPage == 0 || _itemsPerPage > 1000)
            revert ItemsPerPageRange();
        itemsPerPage = _itemsPerPage;
    }

    function setTokenCreator(address token, address newCreator) external {
        if (msg.sender != platformController) revert NotController();
        tokenCreators[token] = newCreator;
    }

    function createLiquidityConfig(
        uint160 _sqrtPriceX96,
        int24 _tickLower,
        int24 _tickUpper,
        uint256 _amount0Desired,
        uint256 _amount1Desired,
        uint256 _virtualAmount,
        uint256 _penaltyMultiplier
    ) external returns (uint256 configId) {
        if (msg.sender != platformController) revert NotController();
        if (_penaltyMultiplier < 10 || _penaltyMultiplier > 500)
            revert PenaltyMultiplierRange();

        configId = liquidityConfigCount;
        liquidityConfigs[configId] = LiquidityConfig({
            sqrtPriceX96: _sqrtPriceX96,
            tickLower: _tickLower,
            tickUpper: _tickUpper,
            amount0Desired: _amount0Desired,
            amount1Desired: _amount1Desired,
            virtualAmount: _virtualAmount,
            penaltyMultiplier: _penaltyMultiplier
        });
        unchecked {
            ++liquidityConfigCount;
        }
        return configId;
    }

    function updateLiquidityConfig(
        uint256 _configId,
        uint160 _sqrtPriceX96,
        int24 _tickLower,
        int24 _tickUpper,
        uint256 _amount0Desired,
        uint256 _amount1Desired,
        uint256 _virtualAmount,
        uint256 _penaltyMultiplier
    ) external {
        if (msg.sender != platformController) revert NotController();
        if (_configId >= liquidityConfigCount) revert InvalidConfigId();
        if (_penaltyMultiplier < 10 || _penaltyMultiplier > 500)
            revert PenaltyMultiplierRange();

        liquidityConfigs[_configId] = LiquidityConfig({
            sqrtPriceX96: _sqrtPriceX96,
            tickLower: _tickLower,
            tickUpper: _tickUpper,
            amount0Desired: _amount0Desired,
            amount1Desired: _amount1Desired,
            virtualAmount: _virtualAmount,
            penaltyMultiplier: _penaltyMultiplier
        });
    }

    function deleteLiquidityConfig(uint256 _configId) external {
        if (msg.sender != platformController) revert NotController();
        if (_configId >= liquidityConfigCount || _configId == 0)
            revert InvalidConfigId();
        delete liquidityConfigs[_configId];
    }

    function getLiquidityConfig(
        uint256 _configId
    ) external view returns (LiquidityConfig memory) {
        require(_configId < liquidityConfigCount, "Invalid config ID");
        return liquidityConfigs[_configId];
    }

    function provideLiquidity(
        address tokenA,
        address tokenB,
        uint256 configId
    ) internal {
        if (tokenA >= tokenB) revert TokenMustBeToken0();
        LiquidityConfig memory config = liquidityConfigs[configId];

        address token0 = tokenA;
        address token1 = tokenB;

        IERC20(token0).approve(POSITION_MANAGER, type(uint256).max);
        IERC20(token1).approve(POSITION_MANAGER, type(uint256).max);

        INonfungiblePositionManager manager = INonfungiblePositionManager(
            POSITION_MANAGER
        );

        int24 tickLower = -config.tickLower;
        int24 tickUpper = config.tickUpper;

        address pool = manager.createAndInitializePoolIfNecessary(
            token0,
            token1,
            FEE_TIER,
            config.sqrtPriceX96
        );
        tokenToPool[token0] = pool;

        (uint256 tokenId, , , ) = manager.mint(
            INonfungiblePositionManager.MintParams({
                token0: token0,
                token1: token1,
                fee: FEE_TIER,
                tickLower: tickLower,
                tickUpper: tickUpper,
                amount0Desired: config.amount0Desired,
                amount1Desired: config.amount1Desired,
                amount0Min: 0,
                amount1Min: 0,
                recipient: address(this),
                deadline: block.timestamp
            })
        );

        _storeNFTId(tokenA, tokenId);
    }

    function collectFeesAndBuyback(
        address tokenAddress
    )
        external
        nonReentrant
        returns (
            uint256 tokenFeesCollected,
            uint256 wethFeesCollected,
            uint256 creatorETHPaid
        )
    {
        uint256 tokenId = tokenToNFTId[tokenAddress];
        if (tokenId == 0) revert NoPosition();

        address pool = tokenToPool[tokenAddress];
        require(pool != address(0), "No pool");
        address token0 = IUniswapV3PoolTokens(pool).token0();
        address token1 = IUniswapV3PoolTokens(pool).token1();

        if (token0 == WETH && token1 != WETH) {
            (token0, token1) = (token1, token0);
        }
        if (token1 != WETH) revert MustBeWETH();

        uint256 beforeToken0 = IERC20(token0).balanceOf(address(this));
        uint256 beforeToken1 = IERC20(token1).balanceOf(address(this));

        INonfungiblePositionManager(POSITION_MANAGER).collect(
            INonfungiblePositionManager.CollectParams({
                tokenId: tokenId,
                recipient: address(this),
                amount0Max: type(uint128).max,
                amount1Max: type(uint128).max
            })
        );

        uint256 collected0 = IERC20(token0).balanceOf(address(this)) -
            beforeToken0;
        uint256 collected1 = IERC20(token1).balanceOf(address(this)) -
            beforeToken1;

        tokenFeesCollected = collected0;
        wethFeesCollected = collected1;
        ethFeeGenerated += collected1;

        if (collected1 > 0) {
            _trackTokenFees(token0, collected1);
            tokenFeesClaimed[token0] += collected1;
        }

        // Always burn non-ETH token fees
        if (collected0 > 0) {
            _burnOrSendToDead(token0, collected0);
        }

        uint256 platformWeth = 0;
        if (collected1 > 0) {
            address creator = tokenCreators[token0];
            if (creator != address(0)) {
                uint256 creatorAmount = (collected1 * 20) / 100;
                platformWeth = collected1 - creatorAmount;

                IWETH(WETH).withdraw(creatorAmount);
                (bool ok, ) = payable(creator).call{value: creatorAmount}("");
                require(ok, "Creator payout failed");
                creatorETHPaid = creatorAmount;
            } else {
                platformWeth = collected1;
            }
        }

        if (devAddress != address(0) && platformWeth > 0) {
            uint256 devAmount = (platformWeth * 20) / 100;
            platformWeth -= devAmount;

            IWETH(WETH).withdraw(devAmount);
            (bool ok, ) = payable(devAddress).call{value: devAmount}("");
            require(ok, "Dev payout failed");
        }

        if (buybackPool != address(0) && platformWeth > 0) {
            IWETH(WETH).withdraw(platformWeth);
            (bool ok, ) = payable(buybackPool).call{value: platformWeth}("");
            require(ok, "Buyback payout failed");
        }

        indexer.emitFeesCollected(tokenId, token0, collected0, collected1);
    }

    function withdrawFeesWETH() external {
        if (msg.sender != platformController) revert NotController();

        uint256 wethBalance = IERC20(WETH).balanceOf(address(this));
        if (wethBalance == 0) revert NoWETHToWithdraw();

        IWETH(WETH).withdraw(wethBalance);

        (bool success, ) = msg.sender.call{value: wethBalance}("");
        require(success, "ETH transfer failed");
    }

    function withdrawFeesETH() external {
        if (msg.sender != platformController) revert NotController();

        uint256 ethBalance = address(this).balance;
        if (ethBalance == 0) revert NoETHToWithdraw();

        (bool success, ) = msg.sender.call{value: ethBalance}("");
        require(success, "ETH transfer failed");
    }

    function getTokenFeesGenerated(
        address tokenAddress
    ) public view returns (uint256) {
        return tokenFeesGenerated[tokenAddress];
    }

    function getTokenFeesClaimed(
        address tokenAddress
    ) public view returns (uint256) {
        return tokenFeesClaimed[tokenAddress];
    }

    function _trackTokenFees(address token, uint256 amount) internal {
        tokenFeesGenerated[token] += amount;
    }

    function _storeNFTId(address token, uint256 nftId) internal {
        tokenToNFTId[token] = nftId;
    }

    function _burnOrSendToDead(address token, uint256 amount) internal {
        if (amount == 0) return;
        try ERC20Burnable(token).burn(amount) {} catch {
            IERC20(token).transfer(
                0x000000000000000000000000000000000000dEaD,
                amount
            );
        }
    }
function getTokenStats(
    address tokenAddress
) external view returns (

    uint256 marketCapInETH,
    uint256 totalFeesGenerated,
    address creatorAddress
) {
    creatorAddress = tokenCreators[tokenAddress];
    uint256 currentMarketCap = getTokenMarketCap(tokenAddress);
    uint256 feesGenerated = tokenFeesGenerated[tokenAddress];

    return (
        currentMarketCap,
        feesGenerated,
        creatorAddress
    );
}

    function getTokenMarketCap(
        address tokenAddress
    ) public view returns (uint256 marketCapInWETH) {
        address WETH = INonfungiblePositionManager(POSITION_MANAGER).WETH9();
        address factory = INonfungiblePositionManager(POSITION_MANAGER)
            .factory();

        address pool = IUniswapV3Factory(factory).getPool(
            tokenAddress,
            WETH,
            FEE_TIER
        );
        if (pool == address(0)) return 0;

        uint256 totalSupply = IERC20(tokenAddress).totalSupply();
        (uint160 sqrtPriceX96, , , , , , ) = IUniswapV3Pool(pool).slot0();

        if (sqrtPriceX96 == 0 || totalSupply == 0) return 0;

        bool tokenIsToken0 = tokenAddress < WETH;

        if (tokenIsToken0) {
            uint256 priceX192 = uint256(sqrtPriceX96) * uint256(sqrtPriceX96);
            marketCapInWETH = Math.mulDiv(totalSupply, priceX192, 1 << 192);

        } else {
            uint256 priceX192 = uint256(sqrtPriceX96) * uint256(sqrtPriceX96);
            marketCapInWETH = Math.mulDiv(totalSupply, 1 << 192, priceX192);
        }
    }
}"
    },
    "src/v2/Indexer.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "./Factory.sol";


contract Indexer {
    event ERC20TokenCreated(
        address indexed tokenAddress,
        address indexed deployer,
        uint256 timestamp
    );
    event SaltBruteforced(
        bytes32 indexed usedSalt,
        address indexed predictedToken
    );
    event FeesCollected(
        uint256 indexed tokenId,
        address indexed token,
        uint256 tokenAmount,
        uint256 ethAmount
    );
    event TokenPurchased(
        address indexed buyer,
        address indexed tokenOut,
        uint256 ethSpent,
        uint256 tokensReceived
    );

    event Buy(
        address indexed buyer,
        address indexed pool,
        address indexed token,
        uint256 amountTokens,
        uint160 sqrtPriceX96,
        uint256 priceX96,
        uint256 ethAmount,
        uint256 totalFeesETH,
        uint256 totalFeesToken
    );
    event Sell(
        address indexed seller,
        address indexed pool,
        address indexed token,
        uint256 amountTokens,
        uint160 sqrtPriceX96,
        uint256 priceX96,
        uint256 ethAmount,
        uint256 totalFeesETH,
        uint256 totalFeesToken
    );
    event BuybackExecuted(
        address indexed targetToken,
        uint256 wethSpent,
        uint256 tokensBurned
    );

    error NotAuthorized();

    mapping(address => bool) public authorizedAddresses;
    address public factory;

    constructor() {
        authorizedAddresses[msg.sender] = true;
    }

    modifier onlyAuthorized() {
        if (!authorizedAddresses[msg.sender]) revert NotAuthorized();
        _;
    }

    function setFactory(address _factory) external onlyAuthorized() {
        require(_factory != address(0), "Factory address is zero");
        factory = _factory;
        authorizedAddresses[_factory] = true;
    }

    function authorizeAddress(address _address) external onlyAuthorized {
        authorizedAddresses[_address] = true;
    }

    function revokeAddress(address _address) external onlyAuthorized {
        authorizedAddresses[_address] = false;
    }

    function emitERC20TokenCreated(
        address tokenAddress,
        address deployer
    ) external onlyAuthorized {
        emit ERC20TokenCreated(tokenAddress, deployer, block.timestamp);
    }

    function emitSaltBruteforced(
        bytes32 usedSalt,
        address predictedToken
    ) external onlyAuthorized {
        emit SaltBruteforced(usedSalt, predictedToken);
    }

    function emitFeesCollected(
        uint256 tokenId,
        address token,
        uint256 tokenAmount,
        uint256 ethAmount
    ) external onlyAuthorized {
        emit FeesCollected(tokenId, token, tokenAmount, ethAmount);
    }

    function emitTokenPurchased(
        address buyer,
        address tokenOut,
        uint256 ethSpent,
        uint256 tokensReceived
    ) external onlyAuthorized {
        emit TokenPurchased(buyer, tokenOut, ethSpent, tokensReceived);
    }

    function emitBuy(
        address buyer,
        address pool,
        address token,
        uint256 amountTokens,
        uint160 sqrtPriceX96,
        uint256 priceX96,
        uint256 ethAmount,
        uint256 totalFeesETH,
        uint256 totalFeesToken
    ) external onlyAuthorized {
        emit Buy(
            buyer,
            pool,
            token,
            amountTokens,
            sqrtPriceX96,
            priceX96,
            ethAmount,
            totalFeesETH,
            totalFeesToken
        );
    }

    function emitSell(
        address seller,
        address pool,
        address token,
        uint256 amountTokens,
        uint160 sqrtPriceX96,
        uint256 priceX96,
        uint256 ethAmount,
        uint256 totalFeesETH,
        uint256 totalFeesToken
    ) external onlyAuthorized {
        emit Sell(
            seller,
            pool,
            token,
            amountTokens,
            sqrtPriceX96,
            priceX96,
            ethAmount,
            totalFeesETH,
            totalFeesToken
        );
    }

    function emitBuybackExecuted(
        address targetToken,
        uint256 wethSpent,
        uint256 tokensBurned
    ) external onlyAuthorized {
        emit BuybackExecuted(targetToken, wethSpent, tokensBurned);
    }
}
"
    },
    "src/v2/FactoryConveyor.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "./Token.sol";

contract FactoryConveyor {
    address public immutable factory;
    address public immutable WETH = WETH_ADDRESS;
    uint256 public constant MAX_SALT_TRIES = 1024;

    IIndexer public indexer;

    error OnlyFactory();

    modifier onlyFactory() {
        if (msg.sender != factory) revert OnlyFactory();
        _;
    }

    constructor(address _factory, address _indexer) {
        factory = _factory;
        indexer = IIndexer(_indexer);
    }

    function setIndexer(address _newIndexer) external onlyFactory {
        indexer = IIndexer(_newIndexer);
    }

    function _tokenInitCode(
        string memory name,
        string memory symbol
    ) internal view returns (bytes memory) {
        return
            abi.encodePacked(
                type(AgentToken).creationCode,
                abi.encode(name, symbol, factory, address(indexer))
            );
    }

    function _predictCreate2(
        bytes32 salt,
        bytes32 initCodeHash
    ) internal view returns (address) {
        bytes32 h = keccak256(
            abi.encodePacked(bytes1(0xff), address(this), salt, initCodeHash)
        );
        return address(uint160(uint256(h)));
    }

    function getTokenBytecode(
        string memory name,
        string memory symbol
    ) external view returns (bytes memory) {
        return _tokenInitCode(name, symbol);
    }

    function findSaltTokenLTWETH(
        string memory name,
        string memory symbol,
        bytes32 baseSalt
    ) external view onlyFactory returns (bytes32 saltFound, address predicted) {
        bytes memory initCode = _tokenInitCode(name, symbol);
        bytes32 initHash = keccak256(initCode);
        uint160 wethNum = uint160(WETH);

        for (uint256 i; i < MAX_SALT_TRIES; ) {
            bytes32 saltCand = keccak256(abi.encodePacked(baseSalt, i));
            address addr = _predictCreate2(saltCand, initHash);
            if (uint160(addr) < wethNum) {
                return (saltCand, addr);
            }
            unchecked {
                ++i;
            }
        }
        revert SaltSearchFailed();
    }

    function deployToken(
        string memory name,
        string memory symbol,
        bytes32 salt,
        address originalDeployer
    ) external onlyFactory returns (address token, address predicted) {
        bytes memory initCode = _tokenInitCode(name, symbol);
        bytes32 initHash = keccak256(initCode);

        AgentToken t = new AgentToken{salt: salt}(
            name,
            symbol,
            factory,
            address(indexer)
        );
        token = address(t);

        predicted = _predictCreate2(salt, initHash);
        require(token == predicted, "CREATE2 address mismatch");

        indexer.emitSaltBruteforced(salt, token);
        indexer.emitERC20TokenCreated(token, originalDeployer);
        indexer.authorizeAddress(token);
    }
}
"
    },
    "lib/v4-core/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol": {
      "content": "// 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;
    }
}
"
    },
    "src/v2/Token.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";



//  $$$$$$\                       $$\
// $$  __$$\                      $$ |
// $$ /  \__|$$\   $$\ $$$$$$$\ $$$$$$\    $$$$$$\   $$$$$$\
// \$$$$$$\  $$ |  $$ |$$  __$$\\_$$  _|  $$  __$$\ $$  __$$\
//  \____$$\ $$ |  $$ |$$ |  $$ | $$ |    $$ /  $$ |$$ |  \__|
// $$\   $$ |$$ |  $$ |$$ |  $$ | $$ |$$\ $$ |  $$ |$$ |
// \$$$$$$  |\$$$$$$$ |$$ |  $$ | \$$$$  |\$$$$$$  |$$ |
//  \______/  \____$$ |\__|  \__|  \____/  \______/ \__|
//           $$\   $$ |
//           \$$$$$$  |
//            \______/

address constant WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address constant UNISWAP_V3_POSITION_MANAGER = 0xC36442b4a4522E871399CD717aBDD847Ab11FE88;
address constant UNISWAP_V3_FACTORY = 0x1F98431c8aD98523631AE4a59f267346ea31F984;
address constant UNISWAP_V3_SWAP_ROUTER = 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45;
uint24 constant FEE_TIER_10000 = 10000;

interface IWETH {
    function deposit() external payable;

    function withdraw(uint256 amount) external;
}

interface IUniswapV3PoolState {
    function liquidity() external view returns (uint128);
}

interface IUniswapV3Factory {
    function getPool(
        address tokenA,
        address tokenB,
        uint24 fee
    ) external view returns (address);
}

interface IUniswapV3Pool {
    function slot0()
        external
        view
        returns (
            uint160 sqrtPriceX96,
            int24 tick,
            uint16 observationIndex,
            uint16 observationCardinality,
            uint16 observationCardinalityNext,
            uint32 feeProtocol,
            bool unlocked
        );

    function feeGrowthGlobal0X128() external view returns (uint256);

    function feeGrowthGlobal1X128() external view returns (uint256);
}

interface IUniswapV3PoolTokens {
    function token0() external view returns (address);

    function token1() external view returns (address);
}

interface ISwapRouter02 {
    struct ExactInputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint256 amountIn;
        uint256 amountOutMinimum;
        uint160 sqrtPriceLimitX96;
    }

    function exactInputSingle(
        ExactInputSingleParams calldata params
    ) external payable returns (uint256 amountOut);
}

interface INonfungiblePositionManager {
    struct MintParams {
        address token0;
        address token1;
        uint24 fee;
        int24 tickLower;
        int24 tickUpper;
        uint256 amount0Desired;
        uint256 amount1Desired;
        uint256 amount0Min;
        uint256 amount1Min;
        address recipient;
        uint256 deadline;
    }

    function factory() external view returns (address);

    function WETH9() external view returns (address);

    function positions(
        uint256 tokenId
    )
        external
        view
        returns (
            uint96 nonce,
            address operator,
            address token0,
            address token1,
            uint24 fee,
            int24 tickLower,
            int24 tickUpper,
            uint128 liquidity,
            uint256 feeGrowthInside0LastX128,
            uint256 feeGrowthInside1LastX128,
            uint128 tokensOwed0,
            uint128 tokensOwed1
        );

    function createAndInitializePoolIfNecessary(
        address token0,
        address token1,
        uint24 fee,
        uint160 sqrtPriceX96
    ) external returns (address pool);

    function mint(
        MintParams calldata params
    )
        external
        returns (
            uint256 tokenId,
            uint128 liquidity,
            uint256 amount0,
            uint256 amount1
        );

    struct CollectParams {
        uint256 tokenId;
        address recipient;
        uint128 amount0Max;
        uint128 amount1Max;
    }

    function collect(
        CollectParams calldata params
    ) external payable returns (uint256 amount0, uint256 amount1);
}

interface IFactoryPoolView {
    function tokenToPool(address token) external view returns (address);
}

interface IIndexer {
    function emitERC20TokenCreated(
        address tokenAddress,
        address deployer
    ) external;

    function emitSaltBruteforced(
        bytes32 usedSalt,
        address predictedToken
    ) external;

    function emitFeesCollected(
        uint256 tokenId,
        address token,
        uint256 tokenAmount,
        uint256 ethAmount
    ) external;

    function emitTokenPurchased(
        address buyer,
        address tokenOut,
        uint256 ethSpent,
        uint256 tokensReceived
    ) external;

    function emitBuy(
        address buyer,
        address pool,
        address token,
        uint256 amountTokens,
        uint160 sqrtPriceX96,
        uint256 priceX96,
        uint256 ethAmount,
        uint256 totalFeesETH,
        uint256 totalFeesToken
    ) external;

    function emitSell(
        address seller,
        address pool,
        address token,
        uint256 amountTokens,
        uint160 sqrtPriceX96,
        uint256 priceX96,
        uint256 ethAmount,
        uint256 totalFeesETH,
        uint256 totalFeesToken
    ) external;

    function authorizeAddress(address _contract) external;
}

error NotController();
error DeploymentDisabled();
error InvalidConfigId();
error SaltSearchFailed();
error TokenMustBeToken0();
error MustBeWETH();
error NoWETHToWithdraw();
error NoETHToWithdraw();
error BatchRange();
error ItemsPerPageRange();
error PenaltyMultiplierRange();
error NoTokensDeployed();
error PageOutOfRange();
error InternalOnly();
error NoPosition();
error NotAuthorized();

contract AgentToken is ERC20, ERC20Burnable {
    using Math for uint256;

    address public platform;
    IIndexer public indexer;
    uint256 private launchBlock;
    uint256 private maxTxAmount;
    uint256 private constant LAUNCH_PERIOD = 5;
    uint256 private constant MAX_WALLET_PERCENTAGE = 2;

    address public constant POSITION_MANAGER = UNISWAP_V3_POSITION_MANAGER;
    address public constant WETH = WETH_ADDRESS;

    mapping(address => uint256) private tokensFromPoolPerOrigin;

    constructor(
        string memory _name,
        string memory _symbol,
        address _platform,
        address _indexer
    ) ERC20(_name, _symbol) {
        platform = _platform;
        indexer = IIndexer(_indexer);
        launchBlock = block.number;

        uint256 totalTokens = 1_000_000 * 10 ** decimals();
        maxTxAmount = (totalTokens * MAX_WALLET_PERCENTAGE) / 100;

        _mint(_platform, totalTokens);
    }

    function owner() public pure returns (address) {
        return address(0);
    }

    function _update(
        address from,
        address to,
        uint256 value
    ) internal override {
        if (
            block.number > launchBlock &&
            block.number <= launchBlock + LAUNCH_PERIOD
        ) {
            address factory = INonfungiblePositionManager(POSITION_MANAGER)
                .factory();
            address pool = IUniswapV3Factory(factory).getPool(
                address(this),
                WETH,
                FEE_TIER_10000
            );

            if (from == pool && to != platform) {
                tokensFromPoolPerOrigin[tx.origin] += value;
                require(
                    tokensFromPoolPerOrigin[tx.origin] <=
                        (maxTxAmount * 110) / 100,
                    "Keeping 2% pool Limits In Kontrol"
                );
            }

            if (to != platform && to != pool && from != address(0)) {
                require(
                    balanceOf(to) + value <= maxTxAmount,
                    "Max wallet limit exceeded during launch period"
                );
            }
        }

        if (
            block.number == launchBlock &&
            from != address(0) &&
            to != platform &&
            from != platform
        ) {
            revert("No buys allowed during launch block!");
        }

        super._update(from, to, value);

        address factoryPool = IFactoryPoolView(platform).tokenToPool(
            address(this)
        );
        if (
            factoryPool != address(0) &&
            (from == factoryPool || to == factoryPool)
        ) {
            (uint160 sqrtPriceX96, , , , , , ) = IUniswapV3Pool(factoryPool)
                .slot0();
            uint256 priceX96 = Math.mulDiv(
                uint256(sqrtPriceX96),
                uint256(sqrtPriceX96),
                1 << 96
            );

            uint256 feeGrowthETH = IUniswapV3Pool(factoryPool)
                .feeGrowthGlobal1X128();
            uint256 feeGrowthToken = IUniswapV3Pool(factoryPool)
                .feeGrowthGlobal0X128();

             bool tokenIsToken0 = address(this) < WETH;
        uint256 ethAmount;
        
        if (tokenIsToken0) {
            uint256 priceX192 = Math.mulDiv(uint256(sqrtPriceX96), uint256(sqrtPriceX96), 1);
            ethAmount = Math.mulDiv(value, priceX192, 1 << 192);
        } else {
            uint256 priceX192 = Math.mulDiv(uint256(sqrtPriceX96), uint256(sqrtPriceX96), 1);
            ethAmount = Math.mulDiv(value, 1 << 192, priceX192);
        }


            if (from == factoryPool && to != address(0)) {
                try
                    indexer.emitBuy(
                        to,
                        factoryPool,
                        address(this),
                        value,
                        sqrtPriceX96,
                        priceX96,
                        ethAmount,
                        feeGrowthETH,
                        feeGrowthToken
                    )
                {} catch {}
            } else if (to == factoryPool && from != address(0)) {
                try
                    indexer.emitSell(
                        from,
                        factoryPool,
                        address(this),
                        value,
                        sqrtPriceX96,
                        priceX96,
                        ethAmount,
                        feeGrowthETH,
                        feeGrowthToken
                    )
                {} catch {}
            }
        }
    }

    function getTokenPair() public view returns (address, address, address) {
        address find_factory = INonfungiblePositionManager(POSITION_MANAGER)
            .factory();
        address find_pool = IUniswapV3Factory(find_factory).getPool(
            address(this),
            WETH,
            FEE_TIER_10000
        );
        return (find_pool, address(this), find_factory);
    }

    function isLaunchPeriodActive() public view returns (bool) {
        return block.number <= launchBlock + LAUNCH_PERIOD;
    }
}


"
    },
    "lib/v4-core/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Burnable.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Extension of {ERC20} that allows token holders to destroy both their own
 * tokens and those that they have an allowance for, in a way that can be
 * recognized off-chain (via event analysis).
 */
abstract contract ERC20Burnable is Context, ERC20 {
    /**
     * @dev Destroys a `value` amount of tokens from the caller.
     *
     * See {ERC20-_burn}.
     */
    function burn(uint256 value) public virtual {
        _burn(_msgSender(), value);
    }

    /**
     * @dev Destroys a `value` amount of tokens from `account`, deducting from
     * the caller's allowance.
     *
     * See {ERC20-_burn} and {ERC20-allowance}.
     *
     * Requirements:
     *
     * - the caller must have allowance for ``accounts``'s tokens of at least
     * `value`.
     */
    function burnFrom(address account, uint256 value) public virtual {
        _spendAllowance(account, _msgSender(), value);
        _burn(account, value);
    }
}
"
    },
    "lib/v4-core/lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../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 private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the default value returned by this function, unless
     * it's overridden.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `value`.
     */
    function transfer(address to, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, value);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, value);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `value`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `value`.
     */
    function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, value);
        _transfer(from, to, value);
        return true;
    }

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _transfer(address from, address to, uint256 value) internal {
        if (from == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        if (to == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(from, to, value);
    }

    /**
     * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
     * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
     * this function.
     *
     * Emits a {Transfer} event.
     */
    function _update(address from, address to, uint256 value) internal virtual {
        if (from == address(0)) {
            // Overflow check required: The rest of the code assumes that totalSupply never overflows
            _totalSupply += value;
        } else {
            uint256 fromBalance = _balances[from];
            if (fromBalance < value) {
                revert ERC20InsufficientBalance(from, fromBalance, value);
            }
            unchecked {
                // Overflow not possible: value <= fromBalance <= totalSupply.
                _balances[from] = fromBalance - value;
            }
        }

        if (to == address(0)) {
            unchecked {
                // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
                _totalSupply -= value;
            }
        } else {
            unchecked {
                // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
                _balances[to] += value;
            }
        }

        emit Transfer(from, to, value);
    }

    /**
     * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
     * Relies on the `_update` mechanism
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _mint(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(address(0), account, value);
    }

    /**
     * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
     * Relies on the `_update` mechanism.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead
     */
    function _burn(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        _update(account, address(0), value);
    }

    /**
     * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     *
     * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
     */
    function _approve(address owner, address spender, uint256 value) internal {
        _approve(owner, spender, value, true);
    }

    /**
     * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
     *
     * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
     * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
     * `Approval` event during `transferFrom` operations.
     *
     * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
     * true using the following override:
     * ```
     * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
     *     super._approve(owner, spender, value, true);
     * }
     * ```
     *
     * Requirements are the same as {_approve}.
     */
    function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
        if (owner == address(0)) {
            revert ERC20InvalidApprover(address(0));
        }
        if (spender == address(0)) {
            revert ERC20InvalidSpender(address(0));
        }
        _allowances[owner][spender] = value;
        if (emitEvent) {
            emit Approval(owner, spender, value);
        }
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `value`.
     *
     * Does not update the allowance value in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Does not emit an {Approval} event.
     */
    function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            if (currentAllowance < value) {
                revert ERC20InsufficientAllowance(spender, currentAllowance, value);
            }
            unchecked {
                _approve(owner, spender, currentAllowance - value, false);
            }
        }
    }
}
"
    },
    "lib/v4-core/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol": {
      "content": "// 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);
}
"
    },
    "lib/v4-core/lib/openzeppelin-contracts/contracts/utils/math/Math.sol": {
      "content": "// 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;

Tags:
ERC20, Multisig, Mintable, Burnable, Swap, Liquidity, Upgradeable, Multi-Signature, Factory, Oracle|addr:0x6e68872c0d5ea70da95be8f44aa7e16930b89d3c|verified:true|block:23704809|tx:0x7bd6b81251d7c422d7566315385ced9082e1065b377cffe43f3e06211f15bd16|first_check:1762003981

Submitted on: 2025-11-01 14:33:01

Comments

Log in to comment.

No comments yet.