PonsV2LaunchFactory

0x07090eded353736f4403dec96f7163b00e559005

Verification
Verified
v0.8.35+commit.47b9dedd
Type
Contract
15,601 bytes
ABI entries
18
12 read · 2 write
License
mit

Contract information

Address
0x07090eded353736f4403dec96f7163b00e559005
Chain
Robinhood Chain (4663)
Compiler
v0.8.35+commit.47b9dedd
Optimization
Enabled
Creation tx
0x9f0804a92d…12c0e007d4

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (12)

FEE_TIER()uint24
MAX_LAUNCH_ETH()uint256
TOTAL_SUPPLY()uint256
allTokenIds(uint256)uint256
locker()address
nextRegistrationId()uint256
positionManager()address
positions(uint256)address, address, address
registrationData(uint256)string, string, string, string, tuple, address, address, bool
totalLaunched()uint256
treasury()address
weth()address

Events (2)

LaunchedRegistered

ABI

[
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "positionManager_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "weth_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "locker_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "treasury_",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [],
    "name": "ReentrancyGuardReentrantCall",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "registrationId",
        "type": "uint256"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "pool",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "creator",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "string",
        "name": "name",
        "type": "string"
      },
      {
        "indexed": false,
        "internalType": "string",
        "name": "symbol",
        "type": "string"
      }
    ],
    "name": "Launched",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "registrationId",
        "type": "uint256"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "creator",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "launchWallet",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "string",
        "name": "name",
        "type": "string"
      },
      {
        "indexed": false,
        "internalType": "string",
        "name": "symbol",
        "type": "string"
      }
    ],
    "name": "Registered",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "FEE_TIER",
    "outputs": [
      {
        "internalType": "uint24",
        "name": "",
        "type": "uint24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MAX_LAUNCH_ETH",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "TOTAL_SUPPLY",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "allTokenIds",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "registrationId",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "token0",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "token1",
        "type": "address"
      },
      {
        "internalType": "uint160",
        "name": "sqrtPriceX96",
        "type": "uint160"
      },
      {
        "internalType": "int24",
        "name": "tickLower",
        "type": "int24"
      },
      {
        "internalType": "int24",
        "name": "tickUpper",
        "type": "int24"
      }
    ],
    "name": "launch",
    "outputs": [
      {
        "internalType": "address",
        "name": "tokenAddress",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "pool",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "locker",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "nextRegistrationId",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "positionManager",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "positions",
    "outputs": [
      {
        "internalType": "address",
        "name": "creator",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "pool",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "string",
        "name": "name_",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "symbol_",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "description_",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "logo_",
        "type": "string"
      },
      {
        "components": [
          {
            "internalType": "string",
            "name": "telegram",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "twitter",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "discord",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "website",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "farcaster",
            "type": "string"
          }
        ],
        "internalType": "struct SocialLinks",
        "name": "socials_",
        "type": "tuple"
      },
      {
        "internalType": "address",
        "name": "creator_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "launchWallet_",
        "type": "address"
      }
    ],
    "name": "register",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "registrationId",
        "type": "uint256"
      }
    ],
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "registrationData",
    "outputs": [
      {
        "internalType": "string",
        "name": "name",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "symbol",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "description",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "logo",
        "type": "string"
      },
      {
        "components": [
          {
            "internalType": "string",
            "name": "telegram",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "twitter",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "discord",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "website",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "farcaster",
            "type": "string"
          }
        ],
        "internalType": "struct SocialLinks",
        "name": "socials",
        "type": "tuple"
      },
      {
        "internalType": "address",
        "name": "creator",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "launchWallet",
        "type": "address"
      },
      {
        "internalType": "bool",
        "name": "launched",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalLaunched",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "treasury",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "weth",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  }
]

Source code

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

import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./PonsV2Token.sol";

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

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

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

interface IPonsV2LaunchLocker {
    function registerPosition(uint256 tokenId, address creator, address token) external;
}

contract PonsV2LaunchFactory is ReentrancyGuard {
    uint256 public constant TOTAL_SUPPLY  = 1_000_000_000 * 10 ** 18;
    uint24  public constant FEE_TIER      = 10000;
    uint256 public constant MAX_LAUNCH_ETH = 0.001 ether;

    address public immutable positionManager;
    address public immutable weth;
    address public immutable locker;
    address public immutable treasury;

    struct Registration {
        string      name;
        string      symbol;
        string      description;
        string      logo;
        SocialLinks socials;
        address     creator;
        address     launchWallet;
        bool        launched;
    }

    uint256 public nextRegistrationId;
    mapping(uint256 => Registration) public registrationData;

    struct Position {
        address creator;
        address token;
        address pool;
    }

    mapping(uint256 => Position) public positions;
    uint256[] public allTokenIds;

    event Registered(
        uint256 indexed registrationId,
        address indexed creator,
        address indexed launchWallet,
        string name,
        string symbol
    );

    event Launched(
        uint256 indexed registrationId,
        address indexed token,
        address indexed pool,
        uint256 tokenId,
        address creator,
        string name,
        string symbol
    );

    constructor(
        address positionManager_,
        address weth_,
        address locker_,
        address treasury_
    ) {
        require(positionManager_ != address(0), "Zero positionManager");
        require(weth_ != address(0), "Zero weth");
        require(locker_ != address(0), "Zero locker");
        require(treasury_ != address(0), "Zero treasury");
        positionManager = positionManager_;
        weth = weth_;
        locker = locker_;
        treasury = treasury_;
    }

    function register(
        string memory name_,
        string memory symbol_,
        string memory description_,
        string memory logo_,
        SocialLinks memory socials_,
        address creator_,
        address launchWallet_
    ) external payable returns (uint256 registrationId) {
        address creator = (creator_ == address(0)) ? msg.sender : creator_;

        registrationId = nextRegistrationId++;
        registrationData[registrationId] = Registration({
            name:         name_,
            symbol:       symbol_,
            description:  description_,
            logo:         logo_,
            socials:      socials_,
            creator:      creator,
            launchWallet: launchWallet_,
            launched:     false
        });

        if (msg.value > 0) {
            require(launchWallet_ != address(0), "launchWallet required to forward ETH");
            uint256 toForward = msg.value > MAX_LAUNCH_ETH ? MAX_LAUNCH_ETH : msg.value;
            uint256 excess = msg.value - toForward;
            (bool ok,) = launchWallet_.call{value: toForward}("");
            require(ok, "ETH forward failed");
            if (excess > 0) {
                (bool ok2,) = msg.sender.call{value: excess}("");
                require(ok2, "ETH refund failed");
            }
        }

        emit Registered(registrationId, creator, launchWallet_, name_, symbol_);
    }

    function launch(
        uint256 registrationId,
        address token0,
        address token1,
        uint160 sqrtPriceX96,
        int24 tickLower,
        int24 tickUpper
    ) external nonReentrant returns (address tokenAddress, address pool) {
        Registration storage reg = registrationData[registrationId];
        require(reg.creator != address(0), "Unknown registration");
        require(!reg.launched, "Already launched");
        require(token0 < token1, "token0 must be < token1");

        if (reg.launchWallet != address(0)) {
            require(msg.sender == reg.launchWallet, "Only launchWallet");
        }

        reg.launched = true;

        PonsV2Token token = new PonsV2Token(
            reg.name,
            reg.symbol,
            TOTAL_SUPPLY,
            reg.description,
            reg.logo,
            reg.socials,
            reg.creator,
            address(this)
        );
        tokenAddress = address(token);
        require(
            tokenAddress == token0 || tokenAddress == token1,
            "Token address mismatch"
        );

        require(
            IERC20(tokenAddress).transferFrom(reg.creator, address(this), TOTAL_SUPPLY),
            "Token pull failed"
        );
        require(
            IERC20(tokenAddress).approve(positionManager, TOTAL_SUPPLY),
            "Approve failed"
        );

        pool = IPositionManagerFactory(positionManager).createAndInitializePoolIfNecessary(
            token0, token1, FEE_TIER, sqrtPriceX96
        );

        uint256 amount0Desired = (tokenAddress == token0) ? TOTAL_SUPPLY : 0;
        uint256 amount1Desired = (tokenAddress == token1) ? TOTAL_SUPPLY : 0;

        (uint256 tokenId,,,) = IPositionManagerFactory(positionManager).mint(
            IPositionManagerFactory.MintParams({
                token0:         token0,
                token1:         token1,
                fee:            FEE_TIER,
                tickLower:      tickLower,
                tickUpper:      tickUpper,
                amount0Desired: amount0Desired,
                amount1Desired: amount1Desired,
                amount0Min:     0,
                amount1Min:     0,
                recipient:      locker,
                deadline:       block.timestamp + 1800
            })
        );

        IPonsV2LaunchLocker(locker).registerPosition(tokenId, reg.creator, tokenAddress);

        positions[tokenId] = Position({
            creator: reg.creator,
            token:   tokenAddress,
            pool:    pool
        });
        allTokenIds.push(tokenId);

        emit Launched(
            registrationId,
            tokenAddress,
            pool,
            tokenId,
            reg.creator,
            reg.name,
            reg.symbol
        );
    }

    function totalLaunched() external view returns (uint256) {
        return allTokenIds.length;
    }
}
Chain explorer3846msChain node83ms