Skip to content

Landing Score v1

After this page you can recompute any published Landing Score from its inputs, and argue with the methodology on its actual terms. This is the versioned recipe; if any ingredient changes, the version bumps and both are published. The reference implementation lives in packages/shared (score.ts, botscore.ts) — the leaderboard, the API, and this page all run the same code.

Landing Score = bot-adjusted real-user landing rate.

For a program over a window:

score = landed_real / (landed_real + dropped_real)

where a transaction is real iff its signer’s bot score for that UTC day is < 0.5, and dropped_real counts real-user attempts classified as drops. Programs with zero observed real-user attempts get score 1 with an interval of [0, 1] — i.e. “no evidence”, not “perfect”.

Deliberately not ML: three transparent signals per signer per UTC day, combined with fixed weights into a score ∈ [0, 1].

Signal Weight Recipe
Volume (signer clustering) 0.5 Daily tx count, log-scaled: 0 at ≤10 tx/day, 1 at ≥5 000 tx/day
Timing regularity 0.3 Coefficient of variation of inter-tx gaps: CV 0 (metronome) → 1, CV ≥ 1 (human burstiness) → 0. Needs ≥5 gaps, else 0
Program diversity 0.2 Distinct programs touched: 1 program all day → 1, ≥6 programs → 0. Signers with <20 tx/day score 0 (not enough evidence)
bot_score = 0.5·volume + 0.3·regularity + 0.2·diversity // clamped to [0,1]
bot = bot_score ≥ 0.5

Known failure modes, accepted for v1: a patient bot under 5 000 tx/day with randomized timing passes as human; a power user who hammers one program all day can look bot-ish. The weights put volume first because it is the hardest signal to fake cheaply. v2 candidates (funding- graph clustering, fee-payer reuse) will be a new version, not a silent change.

Every published score carries a Wilson 95% interval computed on the observed counts:

n = landed_real + dropped_real (observed, not scaled-up)
center = (p + z²/2n) / (1 + z²/n) z = 1.96
margin = z·√(p(1−p)/n + z²/4n²) / (1 + z²/n)

Wilson is chosen over the normal approximation because leaderboard tails — tiny programs, heavy sampling — hit small n constantly, where the normal interval lies.

Ranking rule: overlapping intervals mean the order between two programs is not a claim.

Pre-firehose, mainnet observation is sampled within a fixed public-RPC budget. What that means, stated plainly:

  • Counts are observed counts. We do not scale them up and pretend we saw everything; the interval is computed on what was actually seen, so less coverage ⇒ honestly wider bands.
  • The sample rate is published per program (sampleRate in the dataset).
  • Sampling is time-stratified, so bursty programs are not systematically favored — but a failure mode concentrated in unsampled slots can still be under-observed. That risk shrinks as coverage grows and vanishes with full-firehose funding (a config flip, not a code change).
  • Drops attributed to real users can only be observed for programs whose clients run the SDK; for programs observed purely on-chain, dropped_real is estimated from send-visible public signals and is the weakest input in v1. The dataset marks which basis applies.
  • v1 (current) — initial public recipe, as above.