NoxaLaunchpad

0xdc50697eb61d1fcfa7658208d59fc628bbbe59aa

Verification
Verified
v0.8.28+commit.7893614a
Type
Contract
7,937 bytes
ABI entries
43
19 read · 8 write
License
none

Contract information

Address
0xdc50697eb61d1fcfa7658208d59fc628bbbe59aa
Chain
Robinhood Chain (4663)
Compiler
v0.8.28+commit.7893614a
Optimization
Enabled
Creation tx
0xad3d999d60…bd6983baea

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (19)

BPS()uint256
LAUNCH_FEE()uint256
LP_FEE_BPS()uint256
NAME_SUFFIX()string
PLATFORM()string
WEBSITE()string
creatorLaunchCount(address)uint256
feeExempt(address)bool
getLaunch(uint256)address, address, address, uint256, uint256, uint256, uint256, uint256
isFeeExempt(address)bool
launchCount()uint256
launchIdByToken(address)uint256
launches(uint256)address, address, address, uint256, uint256, uint256, uint256, uint256
launchesByCreator(address, uint256)uint256
owner()address
ownershipHandoverExpiresAt(address)uint256
router()address
treasury()address
weth()address

Events (6)

FeeExemptSetLaunchedOwnershipHandoverCanceledOwnershipHandoverRequestedOwnershipTransferredTreasurySet

ABI

[
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "router_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "treasury_",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [],
    "name": "AlreadyInitialized",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "BadConfig",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "BadValue",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NewOwnerIsZeroAddress",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NoHandoverRequest",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "TransferFailed",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "Unauthorized",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "ZeroAddress",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "account",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "exempt",
        "type": "bool"
      }
    ],
    "name": "FeeExemptSet",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "id",
        "type": "uint256"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "creator",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "pair",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "ethLiquidity",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "tokenLiquidity",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "lpToCreator",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "lpToTreasury",
        "type": "uint256"
      }
    ],
    "name": "Launched",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "pendingOwner",
        "type": "address"
      }
    ],
    "name": "OwnershipHandoverCanceled",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "pendingOwner",
        "type": "address"
      }
    ],
    "name": "OwnershipHandoverRequested",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "oldOwner",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "OwnershipTransferred",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "address",
        "name": "treasury",
        "type": "address"
      }
    ],
    "name": "TreasurySet",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "BPS",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "LAUNCH_FEE",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "LP_FEE_BPS",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "NAME_SUFFIX",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "PLATFORM",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "WEBSITE",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "cancelOwnershipHandover",
    "outputs": [],
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "pendingOwner",
        "type": "address"
      }
    ],
    "name": "completeOwnershipHandover",
    "outputs": [],
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "creator",
        "type": "address"
      }
    ],
    "name": "creatorLaunchCount",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "feeExempt",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "id",
        "type": "uint256"
      }
    ],
    "name": "getLaunch",
    "outputs": [
      {
        "internalType": "address",
        "name": "creator",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "pair",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "ethLiquidity",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "tokenLiquidity",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "lpToCreator",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "lpToTreasury",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "timestamp",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "isFeeExempt",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "string",
        "name": "name_",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "symbol_",
        "type": "string"
      },
      {
        "internalType": "uint256",
        "name": "totalSupply",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "tokenForLp",
        "type": "uint256"
      }
    ],
    "name": "launch",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "id",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "pair",
        "type": "address"
      }
    ],
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "launchCount",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "launchIdByToken",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "launches",
    "outputs": [
      {
        "internalType": "address",
        "name": "creator",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "pair",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "ethLiquidity",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "tokenLiquidity",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "lpToCreator",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "lpToTreasury",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "timestamp",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "launchesByCreator",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "internalType": "address",
        "name": "result",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "pendingOwner",
        "type": "address"
      }
    ],
    "name": "ownershipHandoverExpiresAt",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "result",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "renounceOwnership",
    "outputs": [],
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "requestOwnershipHandover",
    "outputs": [],
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "router",
    "outputs": [
      {
        "internalType": "contract IUniswapV2Router02",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      },
      {
        "internalType": "bool",
        "name": "exempt",
        "type": "bool"
      }
    ],
    "name": "setFeeExempt",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "treasury_",
        "type": "address"
      }
    ],
    "name": "setTreasury",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "transferOwnership",
    "outputs": [],
    "stateMutability": "payable",
    "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"
  },
  {
    "stateMutability": "payable",
    "type": "receive"
  }
]

Source code

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

import {Ownable} from "../lib/solady/src/auth/Ownable.sol";
import {ERC20} from "../lib/solady/src/tokens/ERC20.sol";

interface IUniswapV2Router02 {
    function factory() external view returns (address);
    function WETH() external view returns (address);

    function addLiquidityETH(
        address token,
        uint256 amountTokenDesired,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external payable returns (uint256 amountToken, uint256 amountETH, uint256 liquidity);
}

interface IUniswapV2Factory {
    function getPair(address tokenA, address tokenB) external view returns (address pair);
}

interface IERC20Lite {
    function balanceOf(address) external view returns (uint256);
    function transfer(address, uint256) external returns (bool);
    function approve(address, uint256) external returns (bool);
}

/// @notice NOXA ERC-20. Name is branded with noxafun.eth.limo for discovery.
contract NoxaToken is ERC20 {
    string private _name;
    string private _symbol;

    constructor(string memory name_, string memory symbol_, uint256 supply, address to) {
        _name = name_;
        _symbol = symbol_;
        _mint(to, supply);
    }

    function name() public view override returns (string memory) {
        return _name;
    }

    function symbol() public view override returns (string memory) {
        return _symbol;
    }

    /// @dev Shown on Blockscout "Read contract" — points explorers / users to the pad.
    function website() external pure returns (string memory) {
        return "https://noxafun.eth.limo";
    }

    function platform() external pure returns (string memory) {
        return "NOXA";
    }
}

/// @title NoxaLaunchpad
/// @notice Create ERC-20 + Uniswap V2 ETH pair.
///         Public fee: 0.002 ETH + 5% of LP. Owner / feeExempt: zero fees.
contract NoxaLaunchpad is Ownable {
    uint256 public constant LAUNCH_FEE = 0.002 ether;
    uint256 public constant LP_FEE_BPS = 500; // 5%
    uint256 public constant BPS = 10_000;

    /// @notice Shown on Blockscout read methods for the pad itself.
    string public constant WEBSITE = "https://noxafun.eth.limo";
    string public constant PLATFORM = "NOXA";
    string public constant NAME_SUFFIX = " | noxafun.eth.limo";

    IUniswapV2Router02 public immutable router;
    address public immutable weth;
    address public treasury;

    uint256 public launchCount;

    struct Launch {
        address creator;
        address token;
        address pair;
        uint256 ethLiquidity;
        uint256 tokenLiquidity;
        uint256 lpToCreator;
        uint256 lpToTreasury;
        uint256 timestamp;
    }

    mapping(uint256 => Launch) public launches;
    mapping(address => uint256[]) public launchesByCreator;
    mapping(address => bool) public feeExempt;
    mapping(address => uint256) public launchIdByToken;

    error BadValue();
    error BadConfig();
    error ZeroAddress();
    error TransferFailed();

    event Launched(
        uint256 indexed id,
        address indexed creator,
        address token,
        address pair,
        uint256 ethLiquidity,
        uint256 tokenLiquidity,
        uint256 lpToCreator,
        uint256 lpToTreasury
    );
    event TreasurySet(address treasury);
    event FeeExemptSet(address indexed account, bool exempt);

    constructor(address router_, address treasury_) {
        if (router_ == address(0) || treasury_ == address(0)) revert ZeroAddress();
        _initializeOwner(msg.sender);
        router = IUniswapV2Router02(router_);
        weth = IUniswapV2Router02(router_).WETH();
        treasury = treasury_;
        feeExempt[msg.sender] = true;
        emit FeeExemptSet(msg.sender, true);
    }

    function setTreasury(address treasury_) external onlyOwner {
        if (treasury_ == address(0)) revert ZeroAddress();
        treasury = treasury_;
        emit TreasurySet(treasury_);
    }

    function setFeeExempt(address account, bool exempt) external onlyOwner {
        if (account == address(0)) revert ZeroAddress();
        feeExempt[account] = exempt;
        emit FeeExemptSet(account, exempt);
    }

    function isFeeExempt(address account) public view returns (bool) {
        return account == owner() || feeExempt[account];
    }

    /// @notice Launch token + LP.
    /// @dev Public: msg.value = LAUNCH_FEE + ETH for liquidity.
    ///      Fee-exempt (owner/admin): msg.value = ETH for liquidity only (no pad fee, no LP cut).
    function launch(
        string calldata name_,
        string calldata symbol_,
        uint256 totalSupply,
        uint256 tokenForLp
    ) external payable returns (uint256 id, address token, address pair) {
        if (totalSupply == 0 || tokenForLp == 0 || tokenForLp > totalSupply) revert BadConfig();
        if (bytes(name_).length == 0 || bytes(symbol_).length == 0) revert BadConfig();

        bool exempt = isFeeExempt(msg.sender);
        uint256 fee = exempt ? 0 : LAUNCH_FEE;
        if (msg.value <= fee) revert BadValue();
        uint256 ethForLp = msg.value - fee;

        if (fee != 0) {
            (bool ok,) = treasury.call{value: fee}("");
            if (!ok) revert TransferFailed();
        }

        string memory branded = string.concat(name_, NAME_SUFFIX);
        NoxaToken t = new NoxaToken(branded, symbol_, totalSupply, address(this));
        token = address(t);

        IERC20Lite(token).approve(address(router), tokenForLp);
        uint256 deadline = block.timestamp + 30 minutes;
        (,, uint256 liquidity) =
            router.addLiquidityETH{value: ethForLp}(token, tokenForLp, 0, 0, address(this), deadline);

        pair = IUniswapV2Factory(router.factory()).getPair(token, weth);
        if (pair == address(0)) revert BadConfig();

        uint256 lpTreasury = exempt ? 0 : (liquidity * LP_FEE_BPS) / BPS;
        uint256 lpCreator = liquidity - lpTreasury;
        _splitLp(pair, msg.sender, lpTreasury, lpCreator);

        uint256 leftover = totalSupply - tokenForLp;
        if (leftover != 0) {
            if (!IERC20Lite(token).transfer(msg.sender, leftover)) revert TransferFailed();
        }

        id = ++launchCount;
        Launch storage L = launches[id];
        L.creator = msg.sender;
        L.token = token;
        L.pair = pair;
        L.ethLiquidity = ethForLp;
        L.tokenLiquidity = tokenForLp;
        L.lpToCreator = lpCreator;
        L.lpToTreasury = lpTreasury;
        L.timestamp = block.timestamp;
        launchesByCreator[msg.sender].push(id);
        launchIdByToken[token] = id;

        emit Launched(
            id, msg.sender, token, pair, ethForLp, tokenForLp, lpCreator, lpTreasury
        );
    }

    function _splitLp(address pair, address creator, uint256 lpTreasury, uint256 lpCreator)
        internal
    {
        if (lpTreasury != 0) {
            if (!IERC20Lite(pair).transfer(treasury, lpTreasury)) revert TransferFailed();
        }
        if (lpCreator != 0) {
            if (!IERC20Lite(pair).transfer(creator, lpCreator)) revert TransferFailed();
        }
    }

    function creatorLaunchCount(address creator) external view returns (uint256) {
        return launchesByCreator[creator].length;
    }

    function getLaunch(uint256 id)
        external
        view
        returns (
            address creator,
            address token,
            address pair,
            uint256 ethLiquidity,
            uint256 tokenLiquidity,
            uint256 lpToCreator,
            uint256 lpToTreasury,
            uint256 timestamp
        )
    {
        Launch storage L = launches[id];
        return (
            L.creator,
            L.token,
            L.pair,
            L.ethLiquidity,
            L.tokenLiquidity,
            L.lpToCreator,
            L.lpToTreasury,
            L.timestamp
        );
    }

    receive() external payable {}
}
Chain explorer3208msChain node77ms