{"language":"Solidity","sources":{"contracts/NyseLaunchFactory.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\ncontract NyseCommunityToken {\n    string public name;\n    string public symbol;\n    string public referenceTicker;\n    string public website;\n    string public twitter;\n    string public telegram;\n    uint8 public constant decimals = 18;\n    uint16 public constant sellFeeBps = 100;\n    uint256 public immutable totalSupply;\n    uint256 public immutable tokensPerETH;\n    address public immutable creator;\n    uint256 public creatorFees;\n    bool private entered;\n\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    event Transfer(address indexed from, address indexed to, uint256 value);\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n    event Bought(address indexed account, uint256 ethIn, uint256 tokensOut);\n    event Sold(address indexed account, uint256 tokensIn, uint256 ethOut, uint256 fee);\n    event FeesClaimed(address indexed creator, uint256 amount);\n\n    error InvalidConfiguration();\n    error InsufficientBalance();\n    error InsufficientAllowance();\n    error Slippage();\n    error SoldOut();\n    error InsufficientReserve();\n    error CreatorOnly();\n    error TransferFailed();\n    error ReentrantCall();\n\n    modifier nonReentrant() { if (entered) revert ReentrantCall(); entered = true; _; entered = false; }\n\n    constructor(string memory tokenName, string memory tokenSymbol, string memory ticker, string memory site, string memory x, string memory tg, uint256 supplyTokens, uint256 rate, address tokenCreator) {\n        if (block.chainid != 4663 || bytes(tokenName).length < 3 || bytes(tokenName).length > 48 || bytes(tokenSymbol).length < 2 || bytes(tokenSymbol).length > 10 || supplyTokens < 1_000 || supplyTokens > 1_000_000_000 || rate == 0 || rate > 1_000_000_000 || tokenCreator == address(0)) revert InvalidConfiguration();\n        name = tokenName; symbol = tokenSymbol; referenceTicker = ticker; website = site; twitter = x; telegram = tg;\n        totalSupply = supplyTokens * 1 ether;\n        tokensPerETH = rate;\n        creator = tokenCreator;\n        balanceOf[address(this)] = totalSupply;\n        emit Transfer(address(0), address(this), totalSupply);\n    }\n\n    function buy(uint256 minTokensOut) external payable nonReentrant returns (uint256 tokensOut) {\n        if (msg.value == 0) revert InvalidConfiguration();\n        tokensOut = msg.value * tokensPerETH;\n        if (tokensOut < minTokensOut) revert Slippage();\n        if (balanceOf[address(this)] < tokensOut) revert SoldOut();\n        _transfer(address(this), msg.sender, tokensOut);\n        emit Bought(msg.sender, msg.value, tokensOut);\n    }\n\n    function sell(uint256 tokenAmount, uint256 minEthOut) external nonReentrant returns (uint256 ethOut) {\n        if (tokenAmount == 0) revert InvalidConfiguration();\n        uint256 gross = tokenAmount / tokensPerETH;\n        uint256 fee = gross * sellFeeBps / 10_000;\n        ethOut = gross - fee;\n        if (ethOut < minEthOut) revert Slippage();\n        if (address(this).balance < gross) revert InsufficientReserve();\n        _transfer(msg.sender, address(this), tokenAmount);\n        creatorFees += fee;\n        (bool sent,) = payable(msg.sender).call{value: ethOut}(\"\");\n        if (!sent) revert TransferFailed();\n        emit Sold(msg.sender, tokenAmount, ethOut, fee);\n    }\n\n    function claimFees() external nonReentrant {\n        if (msg.sender != creator) revert CreatorOnly();\n        uint256 amount = creatorFees;\n        creatorFees = 0;\n        (bool sent,) = payable(creator).call{value: amount}(\"\");\n        if (!sent) revert TransferFailed();\n        emit FeesClaimed(creator, amount);\n    }\n\n    function quoteBuy(uint256 ethIn) external view returns (uint256) { return ethIn * tokensPerETH; }\n    function quoteSell(uint256 tokenAmount) external view returns (uint256) { uint256 gross = tokenAmount / tokensPerETH; return gross - (gross * sellFeeBps / 10_000); }\n    function reserveETH() external view returns (uint256) { return address(this).balance - creatorFees; }\n    function circulatingSupply() external view returns (uint256) { return totalSupply - balanceOf[address(this)]; }\n    function transfer(address to, uint256 amount) external returns (bool) { _transfer(msg.sender, to, amount); return true; }\n    function approve(address spender, uint256 amount) external returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; }\n    function transferFrom(address from, address to, uint256 amount) external returns (bool) {\n        uint256 available = allowance[from][msg.sender];\n        if (available != type(uint256).max) {\n            if (available < amount) revert InsufficientAllowance();\n            unchecked { allowance[from][msg.sender] = available - amount; }\n            emit Approval(from, msg.sender, allowance[from][msg.sender]);\n        }\n        _transfer(from, to, amount); return true;\n    }\n    function _transfer(address from, address to, uint256 amount) private {\n        if (to == address(0)) revert InvalidConfiguration();\n        uint256 balance = balanceOf[from];\n        if (balance < amount) revert InsufficientBalance();\n        unchecked { balanceOf[from] = balance - amount; balanceOf[to] += amount; }\n        emit Transfer(from, to, amount);\n    }\n}\n\ncontract NyseLaunchFactory {\n    mapping(bytes32 => address) public marketFor;\n    address[] public allMarkets;\n\n    event MarketCreated(bytes32 indexed key, address indexed market, address indexed creator, string referenceTicker, string symbol, uint256 supplyTokens, uint256 tokensPerETH);\n    error InvalidConfiguration();\n    error SymbolTaken();\n\n    constructor() { if (block.chainid != 4663) revert InvalidConfiguration(); }\n\n    function createMarket(string calldata tokenName, string calldata tokenSymbol, string calldata referenceTicker, string calldata website, string calldata twitter, string calldata telegram, uint256 supplyTokens, uint256 tokensPerETH) external returns (address market) {\n        _validateSymbol(bytes(tokenSymbol));\n        _validateTicker(bytes(referenceTicker));\n        bytes32 key = keccak256(bytes(tokenSymbol));\n        if (marketFor[key] != address(0)) revert SymbolTaken();\n        market = address(new NyseCommunityToken{salt: key}(tokenName, tokenSymbol, referenceTicker, website, twitter, telegram, supplyTokens, tokensPerETH, msg.sender));\n        marketFor[key] = market;\n        allMarkets.push(market);\n        emit MarketCreated(key, market, msg.sender, referenceTicker, tokenSymbol, supplyTokens, tokensPerETH);\n    }\n\n    function marketsLength() external view returns (uint256) { return allMarkets.length; }\n    function _validateTicker(bytes memory value) private pure {\n        if (value.length < 1 || value.length > 8) revert InvalidConfiguration();\n        for (uint256 i; i < value.length; ++i) if (!((value[i] >= 0x41 && value[i] <= 0x5A) || (value[i] >= 0x30 && value[i] <= 0x39))) revert InvalidConfiguration();\n    }\n    function _validateSymbol(bytes memory value) private pure {\n        if (value.length < 2 || value.length > 10) revert InvalidConfiguration();\n        for (uint256 i; i < value.length; ++i) if (!((value[i] >= 0x41 && value[i] <= 0x5A) || (value[i] >= 0x30 && value[i] <= 0x39))) revert InvalidConfiguration();\n    }\n}\n"}},"settings":{"evmVersion":"shanghai","optimizer":{"enabled":true,"runs":1000},"viaIR":true,"outputSelection":{"*":{"*":["abi","evm.bytecode.object","evm.deployedBytecode.object"]}}}}