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
Top comments (0)