Beta software, reviewed internally with automated tools and tests; not yet independently audited. Memecoins are extremely risky; you can lose everything.
🔥 Trending appears here once tokens get real activity (5+ different traders in 24h).

Build on Liquidmint

Everything a bot, terminal or aggregator needs to recognise our tokens and trade them. All of it is also available as one JSON document at /api/info, and the contract definitions at /api/abi/launcher, /token and /hook.

Contracts on Robinhood Chain (chain 4663)

This site is not connected to a launcher yet. Our own addresses are published here at launch; Uniswap's are listed already.

Launcher (creates tokens, collects fees)published at launch
Launch hook (sets the fee on every swap)published at launch
Token implementation (every token is a clone of it)published at launch
Uniswap V4 PoolManager↗
Universal Router (Robinhood's modified version)↗
V4Quoter↗
StateView↗
Permit2↗
Multicall3↗

How to recognise a Liquidmint token

  • Listen to TokenCreated(token, creator, name, symbol) on the launcher
  • or: PoolManager Initialize events whose hooks field equals the Liquidmint hook
  • confirm with launcher.launchOf(token): the creator is not the zero address
  • a pool for the same token with a different hook is NOT ours

Pools

Every token has its own Uniswap V4 pool, created in the launch transaction: currency0 is native ETH (the zero address), currency1 is the token, pool fee static: the creator's choice at launch (0, 3000, 5000 or 10000: read it from the pool key), tick spacing 200, hooks = the launch hook. Pool id = keccak256(abi.encode(poolKey)). Supply is 1,000,000,000 tokens. The liquidity is locked: the launcher has no function that removes it, and the hook rejects any removal. Price in ETH per token = 1 / (sqrtPriceX96 / 2^96)^2, read with StateView.getSlot0(poolId).

Fees, and the launch tax your bot will meet

  • Every swap pays a 1% protocol fee, taken by the hook itself on the INPUT currency (buys pay it in ETH, sells in tokens) and split per token between the creator and the platform (default 85% creator, fixed at launch). Outside liquidity providers cannot dilute it.
  • On top, the pool has a pool fee the creator chose at launch (none by default, or 0.3%, 0.5% or 1%), which goes to liquidity providers. Total cost to a trader = protocol fee + pool fee.
  • Launch tax: buys pay a fee falling in a straight line from 99% to 1% over 30 seconds, counted on the chain's clock from the launch block. Sells are never taxed, and only the launcher's own first buy (in the launch transaction) is exempt: there is no whitelist. The tax is burned.
  • The fee right now: hook.currentFee(sender, poolKey, zeroForOne). The tax held by the hook until the launcher sweeps and burns it: hook.taxEth(poolId).
  • Reading trades: the PoolManager's Swap event reports the pool-level amounts, net of the hook's fee. What a trader actually paid is the pool-level input plus the fee in the hook'sFeeTaken event for the same swap (below). An exact-input swap the pool cannot fill in full reverts (PartialFill), and the hook takes its ETH fee from the PoolManager's own balance while the buyer's ETH is not yet paid in.
  • Uniswap's V4Quoter runs the real swap, so quotes already include the hook's fee. A quote is computed at the latest block's time, so just after a launch it can be worse than a transaction mined a moment later (the tax only falls).
  • Fees paid in tokens (by sellers): the platform's share is always burned; the creator can pledge to burn a share of theirs: launcher.burnBpsOf(token). Tokens burned from fees so far: launcher.feeBurned(token).

Trading through the Universal Router

Plain ETH in, tokens out, one transaction; no wrapping. The code below is what our own site sends (it is tested against a copy of the real chain).

import { encodeAbiParameters } from "viem";

const poolKey = [{ name: "currency0", type: "address" }, { name: "currency1", type: "address" }, { name: "fee", type: "uint24" },
                 { name: "tickSpacing", type: "int24" }, { name: "hooks", type: "address" }];
// Robinhood's Universal Router has ONE extra field (minHopPriceX36, always 0) between amountOutMinimum and hookData.
const swap = { type: "tuple", components: [
  { name: "poolKey", type: "tuple", components: poolKey }, { name: "zeroForOne", type: "bool" }, { name: "amountIn", type: "uint128" },
  { name: "amountOutMinimum", type: "uint128" }, { name: "minHopPriceX36", type: "uint256" }, { name: "hookData", type: "bytes" } ] };

function plan(key, zeroForOne, amountIn, minOut) {
  const s = encodeAbiParameters([swap], [{ poolKey: key, zeroForOne, amountIn, amountOutMinimum: minOut, minHopPriceX36: 0n, hookData: "0x" }]);
  const settle = encodeAbiParameters([{ type: "address" }, { type: "uint256" }], [zeroForOne ? key.currency0 : key.currency1, amountIn]);
  const take = encodeAbiParameters([{ type: "address" }, { type: "uint256" }], [zeroForOne ? key.currency1 : key.currency0, minOut]);
  return encodeAbiParameters([{ type: "bytes" }, { type: "bytes[]" }], ["0x060c0f", [s, settle, take]]); // SWAP_EXACT_IN_SINGLE, SETTLE_ALL, TAKE_ALL
}

// BUY with plain ETH:   router.execute("0x10", [plan(key, true,  ethIn,    minTokensOut)], deadline, { value: ethIn })
// SELL for plain ETH:   router.execute("0x10", [plan(key, false, tokensIn, minEthOut)],   deadline)
//   (command 0x10 = V4_SWAP; our tokens start with an unlimited allowance for Permit2, so a sell needs one Permit2.approve(token, router, amount, expiry),
//    or a signed PermitSingle sent first with command 0x0a: use commands "0x0a10" and inputs [permitInput, plan(...)])
// Quote first with the V4Quoter: quoteExactInputSingle({ poolKey, zeroForOne, exactAmount, hookData: "0x" })

Events on the launcher

TokenCreated(address,address,string,string)
topic0 0xd5d05a8421149c74fd223cfc823befb883babf9bf0b0e4d6bf9c8fdb70e59bb4
TokenLaunched(address,address,bytes32,uint16,uint256,uint256)
topic0 0xdb653d9b1ab7180b64367761830c0f179697f80ef30518ae5c57d15d193cb045
FeesCollected(address,uint256,uint256,uint256,uint256,uint256)
topic0 0xafaf36277fa8ba33159f6c848d1abc449f7088296a631cc23ab278089077270d
FeeTokensBurned(address,uint256,uint256)
topic0 0xd73754d39d1aa0ad215853f3d96fe15aae624d8c80d67d45182e1de6bf7f98f4
PayoutProposed(address,address,uint64)
topic0 0x5c452240ce691963bd28ae11aabb810102af332dfa15369ef531425d221cfe55
PayoutChanged(address,address)
topic0 0x58a5ff072be0c939808b8ba8c3c7009527337e9b9a3b050f8cc0221b09e1a3c1
PayoutCredited(address,uint256)
topic0 0xfa0ea8a012f094d1b6f48df9238391dcbfbbda9acf72c5fa9b26c32451e98a61
Claimed(address,uint256)
topic0 0xd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a
CreatorBpsChanged(uint16)
topic0 0xa4c02a8c60acb61d54741b069157ad64f0e1f1dd035602a9cbbd7278d71ad573
LaunchesPaused(bool)
topic0 0x9db7e995f72cf48cec75587f3da433a60fdca8fb8bb4fcfea16d7fbc2e4751d8

Event on the hook

FeeTaken(bytes32,bool,uint256,uint24)
topic0 0x1f8f211cefe95b4ded59b51db3356ecc6ee1e5774998f6f48436db4dd6d17bcf