ZeroHoodlaunch app

technical reference

ZeroHood — Integration Docs

This page is for indexers, scanners, security tools and anyone else who needs to programmatically recognize, price, and evaluate tokens launched through ZeroHood on Robinhood Chain (chain ID 4663). Everything below is verifiable directly on-chain — no API key, no trust required.

1. Overview

ZeroHood is a fair-launch platform on Robinhood Chain. Anyone can deploy a new fixed-supply ERC-20 in one transaction that immediately becomes a real, tradeable Uniswap v4 pool — no presale, no team allocation, no graduation wait, tradeable and priceable the same block it launches.

Launches and trades are submitted directly by the user's own wallet (they pay their own gas; there is no relayer in the transaction path). The one exception is claiming creator fees, which is sponsored server-side via a relayer-signed EIP-712 authorization so a creator never needs gas to withdraw what they earned.

The token supply is a fixed 1,000,000,000 (18 decimals), and the entire supply is seeded into the pool single-sided (token-only, zero WETH) at launch — see the single-sided liquidity model below. This is what makes launches cost only gas while still giving buyers deep liquidity from block one.

2. Contract addresses

Chain: Robinhood Chain, ID 4663. Everything below is canonical and immutable.

InstantPoolFactory (every launch)
0x694b6c5299a0416e0997c62de5503a00a82a48f3
FeeCollectorVault (holds every LP position, forever)
0x12c30B79b03B7F5364c591F53a499906678b2d78
LaunchFeeEscrowV2 (creator fee escrow)
0x9495c276CDA5fE9C49e865b2Cc8e2253dD9Eb299
TokenLocker (time-lock vault, see Token Locker below)
0xdcc49ea21d595cbbb6475c2957b3d06e472e4d92
WETH (pool pair currency)
0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73
Uniswap v4 PoolManager
0x8366a39CC670B4001A1121B8F6A443A643e40951
Uniswap v4 PositionManager
0x58daec3116aae6d93017baaea7749052e8a04fa7
Permit2
0x000000000022D473030F116dDEE9F6B43aC78BA3

The vault and escrow are also readable straight off the factory (factory.vault() / factory.feeEscrow()), so they stay correct even if the factory is ever redeployed to a new address.

3. Detecting a ZeroHood launch

Watch one event on InstantPoolFactory to discover every launch with full metadata in a single log read — no follow-up eth_call per token:

event Launched(
  address indexed token,
  uint256 indexed tokenId,      // Uniswap v4 LP position NFT id (on the canonical PositionManager)
  address indexed creator,      // the wallet that launched it (msg.sender)
  bytes32 claimKey,             // creator fee-claim key (wallet- or social-derived, see Creator fee claims below)
  string  name,
  string  symbol,
  string  description,
  string  imageURI,             // https:// or ipfs:// — required at launch, never empty
  string  website,              // optional, "" if not set
  string  twitter,              // optional display URL, e.g. https://x.com/handle
  string  telegram,             // optional display URL, e.g. https://t.me/group
  string  xHandle,              // fee-claim handle (x/github/discord); field name kept as `xHandle` for ABI stability
  uint256 wethSeeded            // always 0 — launches are single-sided/seedless; retained for ABI stability
)

To confirm any token is a genuine ZeroHood launch: call InstantPoolFactory.tokenIndex(token)0 means not one of ours; any non-zero value is its 1-based index in launches. getLatest(n) returns the n most recent launches with full metadata for a backfill.

for scanners & feeds (GMGN etc.)

The profile image, website, X and Telegram are all in the event log itself — decode them straight from the Launched data, no IPFS-only, no external API, no follow-up call. Field → display mapping:

imageURI  → profile image  (https:// or ipfs://, always present)
website   → website link   (url, "" if unset)
twitter   → X / Twitter link (url, "" if unset)
telegram  → Telegram link  (url, "" if unset)
name / symbol / description → token identity

Watch this one event on the factory:

factory (emits Launched)
0x694b6c5299a0416e0997c62de5503a00a82a48f3

topic0 (verified against a live emitted event):

0xaab7db13ef23b7916e432d22cf716aebaff1644c405a4632fac716da46e9520e

4. Single-sided liquidity model

At launch the factory mints the full 1B supply and deposits all of it into the v4 pool as a single-sided, token-only liquidity position (0 WETH), spread across a wide price range that starts at a low market cap (~$2,700-equivalent). Buyers supply the WETH as they buy; sellers get WETH back. Functionally it is a bonding curve implemented as one concentrated Uniswap v4 range.

Why it's done this way:

  • Launch costs only gas — there is no liquidity for the creator to fund.
  • Deep from block one — the whole supply backs the curve, so a ~$90 buy is roughly ~3% price impact, not 50%.
  • No hard revert on size — the range is wide enough that a buy of any size fills; larger buys just move price more.

You can verify the single-sidedness directly: the v4 PoolManagerholds ~100% of a fresh launch's token supply and ~0 WETH until the first buy. The pool is a completely standard Uniswap v4 pool — fee 10000 (1%), tickSpacing 200, hooks = address(0) — so nothing ZeroHood-specific is needed to price or route it once discovered.

5. Anti-snipe max-wallet window

For 15 minutes after launch, no non-exempt wallet may hold more than 2% of total supply (20,000,000 tokens). After the window it lifts permanently. This is enforced inside the token itself — every transfer checks it — so it applies to swaps and direct transfers alike, and cannot be bypassed.

// on the launched token (LaunchToken):
maxWalletAmount()     // uint256 — the per-wallet cap (2% of supply), or type(uint256).max if disabled
restrictionEndsAt()   // uint64  — unix timestamp the window ends (0 if disabled)
restrictionActive()   // bool    — true while block.timestamp < restrictionEndsAt

// a transfer that would push a non-exempt wallet over the cap reverts:
error MaxWalletExceeded();

The window is timestamp-based, not block-number-based — deliberate, because Robinhood Chain is an Arbitrum Orbit L2 where block.numberreturns the L1 (Ethereum) block number, not this chain's own count. The cap and duration are set at deploy and are immutable— there is no owner function to change or extend them. The v4 PoolManager (and the factory itself) are exempt so the initial liquidity mint isn't blocked by its own cap.

6. Trading a launched token

Because each launch is an ordinary Uniswap v4 pool (token / WETH, fee 10000, tickSpacing 200, no hooks) on the canonical PoolManager, you price and trade it with the standard v4 tooling — quote via the v4 Quoter, swap via the Universal Router. No ZeroHood-specific contract is involved in a trade at all; only discovery (see Detecting a ZeroHood launch above) is ZeroHood-specific.

The pool pairs with WETH, but the ZeroHood UI lets people trade in the chain's native ETH directly — nobody has to hold or think about WETH. A buy prepends a Universal Router WRAP_ETH command (the attached msg.value is wrapped to WETH inside the router, then swapped for the token), and a sell appends UNWRAP_WETH (the WETH out of the swap is unwrapped and paid back to the trader as native ETH). Integrators are free to trade the WETH pair directly instead; both hit the exact same pool.

Trading fees accrue in the pool. Anyone can pull them into the claimable escrow at any time by calling FeeCollectorVault.collectFees(token)(permissionless) — it splits collected fees 50/50 between the protocol treasury and the creator's claim key, and never touches the underlying liquidity (see Permanent liquidity lock below).

7. Permanent liquidity lock

The LP position NFT for every launch is minted straight to FeeCollectorVault and stays there forever. The vault's ABI has no function anywhere capable of decreasing liquidity, burning, or transferring the position out — the only thing it can ever do with a position is collect the trading fees it earned. There is no owner override, no pause, no emergency exit.

Verify the lock yourself: on the v4 PositionManager, ownerOf(tokenId) for any launch always returns the FeeCollectorVault address in Contract addresses — an immutable contract with no withdrawal path. No rug is possible from launch second one.

for scanners — treat as locked liquidity

Every launch's LP position NFT is owned by a single immutable holder with no withdraw/decrease/ transfer path — functionally equivalent to a burn, but the position stays fee-collectible. A scanner can safely mark liquidity as locked/burntwhen a token's v4 position is owned by:

FeeCollectorVault (permanent LP holder)
0x12c30B79b03B7F5364c591F53a499906678b2d78

The vault has no owner, no upgrade path, and no function that can reduce or move a position — only collectFees(). So "liquidity locked" is provable purely from the position's owner being this address.

8. Creator fee claims (X / GitHub / Discord)

At launch the creator directs their 50% fee share to their own wallet or to a handle on X, GitHub, or Discord. The destination is baked into an on-chain claimKey:

// LaunchFeeEscrowV2:
walletClaimKey(address wallet)              // keccak256("wallet", wallet)
socialClaimKey(string platform, string handle)  // keccak256("social", platform, handle)
// platform is one of "x" | "github" | "discord"; handle is lowercased, no @

A social-delegated fee share is claimable the moment that person logs into ZeroHood with the matching account — even if the token was launched before they ever heard of it. Ownership is proven by OAuth at claim time; the escrow only pays out on a relayer-signed authorization tied to the verified identity. Fees are tracked per-(claimKey, currency), so a pool that has earned in both WETH and the token accrues both claimable independently.

9. Token Locker

TokenLocker (address in Contract addresses) is a standalone, trustless time-lock vault for any ERC-20 on Robinhood Chain — unrelated to launches. Anyone locks tokens until a future timestamp; only the lock's creator can withdraw, and only once that time passes.

lock(address token, uint256 amount, uint64 unlockTime) returns (uint256 lockId)
withdraw(uint256 lockId)          // reverts unless msg.sender == owner AND block.timestamp >= unlockTime
extend(uint256 lockId, uint64 newUnlockTime)  // can only push LATER, never shorten
getUserLocks(address) / getLock(uint256) / totalLocks()

event Locked(uint256 indexed lockId, address indexed owner, address indexed token, uint256 amount, uint64 unlockTime);
event Withdrawn(uint256 indexed lockId, address indexed owner, address indexed token, uint256 amount);
event Extended(uint256 indexed lockId, uint64 newUnlockTime);

Guarantees: no owner/admin/pause/rescue of any kind exists on the contract; a lock can never be shortened or released early by anyone (including its creator); withdraw is double-gated on owner + time; reentrancy-guarded with effects-before-interaction; and it records the actual amount received (fee-on-transfer safe). It uses block.timestamp, notblock.number, for the same L2 reason as Anti-snipe max-wallet window.

Detecting a lock for a specific token (for scanners):

  1. Filter Locked events on TokenLocker where the indexed token topic equals the token address — topic0 = 0x8304b8c1ad220f367b10eb7062c3c2e5d5568a59cad020b216ff3d168766af17.
  2. Sum amount across matches; subtract any whose lockId also has a matching Withdrawn event (topic0 = 0xe5df19de43c8c04fd192bc68e484b2593570925fbb6ad8c07ccafbc2aa5c37a1) — that's the token's current locked balance.
  3. Or skip event replay entirely: call getLock(lockId) directly — it returns {owner, token, amount, unlockTime, withdrawn} in one read.

Live example (a real lock, locked then withdrawn after maturity — good for testing both paths):
locked: 0xe0c2bad2…9f6 · withdrawn: 0x976154cf…4f0

10. Security properties

  • No rug: pool liquidity is locked in an immutable vault with zero withdrawal path (see Permanent liquidity lock).
  • No presale / no team allocation: 100% of supply goes into the pool at launch; the creator gets a fee share, never a supply share.
  • Permissionless launch, self-custody: the creator is bound to msg.sender on-chain; no relayer signs or holds anything for a launch or trade.
  • No caller-controlled fund pull: the WETH side of the mint is hardcoded to 0, so no launch parameter can make the factory pull WETH from anywhere — a bad parameter can at worst make a bad pool for the caller's own token.
  • Anti-snipe: 2%-of-supply per-wallet cap for 15 minutes, enforced in-token, timestamp-based (see Anti-snipe max-wallet window).
  • Standard token: LaunchToken is a plain fixed-supply ERC-20 with EIP-2612 permit and no transfer tax — the anti-snipe cap is the only non-standard transfer rule, and it expires.
  • Limited owner power: the factory owner can only redirect the protocol's own 50% fee cut (setTreasury) — it can never touch pool liquidity, creator fees, or user tokens.

11. Verifying a token yourself

End-to-end, no trust required:

  1. Call InstantPoolFactory.tokenIndex(token) — non-zero confirms it's a ZeroHood launch.
  2. Read the Launched event (see Detecting a ZeroHood launch) for its metadata and tokenId.
  3. On the v4 PositionManager, check ownerOf(tokenId) == FeeCollectorVault — proves liquidity is locked.
  4. Query the v4 pool (token/WETH, fee 10000, tickSpacing 200, hooks 0) on the PoolManager to price it.
  5. Optionally read token.restrictionActive() / maxWalletAmount() to see if the anti-snipe window is still open.

Explorer for spot-checking any address: https://robinhoodchain.blockscout.com

community & support

indexer/scanner integrating ZeroHood? reach out on X or Telegram.