Of the 8,304 pools that opened on Uniswap (Ethereum) in the last two weeks, 1,531 are already a confirmed rug pull or dump, and 79% stopped trading within a day. Half of all launches were dead inside 30 minutes. If you snipe new pairs or copy wallets, the question is not "will this one moon" but "is this one of the 18% that is built to take my ETH".
I build DexMarketCap. We index every swap, liquidity event and balance on Uniswap V2, V3 and V4 since 2020, and we judge every pool and token with the same rules that run on the site: rugged, dumped, honeypot, dead. Those verdicts are on our RapidAPI listing together with holders, wallet PnL, trades, candles, trending and new pairs. This post is a tutorial on using them from a trading or sniper bot, with working code, and at the end the data from the last 14 days of launches.
What the verdicts are
Every token and pool carries a flags object (ULTRA and MEGA plans):
"flags": { "dead": false, "honeypot": false, "rugged": true, "dumped": false }
- rugged: the pool is empty and the liquidity providers took it. More than 80% of everything ever added was removed in one go and nobody refilled it. Classic rug pull.
- dumped: the pool is empty but the liquidity was never removed (often it is burned or locked, which looks safe). The crew held the supply and sold it into the pool until the price was down more than 80% from its high. Pump and dump.
- honeypot: the contract does not let you sell. Taken from security audits, not guessed.
- dead: no trading activity left.
A verdict is a fact about what already happened, not a prediction. That is exactly what makes it useful in three places:
- Filter. A token that was rugged on one pool and relaunched on another, or a "revived" scam, shows up with its history. Skip it.
- Vet the people. A wallet's PnL rows carry the flags of every token it traded. A wallet whose last 300 trades were 250 rug pulls, all profitable, is not a trader: it is the insider of a rug factory. You do not want to copy it, and you do not want to be in a pool where it is the top buyer.
- Measure. How often launches rug, how fast, on which Uniswap version. Set your bot's hold time and size from numbers instead of vibes.
Setup
Node 18+ (built-in fetch). Get a key on RapidAPI; the BASIC plan is free, flags need ULTRA or MEGA.
const HOST = "dex-analytics.p.rapidapi.com";
const headers = { "X-RapidAPI-Key": process.env.RAPIDAPI_KEY, "X-RapidAPI-Host": HOST };
async function api(path) {
const r = await fetch(`https://${HOST}${path}`, { headers });
const body = await r.json();
if (!r.ok) throw new Error(`${path}: ${body.error?.code} ${body.error?.message}`);
return body; // { data, pagination?, meta: { asOf, plan, limited } }
}
1. Vet a token before you buy
Three calls: the token overview (verdicts, price, liquidity), holder stats (who owns the supply), and the token's pools (is there one real pool or five thin ones).
async function vetToken(address) {
const [{ data: t }, { data: h }, { data: pools }] = await Promise.all([
api(`/tokens/${address}`),
api(`/tokens/${address}/holder-stats`),
api(`/tokens/${address}/pools`),
]);
const reasons = [];
if (t.flags?.honeypot) reasons.push("honeypot: cannot sell");
if (t.flags?.rugged) reasons.push("rugged: liquidity was pulled");
if (t.flags?.dumped) reasons.push("dumped: crew sold the supply into the pool");
if (t.flags?.dead) reasons.push("dead: no activity");
if (t.liquidityUsd < 10_000) reasons.push(`thin liquidity: $${t.liquidityUsd}`);
if (h.top10Pct > 50) reasons.push(`top 10 holders own ${h.top10Pct}% of the supply`);
if (h.holders < 50) reasons.push(`only ${h.holders} holders`);
const live = pools.filter(p => p.liquidityUsd >= 1_000);
if (live.length > 2) reasons.push(`${live.length} funded pools on one token (serial pools)`);
return { symbol: t.symbol, priceUsd: t.priceUsd, liquidityUsd: t.liquidityUsd, holders: h.holders,
top10Pct: h.top10Pct, flags: t.flags, ok: reasons.length === 0, reasons };
}
console.log(await vetToken("0x6982508145454ce325ddbe47a25d4ec3d2311933")); // PEPE
Output for a healthy token:
{ symbol: 'PEPE', priceUsd: 0.00000477, liquidityUsd: 33932591, holders: 596705,
top10Pct: 34.5, flags: { dead: false, honeypot: false, rugged: false, dumped: false },
ok: true, reasons: [] }
The thresholds are a starting point. Holder concentration is the one I would not loosen: in the rug farm we documented last week, every token had about 39 holders and one insider wallet buying first, and the LP tokens were held unlocked by the same contract 945 times in a row.
2. Gate your sniper on new pairs
The new-pairs feed is where the 18% live. Over WebSocket (PRO and up) each launch arrives as a row with 5-minute stats; on ULTRA and MEGA it also carries flags, so a relaunch of a rugged token is marked at second zero.
import WebSocket from "ws"; // npm i ws
const MIN_LIQUIDITY = 5_000;
const MIN_BUYERS = 5;
function passesGate(p) {
const f = p.flags ?? {};
if (f.honeypot || f.rugged || f.dumped) return `flagged ${JSON.stringify(f)}`;
if (p.liquidityUsd < MIN_LIQUIDITY) return `liquidity $${p.liquidityUsd}`;
if (p.stats.buyers < MIN_BUYERS) return `${p.stats.buyers} buyers`;
if (p.stats.sells > p.stats.buys) return "more sells than buys in 5m";
if (p.marketCapUsd > 50 * p.liquidityUsd) return "mcap 50x the liquidity";
return null;
}
const { data: t } = await fetch(`https://${HOST}/stream/ticket`, { method: "POST", headers }).then(r => r.json());
const ws = new WebSocket(`${t.url}?ticket=${t.ticket}`);
ws.on("open", () => ws.send(JSON.stringify({ op: "subscribe", channel: "new-pairs" })));
ws.on("message", async (raw) => {
const msg = JSON.parse(raw);
if (msg.type !== "pair") return;
const p = msg.data;
const why = passesGate(p);
if (why) return console.log(`skip ${p.token.symbol}: ${why}`);
const vet = await vetToken(p.token.address); // holders + pools, one more look
if (!vet.ok) return console.log(`skip ${p.token.symbol}: ${vet.reasons.join("; ")}`);
console.log(`candidate ${p.token.symbol} v${p.version} liq $${p.liquidityUsd} https://dexmarketcap.app/ETH/${p.pool}`);
// → your buy logic
});
Polling works on every plan: GET /rank/new-pairs?window=5m&limit=50 every 30 seconds returns the same rows.
3. Vet a wallet before you copy it
This is the part no price feed gives you. A wallet's PnL table lists every token it traded with bought/sold totals and, on ULTRA+, the token's verdict. Count how many of its closed positions ended in a rug or dump:
async function vetWallet(address) {
const [{ data: w }, { data: rows }] = await Promise.all([
api(`/wallets/${address}`),
api(`/wallets/${address}/pnl?limit=500`),
]);
const closed = rows.filter(r => r.sold.txs > 0);
const rugExits = closed.filter(r => r.flags?.rugged || r.flags?.dumped);
const oneShot = closed.filter(r => r.bought.txs === 1 && r.sold.txs === 1 && r.lastTx - r.firstTx < 3600);
const rugShare = closed.length ? rugExits.length / closed.length : 0;
let verdict = "trader";
if (closed.length >= 20 && rugShare >= 0.5) verdict = "rug-farm insider";
else if (closed.length >= 20 && rugShare >= 0.25) verdict = "rug-linked";
else if (w.winRatePct > 95 && closed.length >= 50) verdict = "too good: check manually";
return { verdict, positions: closed.length, rugExits: rugExits.length, rugShare: +rugShare.toFixed(2),
oneShotShare: +(oneShot.length / Math.max(closed.length, 1)).toFixed(2),
winRatePct: w.winRatePct, realizedPnlUsd: w.realizedPnlUsd };
}
console.log(await vetWallet("0x3e88a2ec0f332a9053de55a32cb6835ef11a3faf"));
That address is the insider wallet from our rug-farm investigation. Output:
{ verdict: 'rug-farm insider', positions: 948, rugExits: 944, rugShare: 1,
oneShotShare: 1, winRatePct: 100, realizedPnlUsd: 811277 }
(limit=500 returns up to 500 rows on ULTRA; MEGA returns the full table, which is what the output above was computed on.)
Win rate 100%, one buy and one sell per token inside the hour, 944 of 948 closed positions exited from a token that was rugged afterwards. A copy bot that ranks wallets by win rate puts this wallet at number one and follows it straight into the next rug, because the insider buys before the public and sells before the pull. The flags turn that around in one call.
4. Who is winning in this pool?
Before entering a pool that is already trading, look at who made the money so far. If the top traders are rug-farm insiders, the pool is a farm.
async function vetPool(pool) {
const { data: top } = await api(`/pools/${pool}/top-traders?limit=10`);
const checks = await Promise.all(top.filter(t => !t.walletType).map(async t => ({ ...t, ...(await vetWallet(t.wallet)) })));
const insiders = checks.filter(c => c.verdict === "rug-farm insider" || c.verdict === "rug-linked");
return { topTraders: checks.length, insiders: insiders.length,
insiderProfitUsd: Math.round(insiders.reduce((s, c) => s + c.realizedUsd, 0)),
ok: insiders.length === 0 };
}
walletType (ULTRA+) marks exchanges, routers, pools and burn addresses so you do not run a PnL check on Binance.
5. Python
The same token check in Python, for bots that live there:
import os, requests
HOST = "dex-analytics.p.rapidapi.com"
H = {"X-RapidAPI-Key": os.environ["RAPIDAPI_KEY"], "X-RapidAPI-Host": HOST}
get = lambda path: requests.get(f"https://{HOST}{path}", headers=H, timeout=10).json()["data"]
def vet_token(address):
t, h = get(f"/tokens/{address}"), get(f"/tokens/{address}/holder-stats")
f = t.get("flags", {})
reasons = [k for k in ("honeypot", "rugged", "dumped", "dead") if f.get(k)]
if t["liquidityUsd"] < 10_000: reasons.append(f"thin liquidity ${t['liquidityUsd']:,.0f}")
if h["top10Pct"] > 50: reasons.append(f"top 10 hold {h['top10Pct']}%")
return {"symbol": t["symbol"], "ok": not reasons, "reasons": reasons}
print(vet_token("0x6982508145454ce325ddbe47a25d4ec3d2311933"))
The data: 14 days of Uniswap launches
Every pool created on Ethereum Uniswap between 14 and 28 October 2026, judged by the same rules behind flags. "Dead" means the token has no trading activity left. Lifetime is launch to last swap.
| All | V2 | V3 | V4 | |
|---|---|---|---|---|
| Pools launched | 8,304 | 1,389 | 458 | 6,457 |
| Confirmed rug pulls | 1,371 (17%) | 1,072 (77%) | 43 (9%) | 256 (4%) |
| Confirmed dumps | 160 (2%) | 84 (6%) | 29 (6%) | 47 (1%) |
| Dead | 6,573 (79%) | 1,350 (97%) | 416 (91%) | 4,807 (74%) |
| Median lifetime | 30 min | 24 min | 30 min | 48 min |
| Stopped trading within 24 h | 79% | 93% | 71% | 75% |
When the rugs happen, counted from the pool's first liquidity to its last trade:
| Within | Rugs | Share |
|---|---|---|
| 1 hour | 939 | 61% |
| 6 hours | 1,218 | 80% |
| 24 hours | 1,414 | 92% |
| 3 days | 1,490 | 97% |
What this says for a sniper:
- V2 is a rug factory. More than three in four V2 launches in this window were pulled. The LP tokens of a V2 pool can be removed in one transaction by whoever holds them. A V2 launch with unlocked LP and under 50 holders is a coin flip at best.
- V4 does not rug, it dies. Only 4% of V4 pools were pulled, but 74% went dead within the window. V4 liquidity is often one-sided (just the token) or held by a hook, so there is nothing to pull: the crew sells, the pool empties, the price goes to zero. Those count as dumps only when real money went in; most never had any.
- The first hour is everything. 61% of all pulls land inside the first hour, 80% inside six. A snipe that is not out within the hour is holding through the window where most of the damage happens.
- Dumps are rarer than pulls but harder to see. Burned or locked liquidity reads as "safe" on every checker. It only says the liquidity stays; it says nothing about the supply. Holder concentration is the number that catches a dump before it starts.
Plans and limits
flags on tokens, pools, new pairs, PnL rows and holdings are on ULTRA and MEGA. Holder stats concentration is PRO and up, the tiers and depth ULTRA. The free plan gives 50 requests a day, enough to test every call in this post. The verdicts are our own, derived from indexed liquidity and swap data; we do not resell third-party audit scores.
- API: rapidapi.com/sven.esser86/api/dex-analytics
- Site: dexmarketcap.app, every verdict above is visible on the pool and token pages, and the Scam Watch page lists the live operations.
- Questions and feature requests: comments here, or the RapidAPI discussion tab.
Top comments (0)