Individual signals lie. A strong cap table with known wallets can still go to zero. A high buyer quality score can be followed by a rug. A KOL buy can be a coordinated pump-and-dump. But when multiple independent signals converge on the same token simultaneously — that's when the probability of a genuine opportunity starts to become meaningful.
This post walks through the full signal stack for detecting smart money entries on Solana: what each signal means, how to query it via the Alpha Wallet Intelligence API, and how to combine them into a structured decision checklist.
The Four Signals
Signal 1: Cap Table Composition
What it tells you: Who bought this token in its first minutes of existence, and whether those wallets have a track record of being right.
Endpoint: GET /api/v1/tokens/{mint}/cap-table
The cap table is your starting point. It answers the most fundamental question: did any wallets with verified performance history accumulate early? If the answer is no — if the first buyers are all bots, fresh wallets, or bundle participants with no track record — the other signals are less relevant. For a step-by-step on pulling and reading this list, see our guide on how to find the early buyers of Pump.fun tokens and whether they're smart money.
What you're looking for in the cap table:
- Two or more wallets with
win_rate > 0.55 and tokens_traded >= 20
- No dominance of
bundle_flags: true entries (ideally under 30% of early buyers)
bot_confidence skewing toward low across the clean buyers
- At least one entry with positive
net_pnl_sol — they've actually made money before
The cap table check takes one API call. It's the cheapest filter in the stack and should run first.
Signal 2: Buyer Quality Score
What it tells you: A single 0–100 cohort rating that aggregates win rates, bot signals, bundle flags, and KOL presence into a single number.
Endpoint: GET /api/v1/tokens/{mint}/buyer-quality
Available on all tiers. Cached for 5 minutes server-side, so you can poll it as the token matures and watch the score evolve as more wallets are processed.
Score thresholds for this framework:
| Score | Action |
|---|
| ≥ 70 | Green light — proceed to Signal 3 |
| 50–69 | Yellow — check cap table manually before proceeding |
| < 50 | Stop — cohort quality doesn't support entry |
The quality score and the cap table review are related but not redundant. The quality score gives you a fast go/no-go. The cap table review gives you the specifics that explain the score and may reveal nuances the aggregate misses.
Signal 3: Leaderboard Wallet Match
What it tells you: Whether the specific wallets in the cap table are among the top performers in the entire 25,000+ wallet database — not just better than average, but elite.
Endpoint: GET /api/v1/alpha/leaderboard (used to build your watchlist offline)
The leaderboard doesn't directly answer "is this specific wallet good?" — the cap table endpoint already tells you each wallet's win rate. What the leaderboard adds is context: where does this wallet sit relative to every other scored wallet?
A wallet with a 58% win rate might look mediocre in isolation. If that win rate puts them in the top 200 out of 25,000+ scored wallets, it looks very different.
The practical implementation: build a leaderboard-sourced watchlist offline (refresh weekly), then check cap table buyers against that list. Any cap table buyer who also appears in your top-200 leaderboard watchlist is a tier-1 signal.
import { MadeOnSolClient } from "madeonsol";
const client = new MadeOnSolClient({ apiKey: process.env.MSK_API_KEY });
// Built once, refreshed weekly
let smartMoneySet: Set<string> = new Set();
async function refreshLeaderboard() {
const board = await client.alpha.getLeaderboard({
period: "all",
sort: "win_rate",
min_tokens: 25,
exclude_bots: true,
});
smartMoneySet = new Set(board.wallets.map((w) => w.wallet));
}
// Used per-token check
async function countLeaderboardHits(mint: string): Promise<number> {
const capTable = await client.alpha.getCapTable(mint);
return capTable.buyers.filter((b) => smartMoneySet.has(b.wallet)).length;
}
One leaderboard hit in the cap table is notable. Two is significant. Three or more is exceptional.
Signal 4: KOL Coordination
What it tells you: Whether known KOL wallets bought early, and whether multiple KOLs coordinated (a stronger signal than a single KOL entry).
Sources: is_kol field in cap table response + KOL tracker for call history
The is_kol flag in the cap table response tells you whether a buyer is flagged as a known KOL in the database. A single KOL buying early might mean a call is coming — or it might mean they were scouting and decided against calling it. Two or more KOLs in the early buyers is a much stronger coordination signal.
Cross-reference with the on-site KOL tracker: does this wallet have a history of calling tokens that pumped? What's their typical call frequency? A KOL who calls one token per week and is in the early buyers matters more than one who calls twenty tokens per day.
The linked wallets endpoint adds another layer:
GET /api/v1/alpha/{wallet}/linked
(ULTRA tier) This shows wallets that co-bought 3+ of the same tokens within 2 seconds of each other. When a KOL wallet appears in the cap table alongside several of its linked wallets, it's a group coordinating entries — not just one account.
The Signal Stack in Practice
Here's the decision framework assembled end-to-end:
Token Alert Received
│
▼
1. GET /cap-table
┌── Any clean buyers (no bundle, low bot confidence)?
│ NO → Skip
│ YES → Continue
│
▼
2. GET /buyer-quality
┌── Score >= 50?
│ NO → Skip
│ YES → Continue
│
▼
3. Leaderboard check
┌── Any cap table buyers in top watchlist?
│ NO → Weak signal, optional entry with small size
│ YES → Continue
│
▼
4. KOL check
┌── Any is_kol buyers? Linked wallets present?
│ NO → Signal confirmed, standard entry
│ YES → Signal amplified, full position
In code, this becomes a scoring function that returns a confidence level:
interface SignalResult {
score: number;
confidence: "none" | "weak" | "moderate" | "strong" | "very_strong";
breakdown: Record<string, number>;
}
async function assessToken(mint: string): Promise<SignalResult> {
const [quality, capTable] = await Promise.all([
client.alpha.getBuyerQuality(mint),
client.alpha.getCapTable(mint),
]);
const cleanBuyers = capTable.buyers.filter(
(b) => !b.bundle_flags && b.bot_confidence !== "high"
);
const leaderboardHits = cleanBuyers.filter((b) =>
smartMoneySet.has(b.wallet)
).length;
const kolHits = capTable.buyers.filter((b) => b.is_kol).length;
const breakdown = {
qualityScore: quality.score,
cleanBuyerCount: cleanBuyers.length,
leaderboardHits,
kolHits,
};
// Composite scoring
let score = quality.score * 0.4; // 40% weight on quality score
score += Math.min(leaderboardHits * 10, 30); // up to 30 points for leaderboard hits
score += Math.min(kolHits * 10, 20); // up to 20 points for KOL presence
score += cleanBuyers.length >= 3 ? 10 : 0; // 10 points for clean buyer depth
const confidence =
score >= 85
? "very_strong"
: score >= 70
? "strong"
: score >= 55
? "moderate"
: score >= 40
? "weak"
: "none";
return { score: Math.round(score), confidence, breakdown };
}
Combining With Deployer Intelligence
The signal stack above is purely buyer-side. There's a parallel deployer-side filter that's equally important and orthogonal: has the token's creator wallet historically launched tokens that performed?
The Deployer Hunter tracks 15,500+ deployer wallets by bonding rate and launch history. A token from an Elite-tier deployer that also passes the full buyer signal stack has cleared both demand-side (who bought) and supply-side (who launched) filters simultaneously. That combination is rare — and worth paying attention to when it appears.
Full deployer analysis methodology is covered in the pump.fun deployer tracker post.
The Honest Limitations
Even with all four signals green, you're working with probabilities, not certainties. A few things this framework cannot catch: