PonsLaunchFactory

0xa5aab3f0c6eeadf30ef1d3eb997108e976351feb

Verification
Verified
v0.8.30+commit.73712a01
Type
Contract
24,353 bytes
ABI entries
58
13 read · 11 write
License
none

Contract information

Address
0xa5aab3f0c6eeadf30ef1d3eb997108e976351feb
Chain
Robinhood Chain (4663)
Compiler
v0.8.30+commit.73712a01
Optimization
Enabled
Creation tx
0x836c5e41d4…dfbe0c0e67

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (13)

dexConfigCount()uint256
getDexConfig(uint256)tuple
getLaunchConfig(uint256)tuple
getLaunchedToken(address)tuple
graduationStatus(address)uint256, uint256, bool
launchConfigCount()uint256
launchEnabled()bool
launchFee()uint256
locker()address
owner()address
pendingOwner()address
predictTokenAddress(tuple, uint256, uint256, bytes32, address)address
whitelistedLaunchers(address)bool

Events (11)

DexConfigAddedDexStatusUpdatedLaunchConfigAddedLaunchConfigUpdatedLaunchEnabledUpdatedLaunchFeeUpdatedOwnershipTransferStartedOwnershipTransferredTokenDeployedTokenLaunchedWhitelistedLauncherUpdated

ABI

[
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "initialOwner",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "locker_",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "initialLaunchFee",
        "type": "uint256"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [],
    "name": "DexDisabled",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "FeeTransferFailed",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidBasisPoints",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidDexConfig",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidDexId",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidLaunchConfigId",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidMaxTxBasisPoints",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidTick",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidTokenParams",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "LaunchConfigDisabled",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "LaunchFeeNotPaid",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NotWhitelisted",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      }
    ],
    "name": "OwnableInvalidOwner",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "OwnableUnauthorizedAccount",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "PoolAlreadyExists",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "ReentrancyGuardReentrantCall",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "RouterNotSet",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      }
    ],
    "name": "SafeERC20FailedOperation",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "SupplyTooLow",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "TokenDeploymentFailed",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "TokenNotFound",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "ZeroAddress",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "id",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "string",
        "name": "name",
        "type": "string"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "factory",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "positionManager",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "swapRouter",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint24",
        "name": "poolFee",
        "type": "uint24"
      },
      {
        "indexed": false,
        "internalType": "int24",
        "name": "tickSpacing",
        "type": "int24"
      }
    ],
    "name": "DexConfigAdded",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "id",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "enabled",
        "type": "bool"
      }
    ],
    "name": "DexStatusUpdated",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "id",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "pairToken",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "graduationThreshold",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "int24",
        "name": "initialTick",
        "type": "int24"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "supply",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint16",
        "name": "maxWalletBps",
        "type": "uint16"
      },
      {
        "indexed": false,
        "internalType": "uint16",
        "name": "maxTxBps",
        "type": "uint16"
      },
      {
        "indexed": false,
        "internalType": "uint32",
        "name": "restrictionBlocks",
        "type": "uint32"
      },
      {
        "indexed": false,
        "internalType": "uint24",
        "name": "reservedFee",
        "type": "uint24"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "enabled",
        "type": "bool"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "routerRequiresDeadline",
        "type": "bool"
      }
    ],
    "name": "LaunchConfigAdded",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "id",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "pairToken",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "graduationThreshold",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "int24",
        "name": "initialTick",
        "type": "int24"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "supply",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint16",
        "name": "maxWalletBps",
        "type": "uint16"
      },
      {
        "indexed": false,
        "internalType": "uint16",
        "name": "maxTxBps",
        "type": "uint16"
      },
      {
        "indexed": false,
        "internalType": "uint32",
        "name": "restrictionBlocks",
        "type": "uint32"
      },
      {
        "indexed": false,
        "internalType": "uint24",
        "name": "reservedFee",
        "type": "uint24"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "enabled",
        "type": "bool"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "routerRequiresDeadline",
        "type": "bool"
      }
    ],
    "name": "LaunchConfigUpdated",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "bool",
        "name": "enabled",
        "type": "bool"
      }
    ],
    "name": "LaunchEnabledUpdated",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "launchFee",
        "type": "uint256"
      }
    ],
    "name": "LaunchFeeUpdated",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "previousOwner",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "OwnershipTransferStarted",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "previousOwner",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "OwnershipTransferred",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "deployer",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "dexFactory",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "pairToken",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "dexId",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "launchConfigId",
        "type": "uint256"
      }
    ],
    "name": "TokenDeployed",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "deployer",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "dexFactory",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "pairToken",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "pool",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "dexId",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "launchConfigId",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "positionId",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "restrictionsEndBlock",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "initialBuyAmount",
        "type": "uint256"
      }
    ],
    "name": "TokenLaunched",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "launcher",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "enabled",
        "type": "bool"
      }
    ],
    "name": "WhitelistedLauncherUpdated",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "acceptOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "components": [
          {
            "internalType": "string",
            "name": "name",
            "type": "string"
          },
          {
            "internalType": "address",
            "name": "factory",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "positionManager",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "swapRouter",
            "type": "address"
          },
          {
            "internalType": "uint24",
            "name": "poolFee",
            "type": "uint24"
          },
          {
            "internalType": "int24",
            "name": "tickSpacing",
            "type": "int24"
          },
          {
            "internalType": "bool",
            "name": "enabled",
            "type": "bool"
          }
        ],
        "internalType": "struct PonsLaunchFactory.DexConfig",
        "name": "config",
        "type": "tuple"
      }
    ],
    "name": "addDexConfig",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "id",
        "type": "uint256"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "components": [
          {
            "internalType": "address",
            "name": "pairToken",
            "type": "address"
          },
          {
            "internalType": "uint256",
            "name": "graduationThreshold",
            "type": "uint256"
          },
          {
            "internalType": "int24",
            "name": "initialTick",
            "type": "int24"
          },
          {
            "internalType": "uint256",
            "name": "supply",
            "type": "uint256"
          },
          {
            "internalType": "uint16",
            "name": "maxWalletBps",
            "type": "uint16"
          },
          {
            "internalType": "uint16",
            "name": "maxTxBps",
            "type": "uint16"
          },
          {
            "internalType": "uint32",
            "name": "restrictionBlocks",
            "type": "uint32"
          },
          {
            "internalType": "uint24",
            "name": "reservedFee",
            "type": "uint24"
          },
          {
            "internalType": "bool",
            "name": "enabled",
            "type": "bool"
          },
          {
            "internalType": "bool",
            "name": "routerRequiresDeadline",
            "type": "bool"
          }
        ],
        "internalType": "struct PonsLaunchFactory.LaunchConfig",
        "name": "config",
        "type": "tuple"
      }
    ],
    "name": "addLaunchConfig",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "id",
        "type": "uint256"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "dexConfigCount",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "id",
        "type": "uint256"
      }
    ],
    "name": "getDexConfig",
    "outputs": [
      {
        "components": [
          {
            "internalType": "string",
            "name": "name",
            "type": "string"
          },
          {
            "internalType": "address",
            "name": "factory",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "positionManager",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "swapRouter",
            "type": "address"
          },
          {
            "internalType": "uint24",
            "name": "poolFee",
            "type": "uint24"
          },
          {
            "internalType": "int24",
            "name": "tickSpacing",
            "type": "int24"
          },
          {
            "internalType": "bool",
            "name": "enabled",
            "type": "bool"
          }
        ],
        "internalType": "struct PonsLaunchFactory.DexConfig",
        "name": "",
        "type": "tuple"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "id",
        "type": "uint256"
      }
    ],
    "name": "getLaunchConfig",
    "outputs": [
      {
        "components": [
          {
            "internalType": "address",
            "name": "pairToken",
            "type": "address"
          },
          {
            "internalType": "uint256",
            "name": "graduationThreshold",
            "type": "uint256"
          },
          {
            "internalType": "int24",
            "name": "initialTick",
            "type": "int24"
          },
          {
            "internalType": "uint256",
            "name": "supply",
            "type": "uint256"
          },
          {
            "internalType": "uint16",
            "name": "maxWalletBps",
            "type": "uint16"
          },
          {
            "internalType": "uint16",
            "name": "maxTxBps",
            "type": "uint16"
          },
          {
            "internalType": "uint32",
            "name": "restrictionBlocks",
            "type": "uint32"
          },
          {
            "internalType": "uint24",
            "name": "reservedFee",
            "type": "uint24"
          },
          {
            "internalType": "bool",
            "name": "enabled",
            "type": "bool"
          },
          {
            "internalType": "bool",
            "name": "routerRequiresDeadline",
            "type": "bool"
          }
        ],
        "internalType": "struct PonsLaunchFactory.LaunchConfig",
        "name": "",
        "type": "tuple"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      }
    ],
    "name": "getLaunchedToken",
    "outputs": [
      {
        "components": [
          {
            "internalType": "address",
            "name": "token",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "deployer",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "pairedToken",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "positionManager",
            "type": "address"
          },
          {
            "internalType": "uint256",
            "name": "positionId",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "dexId",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "launchConfigId",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "restrictionsEndBlock",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "supply",
            "type": "uint256"
          },
          {
            "internalType": "bool",
            "name": "isToken0",
            "type": "bool"
          },
          {
            "internalType": "uint24",
            "name": "poolFee",
            "type": "uint24"
          },
          {
            "internalType": "bool",
            "name": "exists",
            "type": "bool"
          },
          {
            "internalType": "uint256",
            "name": "initialBuyAmount",
            "type": "uint256"
          }
        ],
        "internalType": "struct IPonsLaunchFactory.LaunchedToken",
        "name": "",
        "type": "tuple"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      }
    ],
    "name": "graduationStatus",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "pairedPrincipal",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "threshold",
        "type": "uint256"
      },
      {
        "internalType": "bool",
        "name": "graduated",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "launchConfigCount",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "launchEnabled",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "launchFee",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "components": [
          {
            "internalType": "string",
            "name": "name",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "symbol",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "logo",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "description",
            "type": "string"
          },
          {
            "components": [
              {
                "internalType": "string",
                "name": "twitter",
                "type": "string"
              },
              {
                "internalType": "string",
                "name": "telegram",
                "type": "string"
              },
              {
                "internalType": "string",
                "name": "discord",
                "type": "string"
              },
              {
                "internalType": "string",
                "name": "website",
                "type": "string"
              },
              {
                "internalType": "string",
                "name": "farcaster",
                "type": "string"
              }
            ],
            "internalType": "struct PonsLaunchFactory.Socials",
            "name": "socials",
            "type": "tuple"
          },
          {
            "internalType": "address",
            "name": "feeWallet",
            "type": "address"
          }
        ],
        "internalType": "struct PonsLaunchFactory.TokenParams",
        "name": "params",
        "type": "tuple"
      },
      {
        "internalType": "uint256",
        "name": "launchConfigId",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "dexId",
        "type": "uint256"
      },
      {
        "internalType": "bytes32",
        "name": "salt",
        "type": "bytes32"
      }
    ],
    "name": "launchToken",
    "outputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      }
    ],
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "locker",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "pendingOwner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "components": [
          {
            "internalType": "string",
            "name": "name",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "symbol",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "logo",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "description",
            "type": "string"
          },
          {
            "components": [
              {
                "internalType": "string",
                "name": "twitter",
                "type": "string"
              },
              {
                "internalType": "string",
                "name": "telegram",
                "type": "string"
              },
              {
                "internalType": "string",
                "name": "discord",
                "type": "string"
              },
              {
                "internalType": "string",
                "name": "website",
                "type": "string"
              },
              {
                "internalType": "string",
                "name": "farcaster",
                "type": "string"
              }
            ],
            "internalType": "struct PonsLaunchFactory.Socials",
            "name": "socials",
            "type": "tuple"
          },
          {
            "internalType": "address",
            "name": "feeWallet",
            "type": "address"
          }
        ],
        "internalType": "struct PonsLaunchFactory.TokenParams",
        "name": "params",
        "type": "tuple"
      },
      {
        "internalType": "uint256",
        "name": "launchConfigId",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "dexId",
        "type": "uint256"
      },
      {
        "internalType": "bytes32",
        "name": "salt",
        "type": "bytes32"
      },
      {
        "internalType": "address",
        "name": "tokenDeployer",
        "type": "address"
      }
    ],
    "name": "predictTokenAddress",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "renounceOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "id",
        "type": "uint256"
      },
      {
        "internalType": "bool",
        "name": "enabled",
        "type": "bool"
      }
    ],
    "name": "setDexStatus",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "bool",
        "name": "enabled",
        "type": "bool"
      }
    ],
    "name": "setLaunchEnabled",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "newLaunchFee",
        "type": "uint256"
      }
    ],
    "name": "setLaunchFee",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "launcher",
        "type": "address"
      },
      {
        "internalType": "bool",
        "name": "enabled",
        "type": "bool"
      }
    ],
    "name": "setWhitelistedLauncher",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "transferOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "id",
        "type": "uint256"
      },
      {
        "components": [
          {
            "internalType": "address",
            "name": "pairToken",
            "type": "address"
          },
          {
            "internalType": "uint256",
            "name": "graduationThreshold",
            "type": "uint256"
          },
          {
            "internalType": "int24",
            "name": "initialTick",
            "type": "int24"
          },
          {
            "internalType": "uint256",
            "name": "supply",
            "type": "uint256"
          },
          {
            "internalType": "uint16",
            "name": "maxWalletBps",
            "type": "uint16"
          },
          {
            "internalType": "uint16",
            "name": "maxTxBps",
            "type": "uint16"
          },
          {
            "internalType": "uint32",
            "name": "restrictionBlocks",
            "type": "uint32"
          },
          {
            "internalType": "uint24",
            "name": "reservedFee",
            "type": "uint24"
          },
          {
            "internalType": "bool",
            "name": "enabled",
            "type": "bool"
          },
          {
            "internalType": "bool",
            "name": "routerRequiresDeadline",
            "type": "bool"
          }
        ],
        "internalType": "struct PonsLaunchFactory.LaunchConfig",
        "name": "config",
        "type": "tuple"
      }
    ],
    "name": "updateLaunchConfig",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "launcher",
        "type": "address"
      }
    ],
    "name": "whitelistedLaunchers",
    "outputs": [
      {
        "internalType": "bool",
        "name": "enabled",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  }
]

Source code

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {PonsLauncherToken} from "./PonsLauncherToken.sol";
import {PonsLiquidityMath} from "./libraries/PonsLiquidityMath.sol";
import {PonsTickMath} from "./libraries/PonsTickMath.sol";
import {
    INonfungiblePositionManagerLike,
    IPonsLaunchFactory,
    IPonsLaunchLocker,
    ISwapRouter02Like,
    ISwapRouterV3Like,
    IUniswapV3FactoryLike,
    IUniswapV3PoolStateLike
} from "./interfaces/ILaunchpad.sol";

/**
 * @title PonsLaunchFactory
 * @notice Deploys fixed-supply tokens directly into one-sided Uniswap V3
 * positions, permanently locks the position NFT, and optionally executes an
 * initial native-token buy in the same atomic transaction.
 */
contract PonsLaunchFactory is Ownable2Step, ReentrancyGuard, IPonsLaunchFactory {
    using SafeERC20 for IERC20;

    int24 private constant MIN_TICK = -887272;
    int24 private constant MAX_TICK = 887272;
    uint256 private constant BASIS_POINTS = 10_000;

    struct Socials {
        string twitter;
        string telegram;
        string discord;
        string website;
        string farcaster;
    }

    struct TokenParams {
        string name;
        string symbol;
        string logo;
        string description;
        Socials socials;
        address feeWallet;
    }

    struct DexConfig {
        string name;
        address factory;
        address positionManager;
        address swapRouter;
        uint24 poolFee;
        int24 tickSpacing;
        bool enabled;
    }

    struct LaunchConfig {
        address pairToken;
        uint256 graduationThreshold;
        int24 initialTick;
        uint256 supply;
        uint16 maxWalletBps;
        uint16 maxTxBps;
        uint32 restrictionBlocks;
        uint24 reservedFee;
        bool enabled;
        bool routerRequiresDeadline;
    }

    error InvalidDexConfig();
    error InvalidDexId();
    error DexDisabled();
    error InvalidLaunchConfigId();
    error LaunchConfigDisabled();
    error InvalidBasisPoints();
    error InvalidMaxTxBasisPoints();
    error SupplyTooLow();
    error LaunchFeeNotPaid();
    error NotWhitelisted();
    error FeeTransferFailed();
    error TokenDeploymentFailed();
    error PoolAlreadyExists();
    error RouterNotSet();
    error ZeroAddress();
    error InvalidTokenParams();
    error TokenNotFound();

    event TokenDeployed(
        address indexed token,
        address indexed deployer,
        address indexed dexFactory,
        address pairToken,
        uint256 dexId,
        uint256 launchConfigId
    );
    event TokenLaunched(
        address indexed token,
        address indexed deployer,
        address indexed dexFactory,
        address pairToken,
        address pool,
        uint256 dexId,
        uint256 launchConfigId,
        uint256 positionId,
        uint256 restrictionsEndBlock,
        uint256 initialBuyAmount
    );
    event DexConfigAdded(
        uint256 indexed id,
        string name,
        address factory,
        address positionManager,
        address swapRouter,
        uint24 poolFee,
        int24 tickSpacing
    );
    event DexStatusUpdated(uint256 indexed id, bool enabled);
    event LaunchConfigAdded(
        uint256 indexed id,
        address pairToken,
        uint256 graduationThreshold,
        int24 initialTick,
        uint256 supply,
        uint16 maxWalletBps,
        uint16 maxTxBps,
        uint32 restrictionBlocks,
        uint24 reservedFee,
        bool enabled,
        bool routerRequiresDeadline
    );
    event LaunchConfigUpdated(
        uint256 indexed id,
        address pairToken,
        uint256 graduationThreshold,
        int24 initialTick,
        uint256 supply,
        uint16 maxWalletBps,
        uint16 maxTxBps,
        uint32 restrictionBlocks,
        uint24 reservedFee,
        bool enabled,
        bool routerRequiresDeadline
    );
    event LaunchFeeUpdated(uint256 launchFee);
    event LaunchEnabledUpdated(bool enabled);
    event WhitelistedLauncherUpdated(address indexed launcher, bool enabled);

    address public immutable locker;
    uint256 public launchFee;
    bool public launchEnabled;

    mapping(address launcher => bool enabled) public whitelistedLaunchers;
    mapping(address token => LaunchedToken launched) private _launchedTokens;
    mapping(address token => uint256 threshold) private _graduationThresholds;
    DexConfig[] private _dexConfigs;
    LaunchConfig[] private _launchConfigs;

    constructor(address initialOwner, address locker_, uint256 initialLaunchFee) Ownable(initialOwner) {
        if (locker_ == address(0)) revert ZeroAddress();
        locker = locker_;
        launchFee = initialLaunchFee;
    }

    /**
     * @notice Returns the number of configured V3 deployments.
     */
    function dexConfigCount() external view returns (uint256) {
        return _dexConfigs.length;
    }

    /**
     * @notice Returns the number of launch configurations.
     */
    function launchConfigCount() external view returns (uint256) {
        return _launchConfigs.length;
    }

    /**
     * @notice Returns one V3 deployment configuration.
     */
    function getDexConfig(uint256 id) external view returns (DexConfig memory) {
        if (id >= _dexConfigs.length) revert InvalidDexId();
        return _dexConfigs[id];
    }

    /**
     * @notice Returns one token launch configuration.
     */
    function getLaunchConfig(uint256 id) external view returns (LaunchConfig memory) {
        if (id >= _launchConfigs.length) revert InvalidLaunchConfigId();
        return _launchConfigs[id];
    }

    /**
     * @notice Returns the immutable record for a token created by this factory.
     */
    function getLaunchedToken(address token) external view override returns (LaunchedToken memory) {
        return _launchedTokens[token];
    }

    /**
     * @notice Derives graduation from paired-token principal in the locked V3 position.
     * Direct token donations to the pool do not affect this value. A zero threshold
     * disables graduation for the token.
     */
    function graduationStatus(address token)
        external
        view
        returns (uint256 pairedPrincipal, uint256 threshold, bool graduated)
    {
        LaunchedToken memory launched = _launchedTokens[token];
        if (!launched.exists) revert TokenNotFound();

        address pool = PonsLauncherToken(token).liquidityPool();
        (uint160 sqrtPriceX96,,,,,,) = IUniswapV3PoolStateLike(pool).slot0();
        (,,,,, int24 tickLower, int24 tickUpper, uint128 liquidity,,,,) =
            INonfungiblePositionManagerLike(launched.positionManager).positions(launched.positionId);
        (uint256 amount0, uint256 amount1) = PonsLiquidityMath.getAmountsForLiquidity(
            sqrtPriceX96,
            PonsTickMath.getSqrtRatioAtTick(tickLower),
            PonsTickMath.getSqrtRatioAtTick(tickUpper),
            liquidity
        );

        pairedPrincipal = launched.isToken0 ? amount1 : amount0;
        threshold = _graduationThresholds[token];
        graduated = threshold != 0 && pairedPrincipal >= threshold;
    }

    /**
     * @notice Adds a V3 factory, position manager, and router combination.
     */
    function addDexConfig(DexConfig calldata config) external onlyOwner returns (uint256 id) {
        _validateDexConfig(config);
        id = _dexConfigs.length;
        _dexConfigs.push(config);
        emit DexConfigAdded(
            id,
            config.name,
            config.factory,
            config.positionManager,
            config.swapRouter,
            config.poolFee,
            config.tickSpacing
        );
    }

    /**
     * @notice Enables or disables a configured V3 deployment.
     */
    function setDexStatus(uint256 id, bool enabled) external onlyOwner {
        if (id >= _dexConfigs.length) revert InvalidDexId();
        _dexConfigs[id].enabled = enabled;
        emit DexStatusUpdated(id, enabled);
    }

    /**
     * @notice Adds a launch configuration.
     */
    function addLaunchConfig(LaunchConfig calldata config) external onlyOwner returns (uint256 id) {
        _validateLaunchConfig(config);
        id = _launchConfigs.length;
        _launchConfigs.push(config);
        _emitLaunchConfigAdded(id, config);
    }

    /**
     * @notice Replaces an existing launch configuration.
     */
    function updateLaunchConfig(uint256 id, LaunchConfig calldata config) external onlyOwner {
        if (id >= _launchConfigs.length) revert InvalidLaunchConfigId();
        _validateLaunchConfig(config);
        _launchConfigs[id] = config;
        emit LaunchConfigUpdated(
            id,
            config.pairToken,
            config.graduationThreshold,
            config.initialTick,
            config.supply,
            config.maxWalletBps,
            config.maxTxBps,
            config.restrictionBlocks,
            config.reservedFee,
            config.enabled,
            config.routerRequiresDeadline
        );
    }

    /**
     * @notice Changes the fixed native launch fee.
     */
    function setLaunchFee(uint256 newLaunchFee) external onlyOwner {
        launchFee = newLaunchFee;
        emit LaunchFeeUpdated(newLaunchFee);
    }

    /**
     * @notice Opens or closes launches to non-whitelisted callers.
     */
    function setLaunchEnabled(bool enabled) external onlyOwner {
        launchEnabled = enabled;
        emit LaunchEnabledUpdated(enabled);
    }

    /**
     * @notice Grants or revokes permission to launch while the public gate is closed.
     */
    function setWhitelistedLauncher(address launcher, bool enabled) external onlyOwner {
        if (launcher == address(0)) revert ZeroAddress();
        whitelistedLaunchers[launcher] = enabled;
        emit WhitelistedLauncherUpdated(launcher, enabled);
    }

    /**
     * @notice Atomically deploys, pools, locks, records, and optionally buys a token.
     */
    function launchToken(TokenParams calldata params, uint256 launchConfigId, uint256 dexId, bytes32 salt)
        external
        payable
        nonReentrant
        returns (address token)
    {
        if (!launchEnabled && !whitelistedLaunchers[msg.sender]) {
            revert NotWhitelisted();
        }
        if (msg.value < launchFee) revert LaunchFeeNotPaid();
        if (dexId >= _dexConfigs.length) revert InvalidDexId();
        if (launchConfigId >= _launchConfigs.length) {
            revert InvalidLaunchConfigId();
        }
        if (bytes(params.name).length == 0 || bytes(params.symbol).length == 0) {
            revert InvalidTokenParams();
        }

        DexConfig memory dex = _dexConfigs[dexId];
        LaunchConfig memory config = _launchConfigs[launchConfigId];
        if (!dex.enabled) revert DexDisabled();
        if (!config.enabled) revert LaunchConfigDisabled();

        address initialBuyRecipient = params.feeWallet == address(0) ? msg.sender : params.feeWallet;
        bytes memory creationCode = _buildTokenCreationCode(params, config, dex, msg.sender);
        address predictedToken = _computeCreate2Address(salt, keccak256(creationCode));
        if (IUniswapV3FactoryLike(dex.factory).getPool(predictedToken, config.pairToken, dex.poolFee) != address(0)) {
            revert PoolAlreadyExists();
        }

        _payLaunchFee();
        token = _deployToken(salt, creationCode);
        emit TokenDeployed(token, msg.sender, dex.factory, config.pairToken, dexId, launchConfigId);

        bool isToken0 = token < config.pairToken;
        int24 poolTick = isToken0 ? config.initialTick : -config.initialTick;
        (int24 tickLower, int24 tickUpper) = _positionRange(isToken0, config.initialTick, dex.tickSpacing);

        INonfungiblePositionManagerLike manager = INonfungiblePositionManagerLike(dex.positionManager);
        (address token0, address token1) = isToken0 ? (token, config.pairToken) : (config.pairToken, token);
        address pool = manager.createAndInitializePoolIfNecessary(
            token0, token1, dex.poolFee, PonsTickMath.getSqrtRatioAtTick(poolTick)
        );

        IERC20(token).forceApprove(dex.positionManager, config.supply);
        (uint256 positionId,,,) = manager.mint(
            INonfungiblePositionManagerLike.MintParams({
                token0: token0,
                token1: token1,
                fee: dex.poolFee,
                tickLower: tickLower,
                tickUpper: tickUpper,
                amount0Desired: isToken0 ? config.supply : 0,
                amount1Desired: isToken0 ? 0 : config.supply,
                amount0Min: 0,
                amount1Min: 0,
                recipient: address(this),
                deadline: block.timestamp
            })
        );
        IERC20(token).forceApprove(dex.positionManager, 0);

        uint256 initialBuyAmount = msg.value - launchFee;
        uint256 restrictionEndBlock = PonsLauncherToken(token).restrictionEndBlock();
        _launchedTokens[token] = LaunchedToken({
            token: token,
            deployer: msg.sender,
            pairedToken: config.pairToken,
            positionManager: dex.positionManager,
            positionId: positionId,
            dexId: dexId,
            launchConfigId: launchConfigId,
            restrictionsEndBlock: restrictionEndBlock,
            supply: config.supply,
            isToken0: isToken0,
            poolFee: dex.poolFee,
            exists: true,
            initialBuyAmount: initialBuyAmount
        });
        _graduationThresholds[token] = config.graduationThreshold;

        manager.safeTransferFrom(address(this), locker, positionId);
        IPonsLaunchLocker(locker).lockPosition(token);
        // Wire Advanced creator wallet to fee payouts, not only the developer buy.
        if (params.feeWallet != address(0)) {
            IPonsLaunchLocker(locker).setFeeRedirect(token, params.feeWallet);
        }

        emit TokenLaunched(
            token,
            msg.sender,
            dex.factory,
            config.pairToken,
            pool,
            dexId,
            launchConfigId,
            positionId,
            restrictionEndBlock,
            initialBuyAmount
        );

        if (initialBuyAmount != 0) {
            if (dex.swapRouter == address(0)) revert RouterNotSet();
            PonsLauncherToken(token).setInitialBuyRecipient(initialBuyRecipient);
            _executeInitialBuy(dex, config, token, initialBuyRecipient, initialBuyAmount);
            PonsLauncherToken(token).setInitialBuyRecipient(address(0));
        }
    }

    /**
     * @notice Computes the deterministic token address for launch inputs.
     */
    function predictTokenAddress(
        TokenParams calldata params,
        uint256 launchConfigId,
        uint256 dexId,
        bytes32 salt,
        address tokenDeployer
    ) external view returns (address) {
        if (dexId >= _dexConfigs.length) revert InvalidDexId();
        if (launchConfigId >= _launchConfigs.length) {
            revert InvalidLaunchConfigId();
        }
        bytes memory creationCode =
            _buildTokenCreationCode(params, _launchConfigs[launchConfigId], _dexConfigs[dexId], tokenDeployer);
        return _computeCreate2Address(salt, keccak256(creationCode));
    }

    function _buildTokenCreationCode(
        TokenParams calldata params,
        LaunchConfig memory config,
        DexConfig memory dex,
        address tokenDeployer
    ) private pure returns (bytes memory) {
        PonsLauncherToken.Socials memory tokenSocials = PonsLauncherToken.Socials({
            twitter: params.socials.twitter,
            telegram: params.socials.telegram,
            discord: params.socials.discord,
            website: params.socials.website,
            farcaster: params.socials.farcaster
        });

        return abi.encodePacked(
            type(PonsLauncherToken).creationCode,
            abi.encode(
                params.name,
                params.symbol,
                params.logo,
                params.description,
                tokenSocials,
                tokenDeployer,
                dex.factory,
                dex.positionManager,
                config.pairToken,
                dex.poolFee,
                config.supply,
                config.maxWalletBps,
                config.maxTxBps,
                config.restrictionBlocks
            )
        );
    }

    function _deployToken(bytes32 salt, bytes memory creationCode) private returns (address token) {
        assembly ("memory-safe") {
            token := create2(0, add(creationCode, 0x20), mload(creationCode), salt)
        }
        if (token == address(0)) revert TokenDeploymentFailed();
    }

    function _payLaunchFee() private {
        if (launchFee == 0) return;
        address recipient = IPonsLaunchLocker(locker).protocolFeeRecipient();
        if (recipient == address(0)) revert ZeroAddress();
        (bool sent,) = payable(recipient).call{value: launchFee}("");
        if (!sent) revert FeeTransferFailed();
    }

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

    function _positionRange(bool isToken0, int24 initialTick, int24 tickSpacing)
        private
        pure
        returns (int24 tickLower, int24 tickUpper)
    {
        // Truncation toward zero is required to derive V3's usable boundary ticks.
        // forge-lint: disable-next-line(divide-before-multiply)
        int24 minUsableTick = (MIN_TICK / tickSpacing) * tickSpacing;
        // forge-lint: disable-next-line(divide-before-multiply)
        int24 maxUsableTick = (MAX_TICK / tickSpacing) * tickSpacing;

        if (isToken0) {
            return (initialTick, maxUsableTick);
        }
        return (minUsableTick, -initialTick);
    }

    function _validateDexConfig(DexConfig calldata config) private pure {
        if (
            bytes(config.name).length == 0 || config.factory == address(0) || config.positionManager == address(0)
                || config.poolFee == 0 || config.tickSpacing <= 0
        ) {
            revert InvalidDexConfig();
        }
    }

    function _validateLaunchConfig(LaunchConfig calldata config) private pure {
        if (config.pairToken == address(0)) revert ZeroAddress();
        if (config.maxWalletBps > BASIS_POINTS || config.maxTxBps > BASIS_POINTS) {
            revert InvalidBasisPoints();
        }
        uint16 expectedMaxTxBps = _tokenMaxTxBps(config.maxWalletBps);
        if (config.maxTxBps != expectedMaxTxBps) {
            revert InvalidMaxTxBasisPoints();
        }
        if (config.supply < 1 ether) revert SupplyTooLow();
        if (config.initialTick < MIN_TICK || config.initialTick > MAX_TICK || config.initialTick == 0) {
            revert InvalidLaunchConfigId();
        }
    }

    function _tokenMaxTxBps(uint16 maxWalletBps) private pure returns (uint16) {
        uint256 derived = (uint256(maxWalletBps) * 110) / 100;
        uint256 capped = derived > BASIS_POINTS ? BASIS_POINTS : derived;
        // The basis-point cap guarantees that the value fits uint16.
        // forge-lint: disable-next-line(unsafe-typecast)
        return uint16(capped);
    }

    function _emitLaunchConfigAdded(uint256 id, LaunchConfig calldata config) private {
        emit LaunchConfigAdded(
            id,
            config.pairToken,
            config.graduationThreshold,
            config.initialTick,
            config.supply,
            config.maxWalletBps,
            config.maxTxBps,
            config.restrictionBlocks,
            config.reservedFee,
            config.enabled,
            config.routerRequiresDeadline
        );
    }

    function _executeInitialBuy(
        DexConfig memory dex,
        LaunchConfig memory config,
        address token,
        address recipient,
        uint256 amountIn
    ) private {
        if (config.routerRequiresDeadline) {
            ISwapRouterV3Like(dex.swapRouter).exactInputSingle{value: amountIn}(
                ISwapRouterV3Like.ExactInputSingleParams({
                    tokenIn: config.pairToken,
                    tokenOut: token,
                    fee: dex.poolFee,
                    recipient: recipient,
                    deadline: block.timestamp,
                    amountIn: amountIn,
                    amountOutMinimum: 0,
                    sqrtPriceLimitX96: 0
                })
            );
            return;
        }

        ISwapRouter02Like(dex.swapRouter).exactInputSingle{value: amountIn}(
            ISwapRouter02Like.ExactInputSingleParams({
                tokenIn: config.pairToken,
                tokenOut: token,
                fee: dex.poolFee,
                recipient: recipient,
                amountIn: amountIn,
                amountOutMinimum: 0,
                sqrtPriceLimitX96: 0
            })
        );
    }
}
Chain explorer2122msChain node97ms