If you build trading bots or token scanners on Solana, you probably already check new launches for bundling — multiple wallets buying in the token's creation block via a Jito bundle. Tools like Trench Radar made that check standard, and it catches a lot.
Here's the problem: the people running coordinated launches know exactly what you're checking. The counter-move is documented practice by now, and it's dead simple:
Fund 5–15 fresh wallets days before launch — through intermediaries or exchange withdrawals, never directly from the deployer's main wallet.
Don't buy in the creation block. Buy a few seconds or minutes later, mixed in with real traders.
Sell into retail volume once it arrives.
No bundle. Clean bubble map. 0% on every same-block checker. On-chain research into pump.fun launches found deployers funding "sniper wallets" like this at scale — 15,000+ SOL in realized profit across 15,000+ launches. So this isn't an edge case; it's the standard evasion.
The launches still leave two traces, though, and both are readable with nothing but standard RPC calls.
Trace 1: the funding graph
Coordinated wallets were seeded from somewhere. Walk each early buyer's SOL inflows backwards and "independent" wallets collapse into a small set of shared funding sources — sometimes the deployer itself, one hop removed.
The core of it is just getSignaturesForAddress + getTransaction, looking for the first meaningful SOL inflow in a window around the token's creation:
async function findFunder(connection, wallet, windowStart, windowEnd) {
const sigs = await connection.getSignaturesForAddress(wallet, { limit: 50 });
for (const s of sigs) {
if (!s.blockTime || s.blockTime > windowEnd) continue;
if (s.blockTime < windowStart) return null; // past the window
const tx = await connection.getParsedTransaction(s.signature, {
maxSupportedTransactionVersion: 0,
});
if (!tx?.meta) continue;
const keys = tx.transaction.message.accountKeys.map(k => k.pubkey.toBase58());
const idx = keys.indexOf(wallet);
const received = tx.meta.postBalances[idx] - tx.meta.preBalances[idx];
if (received < 5_000_000) continue; // ignore dust/rent (< 0.005 SOL)
// the account whose balance dropped is the sender
for (let i = 0; i < keys.length; i++) {
if (i !== idx && tx.meta.preBalances[i] - tx.meta.postBalances[i] >= 5_000_000) {
return { funder: keys[i], evidenceTx: s.signature };
}
}
}
return null;
}
Run that over the top holders, group by funder, and any funder feeding 2+ holders is a cluster. Two things will bite you in production:
CEX noise. Several holders funded from the same Binance hot wallet is not a cabal — it's people withdrawing from the same exchange. You need to identify exchange/infra wallets (high throughput is the tell: ~1000 txs in minutes-to-hours, no human does that) and exclude them, or your false-positive rate makes the whole check useless.
Windows matter. For graduated pump.fun tokens, the pair-creation timestamp is graduation, not token creation. Cabal wallets get funded during the bonding-curve phase, which can run hours earlier. A tight window misses almost everything.
Trace 2: the first buyers (this is the one everyone skips)
A holder-based scan has a fatal timing flaw: the snipers vanish from the top-holder list the moment they exit — which is exactly when the damage happens. Scan after the dump and everything looks clean.
But who bought first is permanent history. Walk the mint's signature history back to its earliest transactions, extract the buyers from the token-balance deltas, and run the same funding trace on them — regardless of whether they still hold anything:
// buyers = owners whose balance of mint increased in the tx
function parseBuyers(tx, mint) {
const pre = {}, buyers = [];
for (const b of tx.meta.preTokenBalances ?? [])
if (b.mint === mint && b.owner) pre[b.owner] = b.uiTokenAmount.uiAmount ?? 0;
for (const b of tx.meta.postTokenBalances ?? []) {
if (b.mint !== mint || !b.owner) continue;
const delta = (b.uiTokenAmount.uiAmount ?? 0) - (pre[b.owner] ?? 0);
if (delta > 0) buyers.push({ owner: b.owner, delta });
}
return buyers;
}
Then compare each early buyer's launch bag with their current balance (getTokenAccountsByOwner). A group of first buyers who share a funding source, took a double-digit slice at launch, and have already exited is the unbundled-launch fingerprint — and no same-block tool will ever show it to you.
One practical warning: walking a mint's signature history backwards is cheap for dead/rugged tokens (one or two pages) but can be thousands of signatures for an active token. Budget it — pages and wall-clock time — and degrade gracefully instead of hanging your scanner.
Or skip the plumbing
Full disclosure: I build Cabal-Hunter, which runs all of the above (plus same-block bundle detection, live coordinated-dump detection, and deployer launch history) behind one call, with the funding transactions returned as evidence you can verify on Solscan:
250 scans/month free, no signup, no API key
curl "https://api.cabal-hunter.com/api/scan-cabal?mintAddress="
"clusters": [{
"type": "early_sniper",
"wallet_count": 4,
"bought_pct": 11.2,
"combined_pct": 0.3,
"evidence_txs": ["5Kd9..."]
}]
For AI agents there's an MCP server — npx cabal-hunter-mcp — same engine, one tool (check_cabal_risk).
But honestly: if you're building your own scanner, build the two traces above. The unbundled launch is the pattern that matters in 2026, most tools still don't look for it, and everything you need is sitting in public RPC data.
Top comments (0)