Listen for meme / new-token launches on Robinhood Chain via logs
In this post, “meme / new-token launch” means an observable contract event stream on Robinhood Chain (ERC-20 Transfer / mint-like logs, pool-creation events)—not Robinhood App pushes, and not coin picks, sniping, or wash-trading playbooks.
Goal: use BlockReq public RPC to turn “launch signals” into filterable logs subscriptions plus HTTP backfill—useful for dashboards, alerts, and reconciliation. Hearing an event ≠ being able to profit; on-chain observability only guarantees you see public facts, not liquidity, credibility, or returns.
| Use | Endpoint |
|---|---|
| Public HTTPS | https://robinhood-mainnet-rpc.blockreq.com/v1/rpc/public |
| Public WSS | wss://robinhood-mainnet-rpc.blockreq.com/v1/rpc/public |
| Private HTTPS / WSS | Replace trailing public with your {API_KEY} (do not put it in demos) |
Chain identity: EVM, chainId = 0x1237 (decimal 4663). Docs: Public endpoints · eth_subscribe · Supported Networks.
Series split (read this before coding)
- Part 1 (open-watch heartbeat): How to watch Robinhood Chain opens with RPC subscribe (slug
robinhood-open-watch-rpc-subscribe)—focuses oneth_subscribe → newHeads, with logs only as optional narrow filters. If that post is not live yet, treat the series draft as canonical. - This post (Part 2): focuses on mint / pool-creationlogssignals—eth_subscribe logsvseth_getLogs, and how to filter by topic. - Solana launches (another chain): Watch new Solana mints in the browser—logsSubscribe+InitializeMint*; different protocol—don’t mix clients.
1. Where launch signals come from (on-chain logs / create events, not App pushes)
App pushes, social “launch alerts,” and third-party bot webhooks can all lag, miss events, or carry marketing. A verifiable launch window comes from logs in on-chain receipts:
| Signal type | Typical on-chain shape | Good for watching |
|---|---|---|
| Token mint / first supply | ERC-20 Transfer with from == 0x0…0 (common mint shape); or custom Mint / Launch events | “Did new supply appear?” |
| Pool creation | DEX factory PairCreated / PoolCreated, etc. (use the real ABI on that chain) | “Did a new pair / pool appear?” |
| Liquidity add | Mint (Uniswap V2 style), IncreaseLiquidity, etc. | “Did real liquidity go in?” |
| Any custom contract event | Project-specific TokenCreated, Launched… | Only when you have a real ABI and can compute the topic |
Recommended mindset:
- Observable = record
blockNumber,txHash,address,topics,data. - No coin picks = don’t name specific memes or imply “follow the buy.”
- Don’t manipulate = no sniping paths, no wash volume, no bypassing platform risk controls.
Split “an event appeared” from “should I trade”: this post only covers the first half, and is explicit—listening alone does not guarantee profit.
2. eth_subscribe logs vs polling eth_getLogs
WSS eth_subscribe → logs | HTTPS eth_getLogs | |
|---|---|---|
| Shape | Push: event is pushed once the node sees it on-chain | Pull: you specify fromBlock / toBlock |
| Latency | Usually closer to real time; good for launch-window dashboards | Depends on poll interval; good for replay and disconnect backfill |
| Filtering | address + topics (same semantics as getLogs) | Same; plus precise block-height windows |
| Missed messages | Disconnect gaps need self-backfill | You control the window; huge windows hit rate limits |
| Rate-limit pressure | Naked whole-chain logs get kicked easily; narrow filters required | High-frequency large-window polls burn public IP quota |
| Fit | Real-time launch signal streams | Reconciliation, backfill, historical scans |
How to choose (short):
- Need a real-time stream for a few launch minutes → WSS subscribe narrow
logs(requireaddressor the narrowesttopicsyou can). - After disconnect / browser sleep → HTTPS
eth_getLogsbackfill in block chunks. - Production correctness → subscribe for low latency; getLogs for gaps (same as Part 1 and common EVM indexer patterns).
Subscribe request shape:
{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_subscribe",
"params": [
"logs",
{
"address": "0xYourFactoryOrTokenAddress",
"topics": ["0xYOUR_EVENT_TOPIC0"]
}
]
}
Backfill request shape (POST to HTTPS public):
{
"jsonrpc": "2.0",
"id": 2,
"method": "eth_getLogs",
"params": [{
"fromBlock": "0xFROM",
"toBlock": "0xTO",
"address": "0xYourFactoryOrTokenAddress",
"topics": ["0xYOUR_EVENT_TOPIC0"]
}]
}
3. How to filter Transfer / mint / pool-creation topics
3.1 General method: topic0 = keccak256 of the event signature
EVM log topics[0] is the Keccak-256 (32-byte hex) of the event signature string:
topic0 = keccak256("EventName(type1,type2,...)")
Notes:
- Name and parameter types must match the contract ABI exactly (
indexeddoes not change the signature string itself, but it does affect later topic slots). - Tuples / structs must expand per ABI encoding rules—don’t guess.
- Factories, launchpads, and token implementations on Robinhood Chain may share names with Ethereum mainnet but different bytecode—always recompute from a verified ABI or local build artifact on that chain; don’t copy another chain’s address as your filter.
In the browser you can compute with ethers / viem (sketch):
// ethers v6
import { id } from "ethers";
const topic0 = id("Transfer(address,address,uint256)");
// => 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
3.2 Example topics (placeholders + one reusable standard)
| Use | Signature (sketch) | topic0 |
|---|---|---|
ERC-20 Transfer (standard) | Transfer(address,address,uint256) | 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef |
| Custom Mint | Mint(address,uint256), etc. | 0xYOUR_MINT_TOPIC ← replace with the value from the real ABI |
| Pool / pair creation | PairCreated(...) / PoolCreated(...) / project-custom | 0xYOUR_PAIR_OR_POOL_CREATED_TOPIC ← same |
| Launchpad create | Project-custom TokenCreated / Launched… | 0xYOUR_LAUNCH_TOPIC ← same |
Two common mint views (don’t conflate them):
- Standard ERC-20: many implementations record mint as
Transfer(from=0x0, to=recipient, value=amount). When filtering, besidestopics[0]=Transfer, check whethertopics[1](indexedfrom) is the zero address, or decode client-side and decide. - Custom
Mintevents: you must compute the topic from that token / factory ABI;0xYOUR_MINT_TOPICin the table is only a placeholder.
Pool creation is the same idea: Uniswap V2/V3-style events have well-known topics on other chains, but on Robinhood the real factory address, event name, and parameter list may differ. Correct flow: find the factory / launchpad you want to watch → get the ABI → compute topic0 → subscribe with that contract address + topic.
Filter example (Transfer + client-side mint-from-zero check for demo only):
const TRANSFER =
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";
const ZERO_TOPIC =
"0x0000000000000000000000000000000000000000000000000000000000000000";
// Subscribe: prefer an address; naked whole-chain Transfer is extremely noisy
const filter = {
address: "0xYourTokenOrFactory", // required for stability
topics: [TRANSFER],
};
// After a push: rough “looks like mint”
function looksLikeMint(log) {
return log.topics?.[0] === TRANSFER && log.topics?.[1] === ZERO_TOPIC;
}
Pool-creation placeholder (please replace):
{
"address": "0xYourDexFactoryOnRobinhood",
"topics": ["0xYOUR_PAIR_OR_POOL_CREATED_TOPIC"]
}
Again: the
0xYOUR_*samples are not copy-paste mainnet universal topics—replace them with values computed from your target contract ABI. This post does not provide or recommend any specific meme contract addresses.
3.3 Browser-runnable: narrowly filtered logs (defaults to public)
Save the following as robinhood-meme-mint-listen.html and open with npx serve for fewer WebSocket quirks on file://. Connects only to public—no key. By default it subscribes to Transfer on the contract address you enter; check “mint-from-zero only” to coarse-filter mint-shaped logs client-side.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Robinhood Chain · mint / logs listen</title>
<style>
body { font-family: ui-sans-serif, system-ui, sans-serif; margin: 1.5rem; max-width: 52rem; }
button { margin-right: 0.5rem; }
#status { margin: 0.75rem 0; color: #334155; }
pre { background: #0f172a; color: #e2e8f0; padding: 1rem; min-height: 16rem;
overflow: auto; font-size: 12px; border-radius: 8px; }
code { background: #f1f5f9; padding: 0.1rem 0.35rem; border-radius: 4px; }
label { display: block; margin: 0.35rem 0; }
</style>
</head>
<body>
<h1>Robinhood Chain · listen mint / Transfer logs</h1>
<p>Public WSS · <code>eth_subscribe → logs</code> · observe only; no coin picks, no orders.</p>
<p>WSS: <code>wss://robinhood-mainnet-rpc.blockreq.com/v1/rpc/public</code></p>
<p>
<input id="watchAddress" placeholder="0x… token or factory address (required)" size="48" />
</p>
<p>
<input id="topic0" placeholder="topic0 (default ERC-20 Transfer)" size="66"
value="0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" />
</p>
<label>
<input type="checkbox" id="mintOnly" checked />
Show only Transfer with from=0x0 (coarse mint filter; change topic0 for custom Mint)
</label>
<button id="start" type="button">Start</button>
<button id="stop" type="button" disabled>Stop</button>
<button id="clear" type="button">Clear</button>
<div id="status">Idle · listening = observable events, not profit</div>
<pre id="out"></pre>
<script>
const WSS = "wss://robinhood-mainnet-rpc.blockreq.com/v1/rpc/public";
const ZERO =
"0x0000000000000000000000000000000000000000000000000000000000000000";
const out = document.getElementById("out");
const status = document.getElementById("status");
let ws = null;
let nextId = 1;
let backoffMs = 1000;
let wantRun = false;
const seen = new Set();
function log(line) {
const t = new Date().toISOString().slice(11, 19);
out.textContent = `[${t}] ${line}\n` + out.textContent;
}
function setStatus(s) { status.textContent = s; }
function send(method, params) {
const id = nextId++;
ws.send(JSON.stringify({ jsonrpc: "2.0", id, method, params }));
return id;
}
function subscribeLogs() {
const addr = document.getElementById("watchAddress").value.trim();
const topic = document.getElementById("topic0").value.trim();
if (!/^0x[a-fA-F0-9]{40}$/.test(addr)) {
log("enter a valid contract address (avoid naked whole-chain subs)");
return false;
}
if (!/^0x[a-fA-F0-9]{64}$/.test(topic)) {
log("topic0 must be 32-byte hex");
return false;
}
send("eth_subscribe", ["logs", { address: addr, topics: [topic] }]);
log("sent eth_subscribe logs @ " + addr + " topic0=" + topic.slice(0, 10) + "…");
return true;
}
function connect() {
if (!wantRun) return;
setStatus("connecting…");
ws = new WebSocket(WSS);
ws.onopen = () => {
backoffMs = 1000;
if (!subscribeLogs()) {
wantRun = false;
document.getElementById("start").disabled = false;
document.getElementById("stop").disabled = true;
setStatus("not subscribed: invalid address/topic");
try { ws.close(); } catch {}
return;
}
setStatus("connected · subscribed (observable ≠ profit)");
};
ws.onmessage = (ev) => {
let msg;
try { msg = JSON.parse(ev.data); } catch { return; }
if (msg.id && msg.result && typeof msg.result === "string") {
log("subscription id=" + msg.result);
return;
}
if (msg.method !== "eth_subscription") return;
const r = msg.params && msg.params.result;
if (!r || !r.transactionHash) return;
if (document.getElementById("mintOnly").checked) {
if (!(r.topics && r.topics[1] === ZERO)) return;
}
const key = r.transactionHash + ":" + r.logIndex;
if (seen.has(key)) return;
seen.add(key);
const blk = r.blockNumber ? parseInt(r.blockNumber, 16) : "?";
log(
`log #${blk} tx=${r.transactionHash.slice(0, 12)}…` +
` addr=${r.address} topics=${(r.topics || []).length}`
);
};
ws.onclose = () => {
setStatus("closed");
if (!wantRun) return;
setStatus(`reconnect in ${backoffMs}ms`);
setTimeout(connect, backoffMs);
backoffMs = Math.min(backoffMs * 2, 30000);
};
ws.onerror = () => { try { ws.close(); } catch {} };
}
document.getElementById("start").onclick = () => {
wantRun = true;
document.getElementById("start").disabled = true;
document.getElementById("stop").disabled = false;
connect();
};
document.getElementById("stop").onclick = () => {
wantRun = false;
document.getElementById("start").disabled = false;
document.getElementById("stop").disabled = true;
if (ws) try { ws.close(); } catch {}
setStatus("stopped");
};
document.getElementById("clear").onclick = () => {
out.textContent = "";
seen.clear();
};
</script>
</body>
</html>
StackBlitz slot: TBD—the example is planned under
blockreq/blog-demosatexamples/robinhood-meme-mint-listen; for now, run the local HTML above.
For custom mint / pool creation: change only the page topic0 (computed from the real ABI) and address (factory or token). For keyed: change only the WSS constant; keep the key local and do not commit it to a public repo.
On disconnect backfill, reuse the same address + topics, call eth_getLogs against HTTPS public in block chunks, and remember the last processed blockNumber (same pattern as Part 1).
4. BlockReq public endpoint usage and rate limits
| Item | Public endpoint | Private (keyed) |
|---|---|---|
| URL | …/v1/rpc/public | …/v1/rpc/{API_KEY} |
| Rate limit | Best-effort, per IP | Per plan RU / req/s |
| Fit | Learning, short launch-window demos | Long-running dashboards, alerts, production subs |
| Key | None | Create in Dashboard; never put it in public HTML / repos |
Practical tips:
- Always narrow filters — prefer
address; whole-chainTransferwill blow public quota at meme peaks. - Split subscribe vs backfill — WSS for real time; gaps via HTTPS
eth_getLogs; don’t pull thousands of blocks at once. - 429 / instant disconnect — narrow width, lengthen backfill intervals, switch to keyed at peaks; don’t open a dozen wide subs from one IP.
- Dedupe —
txHash + logIndexSet to avoid reconnect replay spam. - Exponential backoff reconnect — inevitable after browser sleep; re-issue eth_subscribe after reconnect.
More: Public endpoints · Plans & pricing.
5. How this splits from Part 1 and the Solana mint post
| Post | Chain / protocol | Primary signal | You use it for |
|---|---|---|---|
| Part 1 · open watch | Robinhood Chain · EVM eth_subscribe | newHeads (optional narrow logs) | Block heartbeat, open-rhythm dashboards |
| This post · mint / launch logs | Same | logs topic filters (Transfer / mint / pool create) | Observable mint and launch-class events |
| Solana new mint | Solana · logsSubscribe | Token Program InitializeMint* | Browser launch listening on another chain |
How to combine (observation stack, not trading stack):
- Part 1’s
newHeadsas the “chain is alive” heartbeat. - This post’s narrow
logsas the “any mint / pool-create event?” signal bus. - When you need a Solana-style launch window, switch protocols and read the Solana post—don’t stuff
logsSubscribeparams into an EVM client.
Compliance boundary (same as the series): no sniping, wash-trading, or platform-rule-bypass playbooks; no coin picks; no API keys in public demos. Listening for meme / new-token launches = subscribing to public observable events; no profit guarantee.
---
Summary
- Launch signals come from Robinhood Chain receipt
logs, not App pushes; hearing an event does not mean you can make money. - Real time → WSS
eth_subscribe logs(narrowaddress+topics); gaps → HTTPSeth_getLogsin chunks. - topic0 =
keccak256(event signature); Transfer in this post is the standard example—Mint / pool creation must use values from real contract ABIs on this chain. - Public is best-effort per-IP rate limited; long-running watch → keyed, keys stay out of demos.
- Part 1 owns
newHeadsheartbeat; this post owns mint / pool-create logs; Solana launches → solana-new-mint-browser-logssubscribe.
Typical next steps: fix factory / watch-address lists → topic whitelist in config → alert Webhook → persist backfill checkpoints. Still an observation stack, not a trading stack.