DEV Community

Bryan MARTIN
Bryan MARTIN

Posted on

What I shipped in one Claude Code session: a real-time mempool rug-detector pipeline

I run RektRadar, a real-time scam-token detector for Ethereum. This is an honest build-log of one session with Claude Code (the Fable model) where I went from "our scam detection misses a few things" to four new detection signals shipped and a three-repo real-time alert pipeline live in production. Every PR linked below is public.

Not "the AI did everything magically". The interesting part is the division of labor: where an agent is genuinely strong, where I had to steer, and the one moment it was about to do something dumb and I stopped it.

The setup

RektRadar is ~7 repos: a mempool watcher, a contract analyzer (7 sub-analyzers), a graph crawler, a Telegram bot, an Astro marketing site, a Vue app, and the Ansible infra. Node/TypeScript throughout, real test suites (the contract analyzer alone has ~7,000 tests).

I started the session with a list of detection gaps a security discussion had surfaced, and worked down it.

1. The headline: catching a rug in the mempool, before it mines

A rug is usually a single transaction: removeLiquidity, setFee to a confiscatory tax, setBlacklist, pause, mint. Between broadcast and inclusion it sits in the public mempool for seconds. We already stream pending txs for sandwich detection, so the move was to watch those same txs for a rug action against a token we already flagged as high-risk.

The design Claude landed on, mirroring the existing DeployWatcher pattern in the repo:

export function classifyPrivilegedCall(
  tx: PrivilegedTxLike,
  byToken: Map<string, WatchEntry>,
): PrivilegedAlert | null {
  const selector = (tx.data ?? "0x").slice(0, 10).toLowerCase();

  // liquidity removal goes through the router, but the token is in the calldata
  if (LIQUIDITY_REMOVAL_SELECTORS[selector]) {
    const token = decodeRemovedLiquidityToken(tx.data);
    const entry = token ? byToken.get(token) : undefined;
    return entry ? { kind: "liquidity_removal_pending", ...entry } : null;
  }
  // owner functions (setFee/blacklist/pause/mint...) are called on the token itself
  const entry = byToken.get((tx.to ?? "").toLowerCase());
  ...
}
Enter fullscreen mode Exit fullscreen mode

A pure classifier + an injected watcher that refreshes the high-risk token set every few minutes. That split mattered: the classifier got 19 unit tests with zero mocks, while the I/O stayed in the watcher. This is the thing agents are quietly good at - given a clean existing pattern, they reproduce its shape rather than inventing a new one.

This is where it gets cross-service. The detection lives in the mempool watcher; the alert needs to reach a Telegram channel. So the session built a three-repo pipeline:

  • a Postgres privileged_alerts hand-off table (infra migration),
  • the mempool watcher writing detected alerts to it (idempotent on tx hash),
  • the Telegram bot polling unposted rows and posting an "imminent rug" message, stamping posted_at so each fires once.

Decoupled producer/consumer, each with its own tests. All three merged and deployed in the same session.

2. Where I had to keep it honest

The ABI verification. The lock-quality signal needed to read a liquidity lock's unlock date to flag "lock expires in 3 days". That means reading the UNCX locker contract on-chain. Claude wanted to write the read against the documented tokenLocks(lpToken, index) ABI. I made it verify the struct against the live contract first - we pulled a real locked token off the locker's global index and decoded an actual unlockDate before trusting the field order. On a security tool, a misread field that emits a false "this is safe" is worse than no signal. The agent will happily write plausible code; the human has to insist on grounding it.

The sybil false-positive. The sybil-holder signal clusters top holders by their funding source - dozens of fresh wallets funded by one address is fake demand. The trap: a cohort that all withdrew from the same exchange is normal. Without a CEX exclusion list this would false-positive on half of crypto. We pulled the 64-address exchange set from the graph-crawler service and excluded it. This is the kind of domain constraint that does not show up in the code, only in the consequences - exactly what you need a human in the loop for.

The "don't push" moment. At one point I asked Claude to open a PR, then immediately realized I wanted to review the branch more first. It had already opened it. It converted it to draft within seconds of my "wait", then closed it cleanly when I confirmed. Cheap recovery, but a reminder that "open a PR" is an outward action you want a beat of confirmation on.

3. What actually shipped

Four new signals, all live:

  • Mempool imminent-rug warning (the pipeline above)
  • Sybil-funded holders - funding-graph clustering with CEX exclusion
  • Lock quality - partial lock + verified-on-chain expiring lock
  • Phishing-bait - URL / claim-channel in the token's on-chain name

Plus the supporting work: the signal documentation catalogue went from 55 to 105 pages (every flag the analyzers raise now has a page explaining it), and a UI palette/spacing refresh on the app.

~18 PRs across 7 repos, all merged through the normal CI + review pipeline, all with tests. The mempool watcher suite is at 2,496 tests, the contract analyzer at ~7,089, the Telegram bot at 114.

The honest scorecard

What the agent was strong at:

  • Pattern matching the codebase. New code looked like the surrounding code - same logger shape, same port/adapter split, same test style.
  • Test discipline. Every behavior change came with tests, and it iterated on real failures (a couple of mocked-config tests broke when I added a new export; it found and fixed them).
  • Cross-service plumbing. Holding the shape of a producer/consumer pipeline across three repos without losing the thread.

What needed me:

  • Grounding claims in reality (verify the ABI live, don't trust the docs).
  • Domain constraints that only show as false positives (the CEX exclusion).
  • Outward actions (the PR I didn't want pushed yet).

The summary I'd give: it is a very fast, very literal pair-programmer that is excellent at the "how" once you are clear on the "what" - and a security tool is exactly the place where you still own the "what".

You can paste any Ethereum token address into the free detector at rektradar.io and watch these signals run live. If you want the product-side writeup of the signals themselves, that's on the blog.

Top comments (0)