A 0–100 wallet stability score
for the pump.fun ecosystem.
What it measures, what it doesn't, how it's computed, where the data comes from, and how the airdrop mechanism works. Every number on this page is pulled from the live engine config; if the engine changes, this page changes with it.
1 · Abstract
Stable Boy assigns every Solana wallet a single number between 0 and 100. The number describes how legible the wallet looks: how much it behaves like a human trader versus a coordinated bundle, an instant-dump bot, or an insider that traded a token before its visible launch.
The score is computed from eight behavioral signals (Layer 1) and reduced by up to six trust penalties (Layer 2). Both layers run against on-chain data sourced from three independent providers — no opinions, no allowlists, no editorial overrides.
A high score is not a profitability claim. A low score is not an accusation. The number is a heuristic shaped by the pump.fun ecosystem's actual patterns; it's designed to be legible and shareable, not authoritative.
2 · Why a score
Pump.fun trading is dominated by patterns that look identical to a human at a glance: a wallet bought a token, made money or didn't, moved on. But on-chain, those wallets fall into very different categories.
- ·Diamond hands — real users who pick a few tokens, hold for hours or days, exit on conviction.
- ·Active traders — legitimate but high-velocity rotators. Take profit, move to the next.
- ·Degens / snipers — buy in the first blocks of a launch, exit within minutes, do this on dozens of tokens a day. Not insiders, but not investors either.
- ·Bundlers / insiders — coordinated actors. Multiple wallets buying the same token in the same Jito bundle. Funded by a shared upstream wallet. Often the dev or someone with pre-launch knowledge.
Tools like trench.bot show some of this per-token. Bubblemaps shows the funding-cluster graph. GMGN tags traders inside a token's top-buyers list. None of them give you one number per wallet that distills which category the wallet falls into based on its full behavior.
That number is Stable Boy.
3 · Architecture
Two layers, composed additively:
final_score = clamp(layer1 + layer2, 0, 100)
- ·Layer 1 (behavioral, 0–100) — weighted average of eight factors describing how the wallet trades.
- ·Layer 2 (penalties, capped at -60) — hard deductions for coordinated-actor patterns. Stack additively; total layer-2 contribution can never exceed half the score.
Wallets with fewer than 5 lifetime trades AND fewer than 3 lifetime tokens return insufficient_data instead of a faked score. We refuse to score what we can't meaningfully measure.
4 · Layer 1 — behavioral score
Eight signals, each producing a sub-score 0–100, weighted into a single Layer 1 number. The weights sum to 100. Curves are tuned to the pump.fun memecoin context; what counts as “long hold” here would be milliseconds in a market with longer time horizons.
| factor | weight |
|---|---|
| Hold duration | 22 |
| Paperhand ratio | 18 |
| Funding source | 13 |
| Wallet age | 12 |
| PnL behavior | 12 |
| Token diversity | 10 |
| Win/loss distribution | 8 |
| SOL balance | 5 |
| total | 100 |
4.1 Hold duration
Median time between a wallet's buy of a token and its first sell of that token. The single most-predictive behavioral signal: bundlers and snipers exit within seconds-to-minutes; long-form holders register hours-to-days.
< 2 min → 0 2–10 min → 20 10 min–1 h → 40 1–6 h → 60 6–24 h → 75 1–7 d → 88 > 7 d → 100
Source: GMGN wallet_stats.pnl_stat.avg_holding_period (seconds, 30-day window).
4.2 Paperhand ratio
Percentage of closed positions that were exited within 5 minutes of entry. Distinct from hold-duration because it measures the distribution, not the median — a wallet with 50% <5min exits and 50% multi-day holds has the same hold-duration as one with 100% 1-hour holds, but tells a different story.
Computed from per-tx wallet_activity using FIFO pairing: each buy enters a queue, each sell consumes the oldest entry, the hold duration of the pair is the difference. Requires at least 3 closed pairs to compute; otherwise returns skipped.
> 80% paperhand → 0 60–80% → 15 40–60% → 35 20–40% → 60 5–20% → 85 < 5% → 100
4.3 Funding source
Where did the wallet's initial SOL come from? Direct from a CEX is a green flag (real onramp). A daisy-chain of freshly-created wallets is a red flag (automation tell).
Stable Boy traces the funding chain up to 3 hops, classifies each hop using Helius entity labels, and detects daisy-chain patterns by inspecting wallet-age timestamps.
| pattern | score |
|---|---|
| direct from labeled CEX (Coinbase, Binance, etc.) | 100 |
| 1 hop from labeled CEX | 85 |
| direct from labeled fund / protocol | 75 |
| 3+ hops to labeled CEX | 60 |
| no funder data | 50 |
| small initial funding (<0.5 SOL) | 35 |
| daisy-chain — 3+ fresh-wallet intermediates | 25 |
| immediate funder is in our bundler registry | 0 |
4.4 Wallet age
Days between the wallet's first observed transaction and now. A meaningful signal because automated wallets are often freshly created for a specific bundle; long-lived wallets had to have been created and used for something else first.
< 7 d → 20 7–30 d → 45 30–180 d → 75 > 180 d → 100
4.5 PnL behavior
A coarse proxy for how the wallet manages positions: high sell-to-buy ratios suggest aggressive dumping or rotation; accumulators sit on the low end. This is v1 — a more honest version measures full-dump events directly from per-position exit data.
sell/buy ratio: > 3 → 30 (dump-heavy) > 1.5 → 55 > 0.7 → 80 ≤ 0.7 → 70 (accumulator-leaning)
4.6 Token diversity
Number of distinct pump.fun tokens traded in 30 days, normalized to tokens-per-day. Sniper accounts churn dozens of tokens a day. Focused holders touch only a few.
> 20/day → 15 10–20/day → 35 3–10/day → 65 1–3/day → 85 < 1/day with multi-token → 100 < 1/day, single token → 60 (anomaly)
4.7 Win/loss distribution
Not just the win rate — the shape of the PnL distribution. We bucket every closed position into five ranges (<−50%, −50% to 0%, 0–2×, 2–5×, >5×) and look at the proportions.
- ·Mostly moonshots, few losses → insider tell (you don't pick winners that cleanly by luck).
- ·Pure-loss profile, no upside → chaser.
- ·Mixed wins and losses with a tail of mid-wins → healthy human distribution.
Both extremes — too clean and too noisy — score lower than a normal trader.
4.8 SOL balance
Native SOL balance held idle at the time of scoring. A wallet that keeps meaningful SOL on hand is more likely to be a considered trader; one that churns every lamport through Jupiter is more likely automated.
v1 uses a snapshot — a proper version would use the time-series. The current implementation overweights wallets that happen to have just received funds.
5 · Layer 2 — trust penalties
Six independent flags. Each detects a specific coordinated- actor pattern; each carries a fixed deduction. Layer 2 totals are capped at -60 so penalties can never exceed half the score range.
| flag | penalty |
|---|---|
| bundle co buy | -20 |
| cluster one hop | -15 |
| cluster two hop | -7 |
| sniper window | -5 |
| funding daisy chain | -15 |
| wash trade | -10 |
| dormant coordinated | -10 |
5.1 Bundle co-buy
The pump.fun bundler fingerprint: ≥3 distinct signer addresses buying the same mint in the same slot. Same-slot multi-signer buys of a fresh token are essentially the signature of a Jito bundle — coordinated, atomic, effectively impossible by coincidence.
Each bundle hit subtracts -20; capped at -40 (max 2 bundles count).
Source: Bitquery same-slot signer-count aggregation on the pump.fun program.
5.2 Sniper window
A wallet bought a pump.fun token within 3 blocks of the token's very first trade. Most-aggressive sniper bots fire in block 0 or 1; a 3-block window catches the slower-but-still-coordinated tier.
Each occurrence subtracts -5; capped at -20.
Source: Bitquery limitBy-style aggregation — earliest pump.fun trade per mint, compared against the wallet's buy slot.
5.3 Cluster proximity
We recursively walk the wallet's funding chain (up to 3 hops via GMGN fund_from_address) and intersect each hop against our local bundler registry. The registry grows organically: every time someone scores a wallet, we asynchronously pull GMGN's per-token bundler tags on that wallet's most recent tokens and write them into a Postgres table. The registry compounds over time.
- ·1-hop hit (your funder is in the registry) →
-15 - ·2-hop hit →
-7
Cold-start property: when the registry is empty, this penalty rarely fires. Every score makes the next score smarter.
5.4 Funding daisy-chain
The funder chain has 3+ hops, and every intermediate wallet was funded within 24 hours of its own creation. Real users are funded from accounts that existed before; daisy-chains are constructed by automation that creates a fresh wallet, funds it from another fresh wallet, funds that from another fresh wallet, all in minutes.
Penalty: -15.
5.5 Wash trade
3+ distinct tokens where the wallet executed at least two opposite-side trades within 10 minutes of each other — the self-churn fingerprint. Catches wallets generating fake volume to look active.
Limitation: this version catches a wallet self-churning a token. True cross-wallet wash (where the counterparty is another wallet of yours) needs counterparty inspection — v3.
Penalty: -10.
6 · Verdict bands
The score range is sliced into four named bands. The boundaries are deliberately wide so small variations don't flip the verdict.
| 80–100 | Diamond hands | real user, holds, clean cluster |
| 50–79 | Active trader | legit but rotates fast |
| 20–49 | Degen / sniper | high velocity, low conviction |
| 0–19 | Bundler-adjacent | clustered, suspicious funding, instant dumps |
7 · Data pipeline
Three providers, each used for what it's best at. No single provider can be replaced without losing functionality; none of them sponsor or endorse Stable Boy.
7.1 GMGN
Source of the behavioral data: wallet_stats (PnL buckets, winrate, hold duration, token count, funder address), wallet_holdings (unrealized PnL),wallet_activity (per-tx history for paperhand ratio + heatmap), token_top_traders (for the bundler-registry accumulation).
Rate limit: 1 request per second per API key. The scoring service serializes calls through a promise chain to respect the limit; fresh scores take 8–12 seconds.
7.2 Bitquery
Source of pump.fun-program-level data: DEXTradeByTokens queries on the pump.fun program address for bundle co-buy detection (same-slot multi-signer scan) and sniper-window detection (earliest trade per mint).
7.3 Helius
Source of entity labels on the funder chain. The Wallet API identity endpoint classifies an address as CEX, protocol, fund, or unknown — driving the funding-source curve's upper tiers.
8 · The diamond-hands airdrop
The live top-20 diamond hands board (last 7 days) defines a rolling set of eligible wallets. Each rank earns a fixed allocation from a 100,000,000 $Stable pool, distributed linearly.
amount(rank) = (21 − rank) / 210 × 100,000,000
| rank | amount |
|---|---|
| #1 | 9,523,809 |
| #5 | 7,619,047 |
| #10 | 5,238,095 |
| #15 | 2,857,142 |
| #20 | 476,190 |
showing ranks 1, 5, 10, 15, 20 · full table on /airdrop
Claim flow
- 1.User connects their Solana wallet via standard wallet adapter (Phantom, Solflare, Backpack, etc.).
- 2.Frontend hits
/api/airdrop/eligibilitywith the connected address. Server checks the current top 20 + theairdrop_claimstable and returns rank + amount or a not-eligible reason. - 3.If eligible, user clicks Claim. Frontend builds a claim message (wallet + timestamp), asks the wallet to sign it.
- 4.Frontend POSTs
/api/airdrop/claimwith the wallet, message, and signature. Server verifies the ed25519 signature, re-checks eligibility (never trusting client-supplied amount), reserves the wallet inairdrop_claims, then signs and submits an SPLtransferCheckedfrom the dev wallet to the user's associated token account. - 5.On confirmation, the row is updated with the real tx signature and the user gets a solscan link.
Security model
- ·Server-signed transfer (hot-key model). The dev wallet's secret lives in a Vercel env var. Trade-off accepted: simplest UX in exchange for a finite blast radius (the dev wallet holds only the airdrop allocation, not a treasury).
- ·Signed-message ownership proof. No transfer fires until the recipient signs a message containing their wallet address and a fresh timestamp. Defeats spoofed POSTs. Replays past 5 minutes are rejected.
- ·Database-level double-claim prevention. Primary key on
wallet_addressmeans two concurrent claims for the same wallet produce one winner and one409 Conflict— no race window. - ·Reservation-first transfer. The claim row is inserted with a placeholder signature before the on-chain call. If the transfer fails, the row is deleted so the user can retry; if it succeeds, the row is updated with the real signature.
- ·
transferCheckedasserts decimals on-chain. Accidental 10× sends from a wrong decimals config are rejected by the SPL program itself.
9 · Privacy
Stable Boy stores three things in its database, all keyed by public Solana wallet address (a public identifier, not PII):
- ·
scored_wallets— the most-recent score per wallet, plus the full receipt JSON, for 24 hours (cache-with-TTL). - ·
funder_lookups— immutable map of wallet → its funder address, derived from public on-chain data. - ·
bundler_taglog— append-only log of per-token trader labels (sniper/bundler/insider/smart-money) observed from public GMGN data. - ·
airdrop_claims— one row per successful claim: wallet, rank, amount, tx signature, timestamp.
Local browser state: a short recently scored list in localStorage, capped at 5 entries. Never transmitted.
No accounts. No emails. No tracking pixels. No analytics SDKs. The site doesn't know who you are.
10 · Limitations we're honest about
- ·30-day window. GMGN's deepest period is 30d, so a wallet dormant in that window scores insufficient_data even if it has years of history.
- ·Pump.fun-flavored. A wallet that primarily trades Jupiter routes or pure Raydium pools will look small through this lens. Stable Boy is intentionally scoped to memecoin behavior.
- ·Cluster cold start. The bundler registry grows from observed tag events. Early scores produce weaker cluster signal than later scores once the registry has compounded.
- ·Wash detection misses cross-wallet wash. Catches a wallet self-churning but not a wallet washing through another wallet it controls — v3 work.
- ·SOL balance is a snapshot. A wallet that just received SOL looks identical to one that's held SOL for months. Real time-series scoring is v3.
- ·Airdrop eligibility is live, not snapshot. If you get bumped from the top 20 between when you check and when you claim, you lose the claim. Race the leaderboard.
11 · Open source
Stable Boy is MIT licensed. Self-host it, fork it, embed the badge, contribute back. The entire scoring engine — every curve, every weight, every penalty trigger — is in src/lib/scoring/. The airdrop primitives are in src/lib/airdrop/.
The most useful contributions:
- ·Score-disagreement reports. If you know a wallet is a bundler / diamond / etc. and Stable Boy disagrees, open the Score Disagreement issue template with the wallet address and your expected score. Curves get better with real adversarial examples.
- ·New Layer-2 signals — cross-wallet wash, dormant-then- coordinated, anything else that catches what the existing six miss.
- ·Score-curve tuning PRs with the score-impact analysis the PR template asks for.