LemonCurveFactory

0x4924d006edd8c142eb3f78c4e8437bf718764485

Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
12,449 bytes
ABI entries
12
9 read · 1 write
License
none

Contract information

Address
0x4924d006edd8c142eb3f78c4e8437bf718764485
Chain
Robinhood Chain (4663)
Compiler
v0.8.26+commit.8a97fa7a
Optimization
Enabled
Creation tx
0xfa5dc6bb18…730017533e

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (9)

ANTI_SNIPE_MAX_WALLET()uint256
ANTI_SNIPE_WINDOW_SECS()uint256
POOL_FEE()uint24
TOKEN_SUPPLY()uint256
curveDeployer()address
getTokenInfo(address)tuple
launches(address)address, address, address, uint256, uint16, uint8
platformFeeReceiver()address
weth()address

Events (1)

CurveLaunched

ABI

[
  {
    "inputs": [
      {
        "internalType": "contract IWETH",
        "name": "_weth",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "_platformFeeReceiver",
        "type": "address"
      },
      {
        "internalType": "contract CurveDeployer",
        "name": "_curveDeployer",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "curve",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "deployer",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "dexFactory",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "positionManager",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint8",
        "name": "dexKind",
        "type": "uint8"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "graduationThreshold",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint16",
        "name": "creatorFeeBps",
        "type": "uint16"
      },
      {
        "indexed": false,
        "internalType": "string",
        "name": "name",
        "type": "string"
      },
      {
        "indexed": false,
        "internalType": "string",
        "name": "symbol",
        "type": "string"
      },
      {
        "indexed": false,
        "internalType": "string",
        "name": "tokenURI",
        "type": "string"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "timestamp",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "virtualTokenReserve",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "virtualEthReserve",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "totalSupply",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "initialTokenReserve",
        "type": "uint256"
      }
    ],
    "name": "CurveLaunched",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "ANTI_SNIPE_MAX_WALLET",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "ANTI_SNIPE_WINDOW_SECS",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "POOL_FEE",
    "outputs": [
      {
        "internalType": "uint24",
        "name": "",
        "type": "uint24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "TOKEN_SUPPLY",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "curveDeployer",
    "outputs": [
      {
        "internalType": "contract CurveDeployer",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      }
    ],
    "name": "getTokenInfo",
    "outputs": [
      {
        "components": [
          {
            "internalType": "address",
            "name": "token",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "curve",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "deployer",
            "type": "address"
          },
          {
            "internalType": "uint256",
            "name": "graduationThreshold",
            "type": "uint256"
          },
          {
            "internalType": "uint16",
            "name": "creatorFeeBps",
            "type": "uint16"
          },
          {
            "internalType": "uint8",
            "name": "dexKind",
            "type": "uint8"
          },
          {
            "internalType": "bool",
            "name": "graduated",
            "type": "bool"
          },
          {
            "internalType": "address",
            "name": "poolAfterGraduation",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "lpLocker",
            "type": "address"
          },
          {
            "internalType": "uint256",
            "name": "tokenReserve",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "ethReserve",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "virtualTokenReserve",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "virtualEthReserve",
            "type": "uint256"
          }
        ],
        "internalType": "struct LemonCurveFactory.TokenInfo",
        "name": "info",
        "type": "tuple"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "components": [
          {
            "internalType": "string",
            "name": "name",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "symbol",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "tokenURI",
            "type": "string"
          },
          {
            "internalType": "address",
            "name": "dexFactory",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "positionManager",
            "type": "address"
          },
          {
            "internalType": "uint8",
            "name": "dexKind",
            "type": "uint8"
          },
          {
            "internalType": "uint256",
            "name": "graduationThreshold",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "virtualTokenReserve",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "virtualEthReserve",
            "type": "uint256"
          },
          {
            "internalType": "uint16",
            "name": "creatorFeeBps",
            "type": "uint16"
          },
          {
            "internalType": "address",
            "name": "creatorFeeReceiver",
            "type": "address"
          },
          {
            "internalType": "string",
            "name": "logoURI",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "description",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "twitter",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "telegram",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "website",
            "type": "string"
          }
        ],
        "internalType": "struct LemonCurveFactory.LaunchParams",
        "name": "p",
        "type": "tuple"
      }
    ],
    "name": "launch",
    "outputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "curve",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      }
    ],
    "name": "launches",
    "outputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "curve",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "deployer",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "graduationThreshold",
        "type": "uint256"
      },
      {
        "internalType": "uint16",
        "name": "creatorFeeBps",
        "type": "uint16"
      },
      {
        "internalType": "uint8",
        "name": "dexKind",
        "type": "uint8"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "platformFeeReceiver",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "weth",
    "outputs": [
      {
        "internalType": "contract IWETH",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  }
]

Source code

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

import {LemonToken} from "./LemonToken.sol";
import {BondingCurve} from "./BondingCurve.sol";
import {IUniswapV3Factory, IUniswapV3Pool, INonfungiblePositionManager, IWETH} from "./interfaces/IUniswap.sol";
import {CurveDeployer} from "./deployers/CurveDeployer.sol";

/// @notice Factory that deploys LemonToken + BondingCurve pairs.
///
/// LemonToken is deployed directly by this factory so explorers/scanners see
/// the same one-hop internal contract-creation trace as the reference launchpad.
/// The large BondingCurve bytecode remains behind CurveDeployer to keep the
/// factory under EIP-170 without hiding the token deployment from indexers.
contract LemonCurveFactory {
    uint256 public constant TOKEN_SUPPLY = 1_000_000_000e18;
    uint24  public constant POOL_FEE = 10_000;
    uint256 public constant ANTI_SNIPE_MAX_WALLET = 10_000_000e18; // 1% of supply, scanner parity
    uint256 public constant ANTI_SNIPE_WINDOW_SECS = 900;

    IWETH public immutable weth;
    address public immutable platformFeeReceiver;
    CurveDeployer public immutable curveDeployer;

    struct Launched {
        address token;
        address curve;
        address deployer;
        uint256 graduationThreshold;
        uint16  creatorFeeBps;
        uint8   dexKind;    // 0 = Uniswap, 1 = Sushi
    }

    mapping(address token => Launched) public launches;

    event CurveLaunched(
        address indexed token,
        address indexed curve,
        address indexed deployer,
        address dexFactory,
        address positionManager,
        uint8   dexKind,
        uint256 graduationThreshold,
        uint16  creatorFeeBps,
        string  name,
        string  symbol,
        string  tokenURI,
        uint256 timestamp,
        uint256 virtualTokenReserve,
        uint256 virtualEthReserve,
        uint256 totalSupply,
        uint256 initialTokenReserve
    );

    constructor(
        IWETH _weth,
        address _platformFeeReceiver,
        CurveDeployer _curveDeployer
    ) {
        weth = _weth;
        platformFeeReceiver = _platformFeeReceiver;
        curveDeployer = _curveDeployer;
    }

    struct LaunchParams {
        string  name;
        string  symbol;
        string  tokenURI;
        address dexFactory;
        address positionManager;
        uint8   dexKind;
        uint256 graduationThreshold;
        uint256 virtualTokenReserve;
        uint256 virtualEthReserve;
        uint16  creatorFeeBps;
        address creatorFeeReceiver;
        // On-chain metadata
        string  logoURI;
        string  description;
        string  twitter;
        string  telegram;
        string  website;
    }

    function launch(LaunchParams calldata p) external returns (address token, address curve) {
        require(bytes(p.name).length > 0 && bytes(p.symbol).length > 0, "meta");
        require(p.dexFactory != address(0) && p.positionManager != address(0), "dex");
        require(p.graduationThreshold > 0, "threshold=0");
        require(p.virtualEthReserve > 0 && p.virtualTokenReserve > 0, "vreserves");
        require(p.creatorFeeBps <= 1000, "creatorFee>10%");
        require(p.dexKind <= 1, "dexKind");

        token = address(new LemonToken(
            p.name,
            p.symbol,
            TOKEN_SUPPLY,
            address(this),
            p.logoURI,
            p.description,
            p.twitter,
            p.telegram,
            p.website
        ));

        curve = curveDeployer.deployCurve(CurveDeployer.Args({
            token: LemonToken(token),
            weth: weth,
            dexFactory: p.dexFactory,
            positionManager: p.positionManager,
            deployer: msg.sender,
            creatorFeeReceiver: p.creatorFeeReceiver == address(0) ? msg.sender : p.creatorFeeReceiver,
            platformFeeReceiver: platformFeeReceiver,
            creatorFeeBps: p.creatorFeeBps,
            graduationThreshold: p.graduationThreshold,
            virtualTokenReserve: p.virtualTokenReserve,
            virtualEthReserve: p.virtualEthReserve,
            stocksVault: address(0),
            vaultBps: uint16(0)
        }));

        _finalizeLaunch(token, curve);

        launches[token] = Launched({
            token: token,
            curve: curve,
            deployer: msg.sender,
            graduationThreshold: p.graduationThreshold,
            creatorFeeBps: p.creatorFeeBps,
            dexKind: p.dexKind
        });

        _emitCurveLaunched(token, curve, p);
    }

    /// @dev Seeds the curve with the full supply and locks in the launch
    /// protections. Pool wiring happens later, inside BondingCurve._graduate().
    function _finalizeLaunch(address token, address curve) internal {
        LemonToken tok = LemonToken(token);
        require(tok.transfer(curve, tok.totalSupply()), "seed");
        tok.configureLaunch(ANTI_SNIPE_MAX_WALLET, 0, ANTI_SNIPE_WINDOW_SECS);
        tok.initPoolSetter(curve);
    }

    function _emitCurveLaunched(address token, address curve, LaunchParams calldata p) internal {
        uint256 supply = LemonToken(token).totalSupply();
        emit CurveLaunched(
            token, curve, msg.sender,
            p.dexFactory, p.positionManager, p.dexKind,
            p.graduationThreshold, p.creatorFeeBps,
            p.name, p.symbol, p.tokenURI,
            block.timestamp,
            p.virtualTokenReserve, p.virtualEthReserve,
            supply, supply
        );
    }

    // --- Views ---

    struct TokenInfo {
        address token;
        address curve;
        address deployer;
        uint256 graduationThreshold;
        uint16  creatorFeeBps;
        uint8   dexKind;
        bool    graduated;
        address poolAfterGraduation;
        address lpLocker;
        uint256 tokenReserve;
        uint256 ethReserve;
        uint256 virtualTokenReserve;
        uint256 virtualEthReserve;
    }

    function getTokenInfo(address token) external view returns (TokenInfo memory info) {
        Launched memory L = launches[token];
        info.token = L.token;
        info.curve = L.curve;
        info.deployer = L.deployer;
        info.graduationThreshold = L.graduationThreshold;
        info.creatorFeeBps = L.creatorFeeBps;
        info.dexKind = L.dexKind;
        if (L.curve == address(0)) return info;
        BondingCurve c = BondingCurve(payable(L.curve));
        info.graduated = c.graduated();
        info.poolAfterGraduation = c.poolAfterGraduation();
        info.lpLocker = c.lpLockerAddress();
        info.tokenReserve = c.tokenReserve();
        info.ethReserve = c.ethReserve();
        info.virtualTokenReserve = c.virtualTokenReserve();
        info.virtualEthReserve = c.virtualEthReserve();
    }
}
Chain explorer6113msChain node957ms