A memecoin sniper bot is, mechanically, three things: a real-time signal, a filter that decides whether to act, and an execution path that submits a transaction before everyone else does. The hardest part is the signal — getting reliable sub-second notification of a fresh launch with the right metadata to filter on. That is exactly what the DEX Firehose is built for.
This guide builds a working sniper from scratch. By the end, you will have a Node.js service that:
- Subscribes to fresh Pump.fun launches via WebSocket
- Filters by deployer reputation tier and minimum trade size
- Logs every candidate and (optionally) wires up to a Jupiter swap
It assumes you have an Ultra subscription on madeonsol.com/pricing (€131/mo, ≈ $149 — pay by card, USDC, or SOL). The Firehose is Ultra-only because it broadcasts every parsed DEX trade across 14 programs — the bandwidth and gRPC infrastructure are real costs.
If you are building this as a side project and the subscription cost is a barrier, it's worth knowing the ecosystem has funding paths for tooling like this — our builder's guide to Solana grants and funding covers where infra-focused projects can get backed.
The signal: what counts as "fresh"?
A "fresh" launch is one where the bonding curve has been live for some short window (often 30 seconds to 5 minutes) and you have not missed the initial run-up. The DEX Firehose exposes this directly via the token_age_max_seconds filter, which uses a persisted first-seen lookup so the value is consistent across our deploy cycles — you do not get a false flood of "new" tokens after every restart.
A subscription that gets you fresh Pump.fun buys looks like this:
import WebSocket from "ws";
const API_KEY = process.env.MADEONSOL_KEY;
// Step 1: get a short-lived stream token
const tokenRes = await fetch("https://madeonsol.com/api/v1/stream/token", {
method: "POST",
headers: { "Authorization": `Bearer ${API_KEY}` },
});
const { token } = await tokenRes.json();
// Step 2: connect to the firehose
const ws = new WebSocket(`wss://madeonsol.com/ws/v1/dex-stream?token=${token}`);
ws.on("open", () => {
ws.send(JSON.stringify({
type: "subscribe",
sub_id: "fresh-pumpfun",
replay: 50, // get the last 50 matching trades on connect
filters: {
dex: "pumpfun",
token_age_max_seconds: 300, // first seen within last 5 minutes
action: "buy",
min_sol: 0.5, // ignore dust
},
}));
});
ws.on("message", (raw) => {
const msg = JSON.parse(raw);
if (msg.type === "connected") console.log("connected, capabilities:", msg.capabilities);
else if (msg.type === "subscribed") console.log("filter active:", msg.filters);
else if (msg.channel === "dex:trades") {
onTrade(msg.data, msg.replay === true);
}
});
function onTrade(t, isReplay) {
const tag = isReplay ? "[replay]" : "[live] ";
console.log(`${tag} ${t.dex} buy ${t.sol_amount} SOL → ${t.mint.slice(0, 8)}… by ${t.wallet.slice(0, 8)}…`);
}
Run that and you will start receiving candidate launches within seconds. The replay: 50 flag immediately backfills the last 50 matching trades from our in-memory ring buffer so your bot has live context the moment it boots.
Filtering for quality, not quantity
Catching every fresh launch is easy. Catching the ones that are actually worth sniping is the entire game. The Firehose lets you stack filters server-side so your bot only wakes up on signals worth acting on.
Three filter dimensions matter:
1. Deployer tier
Most Pump.fun tokens are launched by wallets with no track record (unranked). A small minority are launched by wallets we have classified as elite or good — meaning they have deployed multiple tokens and consistently bonded them above some MC threshold. Tier classification is updated daily by our Deployer Hunter pipeline.
Filter on it like this:
ws.send(JSON.stringify({
type: "subscribe",
sub_id: "elite-launches",
filters: {
dex: "pumpfun",
token_age_max_seconds: 300,
deployer_tier: ["elite", "good"],
action: "buy",
min_sol: 0.5,
},
}));
Across a 24-hour window this typically reduces the firehose by 95%+ while keeping the signals with the highest historical bond rates. If you want to query that classification directly rather than stream it, our Solana deployer API for tracking token creators covers the REST surface behind these tiers.
2. Trade-size cohort
A token that is getting only 0.05 SOL trades is noise. A token with multiple ≥1 SOL buys in its first minute is showing real interest — though be aware that coordinated multi-wallet buying can fake this, which we unpack in our breakdown of how token launches use bundle buys. Use min_sol aggressively (1.0 SOL+) for higher-quality signals, lower (0.3–0.5 SOL) if you want broader coverage.
3. Multiple subs for tiered alerts
Run a primary "act on it" subscription with strict filters and a secondary "watch it" subscription with looser filters — on the same connection:
// High-confidence: act
ws.send(JSON.stringify({
type: "subscribe",
sub_id: "act",
filters: { dex: "pumpfun", token_age_max_seconds: 120, deployer_tier: ["elite"], min_sol: 1.0, action: "buy" },
}));
// Lower-confidence: log + dashboard
ws.send(JSON.stringify({
type: "subscribe",
sub_id: "watch",
filters: { dex: "pumpfun", token_age_max_seconds: 600, deployer_tier: ["elite", "good", "moderate"], min_sol: 0.3 },
}));
Each matched trade carries the sub_id so you route them locally with no ambiguity.