Memecoin alerts for
Robinhood Chain

New launches, bonding-curve trades, graduations and whale swaps on chain 4663, delivered to Telegram and Discord. Rules are schema-validated data a subscriber edits from chat. USD values come from live on-chain liquidity, never a hardcoded price. And the service survives a restart mid-stream without double-sending or silently skipping a block.

$ npm install hood-alerts hoodchain hoodkit viem See the taxonomy Read the docs

Chain to inbox

Four stages, each independently testable. Splitting ingestion from delivery is what lets the free tier have a real delivery delay, lets a Telegram outage stall delivery without stalling ingestion, and keeps a slow platform from pushing the block cursor behind the chain.

Two launchpads, two lifecycles

This is the detail an alert product has to get right. NOXA and The Odyssey are not the same machine, and pretending they are produces alerts that are false rather than merely noisy.

NOXA

fun.noxa.fi/robinhood 路 instant launcher
  • One transaction deploys the ERC-20, creates a Uniswap v3 pool, seeds single-sided liquidity and locks the LP NFT.
  • No bonding curve exists, so there is nothing to fill.
  • Trades as ordinary Uniswap v3 swaps from block one.
  • A NOXA graduation is not a thing. Any product that offers one is describing an event that never fires.
launch curve_trade graduation whale_trade

The Odyssey

theodyssey.fun 路 bonding curve, virtual reserves
  • A launch opens a curve. No pool exists yet, so the launch has no dollar value attached.
  • Every buy and sell on the curve emits Traded, priced through its native-ETH leg.
  • When the curve fills, PoolCompleted and PoolMigrated move liquidity to a locked Uniswap v3 pool.
  • After graduating, its tokens produce whale trades like any other pool.
launch curve_trade graduation whale_trade
The asymmetry is enforced, not documented. A rule asking for NOXA graduations is rejected by the schema at validation time, with an explanation, instead of being accepted and quietly never firing:
safeParseRule({ id: 'nope', kinds: ['graduation'], launchpads: ['noxa'] })
// success: false
// "this combination can never fire: NOXA is an instant launcher with no
//  bonding curve, so it emits no curve_trade and no graduation"

The event taxonomy

Every event carries a stable id derived from its transaction hash and log index, which is what makes replaying a block range after a crash safe.

KindDecoded fromLaunchpadsusdValue is
launch NOXA TokenLaunched, Odyssey TokenCreated both the deployer's initial buy (NOXA), or null on Odyssey, where the curve holds the liquidity
curve_trade Odyssey Traded Odyssey only the native-ETH leg, priced through live WETH/USDG liquidity
graduation Odyssey PoolMigrated Odyssey only the quote side used to seed the migrated pool
whale_trade Uniswap v3 Swap on a tracked memecoin pool both the swap's quote leg

Every source, decoded against mainnet

npm run verify:chain runs the whole read path against the public RPC with no credentials, no database and no writes. Replaying the launchpads' first 1.44 million blocks:

chain 4663, head block 15010850
ETH/USD from live Uniswap v3 liquidity: $1905.26

scanning blocks 61688 to 1500000 (1438313 blocks)

NOXA launches        2621 events
  launch       ? 0x6399E2Bd8af62C0ac13f55613C3469b67332a6Fd $266.74 block 61869
  launch       HUSK 0x57EB9C9153cfE0277F91Ff8B8604C2D3006a9196 $9.53 block 61987
Odyssey launches        4 events
  launch       ROBIN 0xfB4729659eeF22Bfc1c2B680F6F873f8147aaaab unpriced block 983265
Odyssey curve trades  110 events
  curve_trade  ROBIN 0xfB4729659eeF22Bfc1c2B680F6F873f8147aaaab $18.67 block 983265
Odyssey graduations     1 events
  graduation   ROBIN 0xfB4729659eeF22Bfc1c2B680F6F873f8147aaaab $7618.47 block 1048638
Whale trades         4045 events
  whale_trade  CHEEMS 0xdaA213A0Bd8B048D6022e2c46df877E8A204072b $190.46 block 1439024

pools discovered and registered for whale watching: 2622

Follow ROBIN down those four rows and the taxonomy proves itself: a curve opens (unpriced, because a curve holds no pool), trades on the curve, then fills and migrates with $7,618.47 of liquidity seeded. NOXA tokens never appear in the middle two rows, because they cannot. The first NOXA token has no symbol() and renders as ? rather than dropping the alert.

No hardcoded prices. USDG legs are dollars by definition (the chain's fully reserved stablecoin, 6 decimals). ETH legs are priced by asking the chain's own Uniswap v3 liquidity what 1 WETH sells into USDG for. Anything else reports null, and a minUsd rule does not match it. Unknown is never quietly treated as zero.

Surviving a restart mid-stream

An alert bot that double-sends is spam, and one that skips a range misses the launch its subscribers paid for. Three guarantees, each held by a specific mechanism and each covered by a test that simulates the failure.

Never double-send

Every delivery has a deterministic key, eventId|subscriptionId|ruleId, and the event id comes from the transaction hash and log index. Re-processing a range regenerates identical keys, so the second pass inserts nothing.

Never silently skip

The block cursor advances only after every event in a chunk is enqueued and committed. A crash mid-chunk, or a failed RPC call, leaves it pointing at the start of that range, so the range is re-read.

Never lose a queued alert

Queued rows live in an outbox until delivered or dead-lettered. On startup, rows abandoned in sending by a crash return to pending and are retried.

The honest caveat. If the process dies after a platform accepted a message but before the row was marked sent, that alert goes out twice. Neither the Telegram nor the Discord send API takes a client-supplied idempotency key, so the window cannot be closed from here. Everything outside it is exactly once.

Delivery that respects each platform's actual contract

TelegramDiscord
Rate limit signal parameters.retry_after, whole seconds, on a 429 Per-route bucket headers on every response, plus retry_after as a float
Correct behaviour Wait exactly that long, capped so one throttled chat cannot stall the loop Do not send once a bucket is exhausted; apply a global 429 to every route
Escaping 18 reserved characters in MarkdownV2 text, 2 in a link URL, 2 in a code span, 3 in HTML Markdown rendered inside embed titles, descriptions and field values
Permanent failures Blocked bot, deleted chat: dead-lettered, never retried Unknown webhook, missing permission: dead-lettered
Command transport Long polling: no public URL, TLS or firewall rule needed Slash commands over an Ed25519-verified interactions endpoint
Memecoin names are adversarial input. A token called WHO_LET_THE italicises half a MarkdownV2 message and a token called <b>RUG injects markup under HTML parse mode; either way Telegram answers 400 can't parse entities and the alert is lost. Each context has its own escaper and its own tests, and truncation is surrogate-pair aware so a long emoji-bearing name is cut cleanly.

Tiers are enforced, not advertised

Every limit maps to a real cost, and the check lives in exactly one place. The bot asks it before accepting a rule; the dispatcher asks it before queuing a delivery. Nothing else reads the policy table, so the two cannot disagree about who is premium.

LimitFreePremium
Subscriptions110
Rules per subscription350
Filters per rule324
Watchlist size5500
Alerts per hour302,000
Delivery delay60snone
Liquidity and reputation filtersnoyes
Event kindslaunch, graduation, whale_tradeall four, including the curve firehose
Entitlements, honestly. Two providers ship and both work. The default grants premium from configuration, which is what a self-hoster wants. The other reads USDG Transfer logs from a signature-linked wallet to the operator's receiving address and accrues subscription time from those real payments: no facilitator, no card processor, no third party. hood-alerts deliberately does not wire an x402 rail, because x402 prices a single HTTP request and a subscription is not a request.

What it does not do

Watch every pool on the chain

A topic-only Uniswap v3 Swap query overflows the public RPC's 10,000-log result cap in under 2,000 blocks. Whale trades cover a tracked pool set built from launchpad activity, with subscriber watchlists pinned on top of the cap.

Run on testnet

Neither launchpad is deployed on chain 46630. Building sources against it throws rather than reporting an empty chain as "no launches".

Call a rug a rug

The drained-pool figure is a defined heuristic: a prior launch whose quote reserve is now below a threshold. A token that never traded looks the same. It is evidence, not a verdict.

Measure tradeable depth

Liquidity filters read total pool reserves. For concentrated positions the reserve inside the active tick can be far smaller.