Launchpad

0xfd52ad20092984c1405181ab0327a7d98bd4513a

Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
22,168 bytes
ABI entries
56
30 read · 15 write
License
none

Contract information

Address
0xfd52ad20092984c1405181ab0327a7d98bd4513a
Chain
Robinhood Chain (4663)
Compiler
v0.8.26+commit.8a97fa7a
Optimization
Enabled
Creation tx
0x4780610175…5100258b26

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (30)

DEAD()address
FEE()uint24
MAX_BPS()uint256
PRECISION()uint256
TICK_SPACING()int24
TOTAL_SUPPLY()uint256
creationFee()uint256
creatorFeeBps()uint256
feeRecipient()address
getClaimable(address, address)uint256
getMCAP(address)uint256
getPrice(address)uint256
getToken(address)tuple
getTokenCount()uint256
getTokens(uint256, uint256)tuple[], uint256
hr(address, address)uint256
mcapsOf(address[])uint256[]
owner()address
poolLiquidityEth(address)uint256
protocolFeeBps()uint256
reg(address)bool
startTick()int24
ti(address)uint256
tickSpan()int24
tokens(uint256)address, address, string, string, string, string, string, string, string, uint256, bool, address, uint256, bool, bool, uint256, uint256
totalFeesCollected()uint256
ufptp(address, address)uint256
v3factory()address
v3pm()address
weth()address

Events (6)

FeesDistributedLaunchedOwnershipTransferredRewardsClaimedTokenCreatedTrade

ABI

[
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "_v3pm",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "_v3factory",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "_weth",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "_fr",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      }
    ],
    "name": "OwnableInvalidOwner",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "OwnableUnauthorizedAccount",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "ReentrancyGuardReentrantCall",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "t",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "ethToProtocol",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "ethToCreatorOrHolders",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "toHolders",
        "type": "bool"
      }
    ],
    "name": "FeesDistributed",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "t",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "pool",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "positionId",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "tokensInPool",
        "type": "uint256"
      }
    ],
    "name": "Launched",
    "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": "t",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "h",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "a",
        "type": "uint256"
      }
    ],
    "name": "RewardsClaimed",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "i",
        "type": "uint256"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "t",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "c",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "string",
        "name": "n",
        "type": "string"
      },
      {
        "indexed": false,
        "internalType": "string",
        "name": "s",
        "type": "string"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "ts",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "d",
        "type": "bool"
      }
    ],
    "name": "TokenCreated",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "t",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "tr",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "buy",
        "type": "bool"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "tokenAmt",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "ethAmt",
        "type": "uint256"
      }
    ],
    "name": "Trade",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "DEAD",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "FEE",
    "outputs": [
      {
        "internalType": "uint24",
        "name": "",
        "type": "uint24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MAX_BPS",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "PRECISION",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "TICK_SPACING",
    "outputs": [
      {
        "internalType": "int24",
        "name": "",
        "type": "int24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "TOTAL_SUPPLY",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "ta",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "minOut",
        "type": "uint256"
      }
    ],
    "name": "buy",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "ta",
        "type": "address"
      }
    ],
    "name": "claimRewards",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "ta",
        "type": "address"
      }
    ],
    "name": "collectFeesSelf",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "string",
        "name": "nm",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "sy",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "ds",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "im",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "tw",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "tg",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "ws",
        "type": "string"
      },
      {
        "internalType": "bool",
        "name": "_distribute",
        "type": "bool"
      },
      {
        "internalType": "uint256",
        "name": "_firstBuy",
        "type": "uint256"
      }
    ],
    "name": "createToken",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "creationFee",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "creatorFeeBps",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "feeRecipient",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "ta",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "holder",
        "type": "address"
      }
    ],
    "name": "getClaimable",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "ta",
        "type": "address"
      }
    ],
    "name": "getMCAP",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "ta",
        "type": "address"
      }
    ],
    "name": "getPrice",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "ta",
        "type": "address"
      }
    ],
    "name": "getToken",
    "outputs": [
      {
        "components": [
          {
            "internalType": "contract LaunchpadToken",
            "name": "token",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "creator",
            "type": "address"
          },
          {
            "internalType": "string",
            "name": "name",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "symbol",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "description",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "imageUrl",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "twitter",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "telegram",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "website",
            "type": "string"
          },
          {
            "internalType": "uint256",
            "name": "createdAt",
            "type": "uint256"
          },
          {
            "internalType": "bool",
            "name": "graduated",
            "type": "bool"
          },
          {
            "internalType": "address",
            "name": "pool",
            "type": "address"
          },
          {
            "internalType": "uint256",
            "name": "positionId",
            "type": "uint256"
          },
          {
            "internalType": "bool",
            "name": "wethIsToken0",
            "type": "bool"
          },
          {
            "internalType": "bool",
            "name": "distribute",
            "type": "bool"
          },
          {
            "internalType": "uint256",
            "name": "hfp",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "fpta",
            "type": "uint256"
          }
        ],
        "internalType": "struct Launchpad.TokenInfo",
        "name": "",
        "type": "tuple"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "getTokenCount",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "o",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "l",
        "type": "uint256"
      }
    ],
    "name": "getTokens",
    "outputs": [
      {
        "components": [
          {
            "internalType": "contract LaunchpadToken",
            "name": "token",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "creator",
            "type": "address"
          },
          {
            "internalType": "string",
            "name": "name",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "symbol",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "description",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "imageUrl",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "twitter",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "telegram",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "website",
            "type": "string"
          },
          {
            "internalType": "uint256",
            "name": "createdAt",
            "type": "uint256"
          },
          {
            "internalType": "bool",
            "name": "graduated",
            "type": "bool"
          },
          {
            "internalType": "address",
            "name": "pool",
            "type": "address"
          },
          {
            "internalType": "uint256",
            "name": "positionId",
            "type": "uint256"
          },
          {
            "internalType": "bool",
            "name": "wethIsToken0",
            "type": "bool"
          },
          {
            "internalType": "bool",
            "name": "distribute",
            "type": "bool"
          },
          {
            "internalType": "uint256",
            "name": "hfp",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "fpta",
            "type": "uint256"
          }
        ],
        "internalType": "struct Launchpad.TokenInfo[]",
        "name": "r",
        "type": "tuple[]"
      },
      {
        "internalType": "uint256",
        "name": "t",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "hr",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address[]",
        "name": "tas",
        "type": "address[]"
      }
    ],
    "name": "mcapsOf",
    "outputs": [
      {
        "internalType": "uint256[]",
        "name": "r",
        "type": "uint256[]"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "ta",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      }
    ],
    "name": "onTransfer",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "ta",
        "type": "address"
      }
    ],
    "name": "pokeFees",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "ta",
        "type": "address"
      }
    ],
    "name": "poolLiquidityEth",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "protocolFeeBps",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "reg",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "renounceOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "ta",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "amt",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "minEth",
        "type": "uint256"
      }
    ],
    "name": "sell",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "f",
        "type": "uint256"
      }
    ],
    "name": "setCreationFee",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "b",
        "type": "uint256"
      }
    ],
    "name": "setCreatorFeeBps",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "int24",
        "name": "_startTick",
        "type": "int24"
      },
      {
        "internalType": "int24",
        "name": "_tickSpan",
        "type": "int24"
      }
    ],
    "name": "setCurve",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "fr",
        "type": "address"
      }
    ],
    "name": "setFeeRecipient",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "b",
        "type": "uint256"
      }
    ],
    "name": "setProtocolFeeBps",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "startTick",
    "outputs": [
      {
        "internalType": "int24",
        "name": "",
        "type": "int24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "ti",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "tickSpan",
    "outputs": [
      {
        "internalType": "int24",
        "name": "",
        "type": "int24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "tokens",
    "outputs": [
      {
        "internalType": "contract LaunchpadToken",
        "name": "token",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "creator",
        "type": "address"
      },
      {
        "internalType": "string",
        "name": "name",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "symbol",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "description",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "imageUrl",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "twitter",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "telegram",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "website",
        "type": "string"
      },
      {
        "internalType": "uint256",
        "name": "createdAt",
        "type": "uint256"
      },
      {
        "internalType": "bool",
        "name": "graduated",
        "type": "bool"
      },
      {
        "internalType": "address",
        "name": "pool",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "positionId",
        "type": "uint256"
      },
      {
        "internalType": "bool",
        "name": "wethIsToken0",
        "type": "bool"
      },
      {
        "internalType": "bool",
        "name": "distribute",
        "type": "bool"
      },
      {
        "internalType": "uint256",
        "name": "hfp",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "fpta",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalFeesCollected",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "transferOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "ufptp",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "int256",
        "name": "amount0Delta",
        "type": "int256"
      },
      {
        "internalType": "int256",
        "name": "amount1Delta",
        "type": "int256"
      },
      {
        "internalType": "bytes",
        "name": "data",
        "type": "bytes"
      }
    ],
    "name": "uniswapV3SwapCallback",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "v3factory",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "v3pm",
    "outputs": [
      {
        "internalType": "contract INonfungiblePositionManager",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "weth",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "stateMutability": "payable",
    "type": "receive"
  }
]

Source code

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

import {LaunchpadToken} from "./LaunchpadToken.sol";
import {Ownable} from "openzeppelin-contracts/contracts/access/Ownable.sol";
import {ReentrancyGuard} from "openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol";
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";

interface IWETH9 {
    function deposit() external payable;
    function withdraw(uint256) external;
    function approve(address, uint256) external returns (bool);
    function transfer(address, uint256) external returns (bool);
    function balanceOf(address) external view returns (uint256);
}

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;
    }
    struct CollectParams {
        uint256 tokenId; address recipient;
        uint128 amount0Max; uint128 amount1Max;
    }
    function mint(MintParams calldata params)
        external payable returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1);
    function collect(CollectParams calldata params)
        external payable returns (uint256 amount0, uint256 amount1);
    function createAndInitializePoolIfNecessary(address, address, uint24, uint160)
        external payable returns (address);
}

interface IUniswapV3Pool {
    function token0() external view returns (address);
    function token1() external view returns (address);
    function slot0() external view returns (
        uint160 sqrtPriceX96, int24 tick, uint16, uint16, uint16, uint8, bool
    );
    function swap(
        address recipient, bool zeroForOne, int256 amountSpecified,
        uint160 sqrtPriceLimitX96, bytes calldata data
    ) external returns (int256 amount0, int256 amount1);
}

/// @title Launchpad (Uniswap V3 native)
/// @notice At launch, the entire supply is deployed as a single-sided Uniswap V3
///         position (no ETH from the creator, only a flat service fee). Trading
///         happens directly on the V3 pool. Fee sharing ("distribute" tokens) is
///         sourced from the pool's 1% LP fees, collected and distributed pro-rata.
contract Launchpad is Ownable, ReentrancyGuard {
    INonfungiblePositionManager public immutable v3pm;
    address public immutable v3factory;
    address public immutable weth;

    uint256 public constant TOTAL_SUPPLY = 1_000_000_000e18;
    uint24  public constant FEE = 10000;        // 1% tier
    int24   public constant TICK_SPACING = 200; // for the 1% tier
    address public constant DEAD = 0x000000000000000000000000000000000000dEaD;
    uint256 public constant MAX_BPS = 10000;
    uint256 public constant PRECISION = 1e36;
    uint160 internal constant MIN_SQRT_RATIO = 4295128739;
    uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;

    // Curve placement. startTick sets the launch price (=> starting FDV); tickSpan
    // sets how far the single-sided range extends upward. Both must be multiples of
    // TICK_SPACING. Defaults target ~$2.5k FDV at ~$2.8k ETH (tuned via fork test).
    int24 public startTick = -208400;
    int24 public tickSpan = 69000;

    uint256 public creationFee = 0.001 ether;
    uint256 public protocolFeeBps = 25;   // share of collected LP fee (relative to protocol+creator)
    uint256 public creatorFeeBps = 75;
    address public feeRecipient;
    uint256 public totalFeesCollected;

    struct TokenInfo {
        LaunchpadToken token; address creator;
        string name; string symbol; string description;
        string imageUrl; string twitter; string telegram; string website;
        uint256 createdAt; bool graduated; address pool;
        uint256 positionId; bool wethIsToken0;
        bool distribute; uint256 hfp; uint256 fpta;
    }

    TokenInfo[] public tokens;
    mapping(address => uint256) public ti;   // token => index
    mapping(address => bool) public reg;     // token => registered
    mapping(address => mapping(address => uint256)) public ufptp; // token => holder => checkpoint
    mapping(address => mapping(address => uint256)) public hr;    // token => holder => accrued rewards (wei)

    event TokenCreated(uint256 indexed i, address indexed t, address indexed c, string n, string s, uint256 ts, bool d);
    event Launched(address indexed t, address indexed pool, uint256 positionId, uint256 tokensInPool);
    event Trade(address indexed t, address indexed tr, bool buy, uint256 tokenAmt, uint256 ethAmt);
    event FeesDistributed(address indexed t, uint256 ethToProtocol, uint256 ethToCreatorOrHolders, bool toHolders);
    event RewardsClaimed(address indexed t, address indexed h, uint256 a);

    constructor(address _v3pm, address _v3factory, address _weth, address _fr) Ownable(msg.sender) {
        require(_v3pm != address(0) && _v3factory != address(0) && _weth != address(0) && _fr != address(0), "0");
        v3pm = INonfungiblePositionManager(_v3pm);
        v3factory = _v3factory;
        weth = _weth;
        feeRecipient = _fr;
    }

    // ---------------------------------------------------------------- launch

    function createToken(
        string memory nm, string memory sy, string memory ds,
        string memory im, string memory tw, string memory tg, string memory ws,
        bool _distribute, uint256 _firstBuy
    ) external payable nonReentrant returns (address) {
        require(msg.value == creationFee + _firstBuy, "val");

        if (creationFee > 0) {
            totalFeesCollected += creationFee;
            (bool s,) = payable(feeRecipient).call{value: creationFee}("");
            require(s, "fee");
        }

        LaunchpadToken token = new LaunchpadToken(nm, sy, msg.sender, address(this), TOTAL_SUPPLY);

        tokens.push(TokenInfo({
            token: token, creator: msg.sender, name: nm, symbol: sy,
            description: ds, imageUrl: im, twitter: tw, telegram: tg, website: ws,
            createdAt: block.timestamp, graduated: false, pool: address(0),
            positionId: 0, wethIsToken0: weth < address(token),
            distribute: _distribute, hfp: 0, fpta: 0
        }));
        uint256 idx = tokens.length - 1;
        ti[address(token)] = idx;
        reg[address(token)] = true;

        emit TokenCreated(idx, address(token), msg.sender, nm, sy, block.timestamp, _distribute);

        _deployPool(idx);

        if (_firstBuy > 0) {
            _buy(address(token), _firstBuy, msg.sender);
        }
        return address(token);
    }

    /// @dev Creates the pool, initializes it at the launch price, and mints the
    ///      entire supply as a single-sided position owned by this contract.
    function _deployPool(uint256 idx) internal {
        TokenInfo storage info = tokens[idx];
        address tok = address(info.token);

        int24 tickLower; int24 tickUpper; int24 curTick;
        if (info.wethIsToken0) {
            // token is token1; range sits below the current price, priced at the top.
            curTick = -startTick;
            tickUpper = -startTick;
            tickLower = -startTick - tickSpan;
        } else {
            // token is token0; range sits above the current price, priced at the bottom.
            curTick = startTick;
            tickLower = startTick;
            tickUpper = startTick + tickSpan;
        }

        (address token0, address token1) = info.wethIsToken0 ? (weth, tok) : (tok, weth);
        uint160 sqrtP = getSqrtRatioAtTick(curTick);

        address pool = v3pm.createAndInitializePoolIfNecessary(token0, token1, FEE, sqrtP);
        info.pool = pool;

        uint256 supply = info.token.balanceOf(address(this));
        info.token.approve(address(v3pm), supply);

        (uint256 positionId,,,) = v3pm.mint(INonfungiblePositionManager.MintParams({
            token0: token0, token1: token1, fee: FEE,
            tickLower: tickLower, tickUpper: tickUpper,
            amount0Desired: info.wethIsToken0 ? 0 : supply,
            amount1Desired: info.wethIsToken0 ? supply : 0,
            amount0Min: 0, amount1Min: 0,
            recipient: address(this), deadline: block.timestamp
        }));
        info.positionId = positionId;

        emit Launched(tok, pool, positionId, supply);
    }

    // ---------------------------------------------------------------- trading

    function buy(address ta, uint256 minOut) external payable nonReentrant returns (uint256) {
        require(msg.value > 0, "0");
        _check(ta);
        _tryCollect(ta);
        uint256 out = _buy(ta, msg.value, msg.sender);
        require(out >= minOut, "slip");
        return out;
    }

    function sell(address ta, uint256 amt, uint256 minEth) external nonReentrant returns (uint256) {
        require(amt > 0, "0");
        TokenInfo storage info = _check(ta);
        _tryCollect(ta);
        info.token.transferFrom(msg.sender, address(this), amt);

        uint256 wethOut = _swap(ta, address(info.token) == IUniswapV3Pool(info.pool).token0(), amt, address(this));
        IWETH9(weth).withdraw(wethOut);
        require(wethOut >= minEth, "slip");
        (bool s,) = payable(msg.sender).call{value: wethOut}("");
        require(s, "eth");
        emit Trade(ta, msg.sender, false, amt, wethOut);
        return wethOut;
    }

    /// @dev Spends `ethIn` (already held by this contract as ETH) buying `ta` for `to`.
    function _buy(address ta, uint256 ethIn, address to) internal returns (uint256) {
        TokenInfo storage info = tokens[ti[ta]];
        IWETH9(weth).deposit{value: ethIn}();
        // zeroForOne = selling weth for token = weth is the input(token0) side.
        uint256 out = _swap(ta, info.wethIsToken0, ethIn, to);
        emit Trade(ta, to, true, out, ethIn);
        return out;
    }

    /// @dev Exact-input swap on the token's pool. Input token must already be held
    ///      by this contract (WETH for buys, the launch token for sells).
    function _swap(address ta, bool zeroForOne, uint256 amountIn, address recipient)
        internal returns (uint256 amountOut)
    {
        TokenInfo storage info = tokens[ti[ta]];
        (int256 a0, int256 a1) = IUniswapV3Pool(info.pool).swap(
            recipient, zeroForOne, int256(amountIn),
            zeroForOne ? MIN_SQRT_RATIO + 1 : MAX_SQRT_RATIO - 1,
            abi.encode(ta)
        );
        // output is the negative delta of the non-input side.
        amountOut = uint256(-(zeroForOne ? a1 : a0));
    }

    function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external {
        address ta = abi.decode(data, (address));
        TokenInfo storage info = _check(ta);
        require(msg.sender == info.pool, "pool");
        IUniswapV3Pool pool = IUniswapV3Pool(info.pool);
        if (amount0Delta > 0) IERC20(pool.token0()).transfer(msg.sender, uint256(amount0Delta));
        if (amount1Delta > 0) IERC20(pool.token1()).transfer(msg.sender, uint256(amount1Delta));
    }

    // ---------------------------------------------------------- fee sharing

    /// @notice Permissionless: pull accrued LP fees and distribute them.
    function pokeFees(address ta) external nonReentrant {
        _check(ta);
        _collectFees(ta);
    }

    /// @dev Best-effort fee collection during trades: never let a fee-conversion
    ///      revert block buying/selling.
    function _tryCollect(address ta) internal {
        try this.collectFeesSelf(ta) {} catch {}
    }

    function collectFeesSelf(address ta) external {
        require(msg.sender == address(this), "self");
        _collectFees(ta);
    }

    function _collectFees(address ta) internal {
        TokenInfo storage info = tokens[ti[ta]];
        (uint256 a0, uint256 a1) = v3pm.collect(INonfungiblePositionManager.CollectParams({
            tokenId: info.positionId, recipient: address(this),
            amount0Max: type(uint128).max, amount1Max: type(uint128).max
        }));
        (uint256 tokenFee, uint256 wethFee) = info.wethIsToken0 ? (a1, a0) : (a0, a1);
        if (tokenFee == 0 && wethFee == 0) return;

        // Convert the token-denominated portion of fees into WETH so everything is
        // distributed in ETH, matching the claim model.
        if (tokenFee > 0) {
            wethFee += _swap(ta, address(info.token) == IUniswapV3Pool(info.pool).token0(), tokenFee, address(this));
        }
        if (wethFee == 0) return;

        IWETH9(weth).withdraw(wethFee); // WETH -> ETH held by this contract

        uint256 denom = protocolFeeBps + creatorFeeBps;
        uint256 toProtocol = denom == 0 ? 0 : (wethFee * protocolFeeBps) / denom;
        uint256 toCreator = wethFee - toProtocol;

        if (toProtocol > 0) {
            totalFeesCollected += toProtocol;
            (bool ps,) = payable(feeRecipient).call{value: toProtocol}("");
            require(ps, "pf");
        }
        if (toCreator > 0) {
            if (info.distribute) {
                _addHF(ta, toCreator); // pooled pro-rata to holders (ETH kept in contract)
            } else {
                (bool cs,) = payable(info.creator).call{value: toCreator}("");
                require(cs, "cf");
            }
        }
        emit FeesDistributed(ta, toProtocol, toCreator, info.distribute);
    }

    // -------------------------------------------------- reward accounting

    function onTransfer(address ta, address from, address to) external {
        TokenInfo storage info = tokens[ti[ta]];
        require(msg.sender == address(info.token), "only token");
        if (!info.distribute) return;
        _settle(ta, from);
        _settle(ta, to);
    }

    function _excluded(TokenInfo storage info, address a) internal view returns (bool) {
        return a == address(0) || a == DEAD || a == address(this) || a == info.pool || a == address(v3pm);
    }

    function _circulating(TokenInfo storage info) internal view returns (uint256) {
        uint256 s = TOTAL_SUPPLY;
        s -= info.token.balanceOf(address(this));
        s -= info.token.balanceOf(info.pool);
        s -= info.token.balanceOf(DEAD);
        s -= info.token.balanceOf(address(v3pm));
        return s;
    }

    function _settle(address ta, address holder) internal {
        TokenInfo storage info = tokens[ti[ta]];
        if (!info.distribute || _excluded(info, holder)) return;
        uint256 bal = info.token.balanceOf(holder);
        if (bal == 0 || info.fpta <= ufptp[ta][holder]) {
            ufptp[ta][holder] = info.fpta;
            return;
        }
        uint256 pending = (bal * (info.fpta - ufptp[ta][holder])) / PRECISION;
        if (pending > 0) hr[ta][holder] += pending;
        ufptp[ta][holder] = info.fpta;
    }

    function _addHF(address ta, uint256 amt) internal {
        TokenInfo storage info = tokens[ti[ta]];
        if (!info.distribute || amt == 0) return;
        uint256 circ = _circulating(info);
        if (circ < 100e18) {
            // no eligible holders yet; route to creator so ETH is not stranded.
            (bool cs,) = payable(info.creator).call{value: amt}("");
            require(cs, "cf2");
            return;
        }
        info.hfp += amt;
        info.fpta += (amt * PRECISION) / circ;
    }

    function getClaimable(address ta, address holder) public view returns (uint256) {
        TokenInfo storage info = tokens[ti[ta]];
        if (!info.distribute || _excluded(info, holder)) return 0;
        uint256 bal = info.token.balanceOf(holder);
        uint256 pending = bal == 0 ? 0 : (bal * (info.fpta - ufptp[ta][holder])) / PRECISION;
        return hr[ta][holder] + pending;
    }

    function claimRewards(address ta) external nonReentrant returns (uint256) {
        TokenInfo storage info = _check(ta);
        require(info.distribute, "off");
        _tryCollect(ta); // sweep latest LP fees (incl. external Uniswap trades) before paying
        _settle(ta, msg.sender);
        uint256 amt = hr[ta][msg.sender];
        require(amt > 0, "0");
        hr[ta][msg.sender] = 0;
        info.hfp -= amt;
        (bool s,) = payable(msg.sender).call{value: amt}("");
        require(s, "eth");
        emit RewardsClaimed(ta, msg.sender, amt);
        return amt;
    }

    // ------------------------------------------------------------- views

    /// @return price ETH (wei) per whole token, from the live pool price.
    function getPrice(address ta) public view returns (uint256) {
        TokenInfo storage info = _check(ta);
        (uint160 sqrtP,,,,,,) = IUniswapV3Pool(info.pool).slot0();
        // p = rawPrice(token1/token0) * 2^96
        uint256 p = (uint256(sqrtP) * uint256(sqrtP)) >> 96;
        if (p == 0) return 0;
        // return value = (ETH per whole token) * 1e18
        if (info.wethIsToken0) {
            // rawPrice = token/weth  =>  ETH per token = 2^96 / p
            return (uint256(1e18) << 96) / p;
        } else {
            // rawPrice = weth/token  =>  ETH per token = p / 2^96
            return (p * 1e18) >> 96;
        }
    }

    function getMCAP(address ta) public view returns (uint256) {
        return (TOTAL_SUPPLY * getPrice(ta)) / 1e18;
    }

    /// @notice Batch market caps (wei ETH) for a list of tokens — one RPC call for cards.
    function mcapsOf(address[] calldata tas) external view returns (uint256[] memory r) {
        r = new uint256[](tas.length);
        for (uint256 i; i < tas.length; i++) {
            if (reg[tas[i]]) r[i] = getMCAP(tas[i]);
        }
    }

    /// @notice ETH liquidity (wei) currently sitting in a token's pool.
    function poolLiquidityEth(address ta) external view returns (uint256) {
        return IWETH9(weth).balanceOf(_check(ta).pool);
    }

    function getTokenCount() external view returns (uint256) { return tokens.length; }
    function getTokens(uint256 o, uint256 l) external view returns (TokenInfo[] memory r, uint256 t) {
        t = tokens.length;
        uint256 e = o + l; if (e > t) e = t;
        if (o >= e) return (new TokenInfo[](0), t);
        r = new TokenInfo[](e - o);
        for (uint256 i = o; i < e; i++) r[i - o] = tokens[i];
    }
    function getToken(address ta) external view returns (TokenInfo memory) { return _check(ta); }

    // ------------------------------------------------------------- admin

    function setCreationFee(uint256 f) external onlyOwner { creationFee = f; }
    function setProtocolFeeBps(uint256 b) external onlyOwner { protocolFeeBps = b; }
    function setCreatorFeeBps(uint256 b) external onlyOwner { creatorFeeBps = b; }
    function setFeeRecipient(address fr) external onlyOwner { require(fr != address(0), "0"); feeRecipient = fr; }
    function setCurve(int24 _startTick, int24 _tickSpan) external onlyOwner {
        require(_startTick % TICK_SPACING == 0 && _tickSpan % TICK_SPACING == 0 && _tickSpan > 0, "align");
        startTick = _startTick; tickSpan = _tickSpan;
    }

    function _check(address ta) internal view returns (TokenInfo storage) {
        require(reg[ta], "reg");
        return tokens[ti[ta]];
    }

    // --------------------------------------------------- TickMath (0.8 port)

    /// @notice Uniswap V3 TickMath.getSqrtRatioAtTick, ported to Solidity 0.8.
    function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) {
        unchecked {
            uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));
            require(absTick <= 887272, "T");
            uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000;
            if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;
            if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;
            if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;
            if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;
            if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;
            if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;
            if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;
            if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;
            if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;
            if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;
            if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;
            if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;
            if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;
            if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;
            if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;
            if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;
            if (absTick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;
            if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;
            if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;
            if (tick > 0) ratio = type(uint256).max / ratio;
            sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));
        }
    }

    receive() external payable {}
}
Chain explorer1850msChain node126ms