# Solana rent estimates: study 1.0, 9 September 2026

Author: Reclaim / MarketWhale
Canonical citation: https://reclaim.mwh.app/learn/i-scanned-1000-solana-wallets-free-sol#results

## Scope and provenance

This is a NEW scan of all 85 unique addresses in the repository's retained `snapshots/leaderboard/2026-01-25.json`. The snapshot's date is embedded metadata, not an independently verified historical collection window. Its original selection rules are unavailable. The original article attributed its cohort to KOLScan; current membership, activity, identity and ownership were not verified. No evidence substantiated the earlier 1,000-wallet claim; this study replaces that claim. Historical monetary totals are not compared with this scan because the earlier eligibility and cost calculation cannot be verified.

85 source rows, 85 unique addresses, zero duplicates. Lexicographic address ordering; all addresses attempted, no sampling by outcome. Source, cohort, raw observation and implementation SHA-256 hashes are in `observations.json`. Raw observations are retained separately in the source repository for maintainers. Public rows omit direct identifiers; they are not guaranteed anonymous. Public data permits independent reproduction of aggregates, not independent verification of the wallet-to-row mapping or the underlying RPC responses. Raw token-account RPC payloads were not retained.

## Collection

Solana mainnet-beta, 2026-09-09T15:29:15.238Z through 2026-09-09T15:32:00.922Z. Version 1.0 GET /api/v1/preview on a local Reclaim server using its configured Helius RPC. Confirmed commitment, minContextSlot set from getSlot. Successful observation slots: 445645271–445645788. No atomic cross-wallet snapshot; per-wallet reads may differ in slot. The API emits a 30-second expiry for operational previews; this dataset is a frozen historical record, not a currently actionable quote.

Collection is serial with 1,100 ms between wallets, up to two HTTP attempts per wallet, 20-second HTTP timeout. Retry transport/contract failures, 429, or 5xx once; wait three seconds, or bounded Retry-After (1–60 seconds) when provided. No retry for 422. Both attempts retained. 103 HTTP requests; 18 wallets retried. The API has at most five RPC calls per preview, three in parallel, a 12-second total RPC timeout, a 6 MiB aggregate response budget and a 5,000 total token-account limit. These limits were not relaxed for this study.

75 completed previews; 72 provisionally eligible, three no_accounts, zero blocked. Seven WALLET_TOO_LARGE and three RPC_UNAVAILABLE final failures. WALLET_TOO_LARGE can reflect the account or response-size limit; exact unseen account counts are unknown. Failure amounts are null, never zero. Oversized-wallet exclusions can bias amounts downward; do not generalize to all Solana wallets or extrapolate cohort totals.

## Candidate and cost model

Both legacy SPL Token and Token-2022 accounts queried with getTokenAccountsByOwner. Zero parsed token amounts are candidates after protecting one empty native/wrapped-SOL account (prefer associated token account). The preview checks the reported close authority. It does not fully validate Token-2022 extensions or simulate transactions. 68 completed previews carried TOKEN_2022_REQUIRES_VALIDATION. Every completed preview carries warnings that estimates are not simulated, network fees are unknown, and batch rounding may differ. No signing, account enrollment or transaction submission was part of collection.

Gross = candidate account lamports summed exactly. Service = floor(gross * 600 / 10000). Referral portion = floor(gross * 400 / 10000); paid to service in this preview. When wallet balance <= 100000 lamports, subsidy = 100000 * candidate count. If subsidized with no native account and >=2 empty accounts, service-account rent is a current RPC rent-exemption estimate for a 165-byte account. Net = max(0, gross - service - referral - subsidy - service-account rent). Network fees are null and excluded. This run had no subsidy or service-account-rent deductions. Provisional eligibility is not proof of recoverability. Account state, extensions, authority, transaction checks and fees can alter execution.

Protocol sources:
- https://solana.com/docs/tokens/basics/close-account
- https://solana.com/docs/rpc/http/gettokenaccountsbyowner

## Statistical rules

Primary population: all 75 completed previews, including three no_accounts zero observations. Failed previews are excluded, with unknown amounts. Secondary population: only 72 provisionally eligible previews. Eligibility shares report both denominators: 72/75 = 96%; 72/85 = 84.705882...%, with ten unknown outcomes. The latter is the observed eligible share, not a full-cohort prevalence estimate.

Amounts are integer lamport strings. 1 SOL = 1,000,000,000 lamports. All sums and ordering use BigInt. Median is the middle value for odd N or the arithmetic mean of the middle two values for even N, preserving half lamports. Percentiles use nearest rank: one-based rank ceil(p * N), p = 0.75 or 0.90. No weighting, imputation, trimming, inferential confidence intervals or population extrapolation. Distribution bins in SOL: exactly 0; >0 to <0.01; >=0.01 to <0.1; >=0.1 to <1; >=1. Each population/amount column is partitioned exactly once.

## Files and data dictionary

- `summary.json`: sample counts, status/error counts, requests, retries, slot range, warning counts, distribution bins and gross/net statistics for allCompleted and eligibleOnly.
- `summary.csv`: four population/metric rows with count, total_lamports, median_lamports, p75_lamports, p90_lamports. All amounts in lamports, not SOL.
- `observations.json`: source and implementation hashes, design/method metadata and 85 rows. JSON is the canonical input to analysis; it retains request attempts.
- `observations.csv`: the same 85 rows without nested attempts or metadata. Empty cells mean missing/unknown; numeric zero means measured/estimated zero. Arrays use `|` separators. Import lamport columns as text if a spreadsheet might coerce large integers.
- `analyze.mjs`: dependency-free Node.js 20+ aggregate calculation. No network or wallet access.
- `collect.mjs`: read-only collector; requires a local checkout with the preview implementation, a source snapshot with `wallets[].wallet`, and a running preview server. It refuses to overwrite its output file. Use a different output path for each new collection.

Row fields:
- recordId: stable sequential reference to the sorted frozen cohort; not a wallet address.
- status: eligible, blocked, no_accounts, or failed. Eligible is provisional.
- errorCode: final failure code, null for completed previews.
- attempts (JSON only): requestedAt and finishedAt UTC ISO strings, httpStatus (null on transport/contract failure), errorCode (null on success).
- observedAt: UTC observation timestamp; minSlot/maxSlot: range of successful account/balance observation slots. Null on failure.
- scannedAccounts: all parsed accounts across the two token programs; emptyAccounts: zero token amount; candidateAccounts: empty minus protected; protectedAccounts: preserved native account count. Null on failure.
- grossRentLamports, serviceLamports, referralPortionLamports, subsidyLamports, serviceAccountRentLamports, estimatedNetLamports: exact integer strings on success, null on failure.
- networkFeeLamports: null for every row; never interpreted as a zero network fee.
- reasonCodes, warnings: arrays of API codes; empty arrays on failed rows indicate no preview, not an absence of operational risk.

## Reproduce the published arithmetic

Download observations.json and analyze.mjs into one directory:

```sh
node analyze.mjs observations.json reproduced
```

This writes reproduced.json and reproduced.csv. They should match summary.json and summary.csv byte-for-byte. It recomputes the frozen observations; it does not rescan wallets.

Maintainers can rebuild public outputs from the retained raw run, verify source/cohort/implementation hashes and run checks from the reclaim repository:

```sh
node scripts/research/build-dataset.mjs
node --test scripts/research/checks.mjs
```

For a NEW live scan in the repository with its preview server running:

```sh
node scripts/research/collect.mjs snapshots/leaderboard/2026-01-25.json research/NEW-RUN.json http://localhost:3104
```

Use a unique NEW-RUN output path; wallet state will differ. The public downloads intentionally do not distribute the source's names or wallet-to-person mappings. Do not relabel a new run as this historical dataset.
