BlockReq
Back to all articles

Rpc Tutorials

Listen for meme / new-token launches on Robinhood Chain via logs

Subscribe to mint / pool-creation logs on Robinhood Chain with eth_subscribe and eth_getLogs backfill. Observable signals only—hearing an event is not profit.

BlockReq EngineeringSeptember 5, 202610 min read

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.

UseEndpoint
Public HTTPShttps://robinhood-mainnet-rpc.blockreq.com/v1/rpc/public
Public WSSwss://robinhood-mainnet-rpc.blockreq.com/v1/rpc/public
Private HTTPS / WSSReplace 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 on eth_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-creation logs signalseth_subscribe logs vs eth_getLogs, and how to filter by topic. - Solana launches (another chain): Watch new Solana mints in the browserlogsSubscribe + 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 typeTypical on-chain shapeGood for watching
Token mint / first supplyERC-20 Transfer with from == 0x0…0 (common mint shape); or custom Mint / Launch events“Did new supply appear?”
Pool creationDEX factory PairCreated / PoolCreated, etc. (use the real ABI on that chain)“Did a new pair / pool appear?”
Liquidity addMint (Uniswap V2 style), IncreaseLiquidity, etc.“Did real liquidity go in?”
Any custom contract eventProject-specific TokenCreated, LaunchedOnly 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_subscribelogsHTTPS eth_getLogs
ShapePush: event is pushed once the node sees it on-chainPull: you specify fromBlock / toBlock
LatencyUsually closer to real time; good for launch-window dashboardsDepends on poll interval; good for replay and disconnect backfill
Filteringaddress + topics (same semantics as getLogs)Same; plus precise block-height windows
Missed messagesDisconnect gaps need self-backfillYou control the window; huge windows hit rate limits
Rate-limit pressureNaked whole-chain logs get kicked easily; narrow filters requiredHigh-frequency large-window polls burn public IP quota
FitReal-time launch signal streamsReconciliation, backfill, historical scans

How to choose (short):

  • Need a real-time stream for a few launch minutes → WSS subscribe narrow logs (require address or the narrowest topics you can).
  • After disconnect / browser sleep → HTTPS eth_getLogs backfill 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:

  1. Name and parameter types must match the contract ABI exactly (indexed does not change the signature string itself, but it does affect later topic slots).
  2. Tuples / structs must expand per ABI encoding rules—don’t guess.
  3. 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)

UseSignature (sketch)topic0
ERC-20 Transfer (standard)Transfer(address,address,uint256)0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
Custom MintMint(address,uint256), etc.0xYOUR_MINT_TOPICreplace with the value from the real ABI
Pool / pair creationPairCreated(...) / PoolCreated(...) / project-custom0xYOUR_PAIR_OR_POOL_CREATED_TOPICsame
Launchpad createProject-custom TokenCreated / Launched0xYOUR_LAUNCH_TOPICsame

Two common mint views (don’t conflate them):

  1. Standard ERC-20: many implementations record mint as Transfer(from=0x0, to=recipient, value=amount). When filtering, besides topics[0]=Transfer, check whether topics[1] (indexed from) is the zero address, or decode client-side and decide.
  2. Custom Mint events: you must compute the topic from that token / factory ABI; 0xYOUR_MINT_TOPIC in 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-demos at examples/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

ItemPublic endpointPrivate (keyed)
URL…/v1/rpc/public…/v1/rpc/{API_KEY}
Rate limitBest-effort, per IPPer plan RU / req/s
FitLearning, short launch-window demosLong-running dashboards, alerts, production subs
KeyNoneCreate in Dashboard; never put it in public HTML / repos

Practical tips:

  1. Always narrow filters — prefer address; whole-chain Transfer will blow public quota at meme peaks.
  2. Split subscribe vs backfill — WSS for real time; gaps via HTTPS eth_getLogs; don’t pull thousands of blocks at once.
  3. 429 / instant disconnect — narrow width, lengthen backfill intervals, switch to keyed at peaks; don’t open a dozen wide subs from one IP.
  4. DedupetxHash + logIndex Set to avoid reconnect replay spam.
  5. 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

PostChain / protocolPrimary signalYou use it for
Part 1 · open watchRobinhood Chain · EVM eth_subscribenewHeads (optional narrow logs)Block heartbeat, open-rhythm dashboards
This post · mint / launch logsSamelogs topic filters (Transfer / mint / pool create)Observable mint and launch-class events
Solana new mintSolana · logsSubscribeToken Program InitializeMint*Browser launch listening on another chain

How to combine (observation stack, not trading stack):

  1. Part 1’s newHeads as the “chain is alive” heartbeat.
  2. This post’s narrow logs as the “any mint / pool-create event?” signal bus.
  3. When you need a Solana-style launch window, switch protocols and read the Solana post—don’t stuff logsSubscribe params 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

  1. Launch signals come from Robinhood Chain receipt logs, not App pushes; hearing an event does not mean you can make money.
  2. Real time → WSS eth_subscribe logs (narrow address + topics); gaps → HTTPS eth_getLogs in chunks.
  3. 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.
  4. Public is best-effort per-IP rate limited; long-running watch → keyed, keys stay out of demos.
  5. Part 1 owns newHeads heartbeat; 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.