Most Solana memecoins die. A few look clean on a chart and still rug. Before you ape, you want a short technical pass: mint/freeze authority, holder concentration (without counting the bonding curve as a whale), LP lock, and a couple of RugCheck signals.
Below is a free, keyless Python 3 script (solcheck.py) that does that in about a minute. Full copy-paste source: solcheck.py on Telegraph. Stdlib only. No API keys.
Not financial advice. A green flag summary does not mean "safe". Bundles and snipers still need a manual look.
What you get
python3 solcheck.py <MINT_ADDRESS> python3 solcheck.py <MINT_ADDRESS> --json Output includes name/symbol/age/launchpad, mcap, liquidity, 24h volume and buys/sells, mint & freeze authority from chain RPC, holder count, top-10 % excluding bonding curve / AMM pools / lockers, dev wallet + holdings + other launches, LP locked %, RugCheck score/risks/insiders, and a RED / YELLOW / GREEN flag list.
Data sources (all free, no keys)
| Source | What we take |
|---|---|
RugCheck api.rugcheck.xyz | token meta, top holders, knownAccounts, markets/LP lock, creator, risks, graph insiders, score |
DexScreener api.dexscreener.com | pair age, mcap, liquidity, 24h volume/txns |
| Jupiter lite-api | price/liquidity fallback, token search meta |
Solana public RPC getAccountInfo | mintAuthority / freezeAuthority (source of truth) |
The script retries on HTTP 429/5xx with simple backoff and prints n/a for fields that failed instead of crashing.
Fetch helper
UA = {"User-Agent": "solana-memecoin-checker/1.0", "Accept": "application/json"} RPC = "https://api.mainnet-beta.solana.com" def fetch(url, body=None, retries=3, timeout=20): data = json.dumps(body).encode() if body is not None else None hdrs = dict(UA, **({"Content-Type": "application/json"} if data else {})) err = None for i in range(retries): try: req = urllib.request.Request(url, data=data, headers=hdrs) with urllib.request.urlopen(req, timeout=timeout) as r: return json.loads(r.read().decode()), None except urllib.error.HTTPError as e: err = f"HTTP {e.code}" if e.code in (429, 500, 502, 503, 504): time.sleep(1.5 * (i + 1)); continue return None, err except Exception as e: err = type(e).__name__ + ": " + str(e)[:80] time.sleep(1) return None, err Five calls per mint:
rc, errors["rugcheck"] = fetch(f"https://api.rugcheck.xyz/v1/tokens/{mint}/report") ds, errors["dexscreener"] = fetch(f"https://api.dexscreener.com/tokens/v1/solana/{mint}") jp, errors["jupiter_price"] = fetch(f"https://lite-api.jup.ag/price/v3?ids={mint}") js, errors["jupiter_search"] = fetch(f"https://lite-api.jup.ag/tokens/v2/search?query={mint}") rpc, errors["rpc"] = fetch(RPC, { "jsonrpc": "2.0", "id": 1, "method": "getAccountInfo", "params": [mint, {"encoding": "jsonParsed"}], }) Pick the DexScreener pair with the most USD liquidity so you don't report a dust pool.
The holder trap: exclude the curve and the pools
If you sum "top holders" raw on a pump.fun token, the bonding curve often shows up as ~90% and looks like a whale. It isn't. Same for AMM/LP accounts and lockers.
known = rc.get("knownAccounts") or {} excl = {a for a, v in known.items() if v.get("type") in ("AMM", "LOCKER")} for m in rc.get("markets") or []: for k in ("pubkey", "liquidityAAccount", "liquidityBAccount"): v = m.get(k) if isinstance(v, str): excl.add(v) elif isinstance(v, dict): excl.update(x for x in (v.get("pubkey"), v.get("owner")) if isinstance(x, str)) holders = rc.get("topHolders") or [] real = [h for h in holders if h.get("owner") not in excl and h.get("address") not in excl] top10 = sum(h.get("pct") or 0 for h in real[:10]) if holders else None That top10 number is what the flags use.
Authorities from RPC first
RugCheck usually has mint/freeze fields, but the mint account on chain is the source of truth:
info = (((rpc or {}).get("result") or {}).get("value") or {}).get("data", {}) info = info.get("parsed", {}).get("info", {}) if isinstance(info, dict) else {} def auth(key): if info: return info.get(key) return rc.get(key) if rc else "unknown" mint_auth, freeze_auth = auth("mintAuthority"), auth("freezeAuthority") None means revoked. Any pubkey means the authority is still active (dev can mint more, or freeze wallets).
Flag thresholds
| Check | Green | Yellow | Red |
|---|---|---|---|
| Mint / freeze authority | revoked | – | active |
| Top-10 ex pools | ≤15% | 15–30% | >30% |
| Dev holdings | ≤3% | 3–10% | >10% |
| LP locked | ≥90% | 50–90% | <50% |
| RugCheck risk level | – | warn | danger |
| Graph / top-holder insiders | – | – | any |
Extra yellows: still on the pump.fun curve, liquidity under $10k after migration, buy/sell ratio > 8 (possible bots/wash), age under 1 hour, serial launcher (dev with >3 other tokens).
red, yellow, green = [], [], [] (red if mint_auth else green).append( "mint authority " + ("ACTIVE (dev can print tokens)" if mint_auth else "revoked") ) (red if freeze_auth else green).append( "freeze authority " + ("ACTIVE (dev can freeze wallets)" if freeze_auth else "revoked") ) if top10 is not None: (red if top10 > 30 else yellow if top10 > 15 else green).append( f"top-10 holders (ex pools/curve) {top10:.1f}%" ) # ... LP lock, dev %, curve, age, RugCheck risks, insiders ... verdict = ("RED - high risk" if red else "YELLOW - caution" if yellow else "GREEN - basics look clean (still risky!)") What it does NOT check
There is no reliable free public API for bundle/sniper detection. The script prints manual links instead:
https://trench.bot/bundles/<MINT> https://app.bubblemaps.io/sol/token/<MINT> Also watch socials and whether the site/X account was copied from another project. That stays human work.
Real run (2026-11-05 ~20:11 Europe/Moscow)
I ran the same logic over 28 tokens from DexScreener's Solana boosts/profiles feeds. Snapshot counts that hour: 19 RED / 5 YELLOW / 4 GREEN. Numbers go stale in minutes; this is a freeze-frame, not a ranking.
Example A: $Democat (The Democrat Cat), mint 9Y1F6dZ6HpjZDYZdYuUGwMbkUiPsyU7WPTqTQU4Tpump:
age 19.3 h | mcap ~$417k | liq ~$54k | holders 5896 mint/freeze revoked | top-10 ex pools 5.6% | LP locked 100% dev holds 0% | RugCheck score 1 | graph insiders 0 summary: GREEN - basics look clean (still risky!) Example B: $Raul (Raul Bautista), mint C1dNqHWwrLC6Hmtbr75BL3FmH4UCN3ztam7VDtwhpump:
age 45.6 h | mcap ~$35k | liq ~$15k | holders 327 mint/freeze revoked | top-10 ex pools 38.0% | LP locked 100% dev holds 0% | RugCheck graph insiders 6 [RED] top-10 holders (ex pools/curve) 38.0% [RED] RugCheck detected 6 insider wallets via graph analysis summary: RED - high risk Same green authorities and LP lock in both. The difference is concentration and insider graph. That is why the top-10-ex-pools step matters.
Run it yourself
- Copy
solcheck.pyfrom the Telegraph script page. -
python3 solcheck.py <MINT>(Python 3, no pip installs). - Open the trench.bot and Bubblemaps links it prints.
- Re-run before you trade; data ages fast.
If you want machine-readable output for a sheet or a small dataset, add --json.
Disclaimer
Education only. Not financial advice. Memecoins can go to zero. Flags are heuristics. Confirm on-chain yourself.
Disclosure: if you trade on Axiom, signing up via my referral link gets you their documented 10% fee discount (and I get a share of fees): https://axiom.trade/@anteikq

