Skip to content

swiftnodes/mempool-watcher

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Mempool Watcher

Real-time EVM mempool monitoring with pluggable filters. Streams pending transactions over WebSocket, fetches the full transaction body for each, runs your filter, and prints structured events with decoded method signatures.

Useful for: building MEV detectors, watching specific addresses, tracking large value transfers, monitoring DEX swap activity, debugging pending-tx behavior, or just learning how mempool data actually flows.

git clone https://github.com/swiftnodes/mempool-watcher
cd mempool-watcher
cp .env.example .env             # add your SwiftNodes API key
npm install
CHAIN=base npm start

Sample output:

2026-05-13T14:31:22.118Z
  from:   0xab12...90cd
  to:     0x4752ba5DBc23F44D87826276BF6Fd6b1C372aD24
  value:  0.0 ETH
  method: 0x7ff36ab5 (swapExactETHForTokens(uint256,address[],address,uint256))
  gas:    0.42 gwei (maxFee)
  tx:     https://basescan.org/tx/0xdeadbeef...

Supported chains

Six chains out of the box, easy to extend:

  • Ethereum (eth)
  • Base (base)
  • BNB Smart Chain (bsc)
  • Arbitrum One (arbitrum)
  • Optimism (optimism)
  • Polygon (polygon)

Powered by SwiftNodes — full mempool access available on every plan (most providers gate this on premium tiers).

Architecture

src/
  chains.js     ← Per-chain config: WebSocket URL, native symbol, explorer
  filters.js    ← Composable filter primitives (allOf, anyOf, methodSelector, etc.)
  index.js     ← Subscribes, fetches tx bodies, applies filter, prints

How it works

  1. Subscribe to eth_subscribe("newPendingTransactions") via WebSocket.
  2. For each pending tx hash, fetch the full transaction body with eth_getTransactionByHash.
  3. Apply your filter (composable function) — drop if it doesn't match.
  4. Decode the method selector against a known-signature table.
  5. Print a structured event.

Average tx-to-print latency: 50-300ms depending on network. Mempool firehose volume varies wildly by chain — Ethereum ~50-200 pending/sec, Base ~100-500 pending/sec, BSC ~1000+ pending/sec during peak.

Filtering

The default filter captures: ETH transfers ≥ 1 native unit, token approvals, and major DEX swaps. Edit FILTER in src/index.js:

import { allOf, anyOf, not, toAddress, methodSelector, minValueWei, isEthTransfer } from "./filters.js";

// Watch a specific whale wallet
const FILTER = anyOf(
  fromAddress("0x...whale..."),
  toAddress("0x...whale..."),
);

// Watch all transactions to a specific contract
const FILTER = toAddress("0x...vault...");

// Watch large value transfers (>= 100 ETH)
const FILTER = allOf(isEthTransfer(), minValueWei(100n * 10n ** 18n));

// Watch Uniswap Universal Router calls only
const FILTER = methodSelector("0x3593564c");

// Compose: watch a whale's swap activity specifically
const FILTER = allOf(
  fromAddress("0x...whale..."),
  anyOf(
    methodSelector("0x7ff36ab5"),  // swapExactETHForTokens
    methodSelector("0x38ed1739"),  // swapExactTokensForTokens
  ),
);

Filter primitives in src/filters.js:

Primitive What it does
toAddress(addr) Match txs sent TO this address
fromAddress(addr) Match txs sent FROM this address
methodSelector(hex) Match by 4-byte function selector
minValueWei(wei) Match txs with value ≥ N
isEthTransfer() Match value transfers (no calldata)
isContractCall() Match contract interactions
allOf(...) AND combinator
anyOf(...) OR combinator
not(filter) NOT combinator

Common use cases

Detect large transfers in real time

const FILTER = allOf(isEthTransfer(), minValueWei(50n * 10n ** 18n));

Track a whale wallet

const FILTER = anyOf(fromAddress(WHALE), toAddress(WHALE));

Watch a specific DEX router for pending swaps

const FILTER = toAddress("0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"); // Uniswap V3 router

Detect new contract deployments

const FILTER = (tx) => tx.to === null;

Replace this with a webhook poster

Swap console.log(...) in onTransactions for an fetch() to your Discord/Slack/Telegram webhook URL. Two-line change.

Why SwiftNodes for this

Most RPC providers either don't expose newPendingTransactions at all, or gate it on premium tiers ($1500+/mo with some). SwiftNodes:

  • Full mempool WebSocket subscriptions on every plan, including free tier
  • 6 chains here, 75+ total with the same API
  • No-KYC signup so you can experiment without paperwork

Run this in production for serious MEV use cases? You'll want a paid tier for higher rate limits and dedicated WebSocket connection slots, but the free tier is enough to experiment and validate.

Limitations

  • You're not the only one watching. Public mempool is competitive. By the time your bot acts on a pending tx, a thousand others have too. Latency edge is everything for actual MEV.
  • Some chains have private mempools. BSC and Polygon have validator-only "MEV pools" you can't see from public RPC. You'll miss those.
  • Subscription depth varies. Different upstream nodes have different mempool views; what you see depends on which node your subscription routes to.
  • Bandwidth is real. Full firehose with no filter on Ethereum mainnet is ~5 MB/s sustained. Filter aggressively.

License

MIT — fork, modify, ship.

Contributing

PRs welcome for:

  • More method signatures in KNOWN_METHODS
  • Additional chains
  • Filter primitives for common patterns (token transfers by ERC20 contract, etc.)
  • Notification integrations

About

Real-time EVM mempool watcher with pluggable filters. Streams pending transactions over WebSocket, decodes method signatures, prints structured events. 6 chains.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors