Stable Boystable boy
back
whitepaper · v1.0.3

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.

factorweight
Hold duration22
Paperhand ratio18
Funding source13
Wallet age12
PnL behavior12
Token diversity10
Win/loss distribution8
SOL balance5
total100

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.

patternscore
direct from labeled CEX (Coinbase, Binance, etc.)100
1 hop from labeled CEX85
direct from labeled fund / protocol75
3+ hops to labeled CEX60
no funder data50
small initial funding (<0.5 SOL)35
daisy-chain — 3+ fresh-wallet intermediates25
immediate funder is in our bundler registry0

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.

flagpenalty
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–100Diamond handsreal user, holds, clean cluster
50–79Active traderlegit but rotates fast
20–49Degen / sniperhigh velocity, low conviction
0–19Bundler-adjacentclustered, 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
rankamount
#19,523,809
#57,619,047
#105,238,095
#152,857,142
#20476,190

showing ranks 1, 5, 10, 15, 20 · full table on /airdrop

Claim flow

  1. 1.User connects their Solana wallet via standard wallet adapter (Phantom, Solflare, Backpack, etc.).
  2. 2.Frontend hits /api/airdrop/eligibility with the connected address. Server checks the current top 20 + the airdrop_claims table and returns rank + amount or a not-eligible reason.
  3. 3.If eligible, user clicks Claim. Frontend builds a claim message (wallet + timestamp), asks the wallet to sign it.
  4. 4.Frontend POSTs /api/airdrop/claim with the wallet, message, and signature. Server verifies the ed25519 signature, re-checks eligibility (never trusting client-supplied amount), reserves the wallet in airdrop_claims, then signs and submits an SPL transferChecked from the dev wallet to the user's associated token account.
  5. 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_address means two concurrent claims for the same wallet produce one winner and one 409 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.
  • ·transferChecked asserts 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.
v1.0.3 · last revised on every commit to the engine config
stability scores are a heuristic, not a verdict