How To Check If a Token Is Safe With Evidence
DYOR isn’t a vibe; it’s a workflow. This guide gives you a repeatable, evidence-based checklist to judge token safety using on-chain data, contract source, ownership controls, liquidity locks, holder distribution, trading constraints, and provenance. Every step links to external tools so you can back up your conclusion with screenshots and hashes.
The 7-Point Evidence Framework
1) Contract verified & identical
2) Admin powers controlled
- No arbitrary
mint()or unlimitedsetTax() - Owner role in a multisig or timelock
- Blacklist/pause functions removed or controlled with timelock
3) Liquidity is sticky
- LP tokens burned or locked for a meaningful period
- No dev-held LP outsized share
- Pair contracts known and liquid across venues
4) Holder distribution sane
- No top wallet controlling > 20–30% (excluding contracts)
- Team/treasury addresses disclosed and bound by vesting
- No sudden top-holder inflows pre-announcement
5) Trading works normally
- Buy/sell simulate OK (no honeypot toggles)
- Taxes if any are reasonable (< 10% typical)
- No hidden maxTx/maxWallet traps at live supply
6) Clean provenance
- Deployer history free of rugs
- If proxy, implementation audited & immutable upgrades (timelock)
- Known templates (OpenZeppelin) with minimal edits
7) Transparent comms
- Signed deploy posts (GPG/PGP, EIP-4361 “Sign-In”)
- Audit reports (with findings & fixes)
- Timelock & governance addresses public
Safety Flowchart (When to Stop)
Step 1 — Contract Source & Bytecode Match
Start on the official explorer for the chain: Etherscan (ETH), BaseScan (Base), Arbiscan (Arbitrum), BscScan (BSC), etc. Paste the token address.
- Look for “Contract: Verified” and a green check. Click “Contract” tab → “Code.” Confirm:
- Compiler version (e.g.,
v0.8.24+commit) & equals what the deployer claims - Optimizer settings (enabled, runs count)
- License (MIT/Apache-2.0); non-license ≠ scam, but standard licenses are a plus
- Compiler version (e.g.,
- Bytecode match: Explorers display “Matches deployed bytecode at …”. If partial or “similar,” be cautious.
- Diff from OpenZeppelin: If it’s an ERC-20, compare functions to OpenZeppelin ERC-20. Non-standard additions like
setTax(),enableTrading(),excludeFromFee(),setMaxTx()warrant careful review. - Proxy? If the contract says “Proxy,” check “Read as Proxy” → implementation address. Audit that implementation too.
Yellow flag: Unverified source means you can’t see what functions exist. Many rugs hide mint/blacklist logic behind unverified contracts.
Step 2 — Admin Powers (Mint, Pause, Blacklist, Taxes)
Rug mechanics frequently rely on hidden or overpowered admin functions. In the Contract “Read/Write” tabs, and in the verified code, search for:
Dangerous patterns
mint(address,uint256)without caps or roles → infinite dilutionblacklist(address,bool)orsetTradingEnabled(bool)→ can block sellssetTax(uint256)with no sane bounds → 99% tax honeypotsetMaxTxAmount()orsetMaxWallet()that can be lowered post-launch → traps- Upgradeable proxy with
upgradeTo()fully under dev EOA → can swap logic
Safer controls
- Roles via
Ownable/AccessControlbut owner is a multisig (Safe) - Timelock on critical functions (e.g., 24–48h) (OZ Timelock)
- Bounded taxes (e.g.,
require(_tax <= 10_00)for ≤10%) - Renounced ownership (trade-off: no upgrades) or governance process documented
Evidence to save: Screenshots of the functions, the owner address (and that it’s a multisig/timelock), and any require bounds on tax/limits.
Step 3 — Liquidity: Lock, Burn, or Rugable?
If the team can remove liquidity, price can nuke to zero. Check the main DEX pairs (Uniswap v2/v3, Base/Arbitrum variants) on Dexscreener or DexTools, then click the LP token:
- Is LP burned? Look for LP tokens sent to
0xdeador0x0000...dead. - Is LP locked? If locked, find the locker (e.g., Unicrypt, Team.Finance). Record lock duration and % locked.
- Residual LP risk: Even with locks, verify that a meaningful % (e.g., >60–80% on early launches) is locked for months, not days.
Step 4 — Holder Distribution & Smart Money
In the explorer “Holders” tab, export the distribution. Exclude known contracts (LP, router, CEX wallets) and re-weight human wallets:
- Top holder threshold: A single externally owned account (EOA) > 20–30% is risky unless explained (vesting/treasury).
- Team wallets: If disclosed, they should be time-locked or vesting. Verify the timelock address.
- Smart money: Look for reputable funds/wallets with long holding periods. Tools: Dune, Nansen (paid), DeBank.
Evidence: CSV of holders (annotate contracts vs EOAs), and a note on any whale concentration.
Step 5 — Buy/Sell Simulation & Honeypot Tests
Before you risk capital, simulate a buy and a sell. Use multiple tools:
- Dexscreener / DexTools price impact & router paths
- TokenSniffer & GoPlus Token Security (automated checks)
- Explorer “Write” tab to read current tax/maxTx if exposed
What to confirm
- A small buy and a small sell both succeed (no revert)
- Taxes (if any) are within stated bounds
- Router isn’t a malicious custom router (prefer Uniswap v2/v3, Sushi, etc.)
- No dynamic blacklists that flip after buys
Red flags
- Buys succeed, sells revert (honeypot)
- 99% “fee” on sell
- MaxTx/MaxWallet changed right after you buy
- Trading paused by owner post-launch
Note: Some automated scanners produce false positives or miss proxy upgrades. Always corroborate with the contract code and a live micro-trade.
Step 6 — Deployer & Provenance (Clones, Upgrades) h2>
Click the token’s “Contract Creator” link. Review the deployer’s other contracts and activity:
- Prior rugs? If the same deployer rugged before (liquidity pulled, mint abuse), weight heavily against.
- Clone templates: Many tokens clone standard templates. Diff vs a known-good commit (OpenZeppelin). Minimal diffs are safer.
- Proxy upgrades history: If upgradable, check change logs and who can upgrade (timelock? multisig?).
Evidence: Deployer address notes, list of previous contracts, and any news/audit links.
Step 7 — Communications & Commitments
Legit teams tend to leave verifiable breadcrumbs:
- Signed deploy announcements (e.g., EIP-4361 “Sign-In with Ethereum”)
- Public multisig/timelock addresses with instructions
- Audits from reputable firms (CertiK, Trail of Bits, OpenZeppelin, SlowMist)
- Clear disclosures on tokenomics/vesting with on-chain vesting contracts
Your Toolkit
Explorers
- Etherscan / BaseScan / Arbiscan
- Holder tabs, Contract tabs, Proxy/Implementation
- Revoke.cash to check allowances
Scanners & Risk
- TokenSniffer
- GoPlus Token Security
- Forta (real-time bot alerts)
Market Intel
Audits & Threat Intel
Dev References
L2 Explorers
CLI Recipes (Automate Key Checks)
ethers.js — Read owner, totalSupply, and try to detect dangerous functions
import { ethers } from "ethers";
// Set your RPC (Infura, Alchemy, Ankr, QuickNode, etc.)
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
// Minimal ABI: ERC-20 + common risky functions
const ABI = [
"function name() view returns (string)",
"function symbol() view returns (string)",
"function totalSupply() view returns (uint256)",
"function decimals() view returns (uint8)",
"function owner() view returns (address)",
"function getOwner() view returns (address)",
// suspected risky
"function mint(address,uint256)",
"function setTax(uint256)",
"function setMaxTxAmount(uint256)",
"function blacklist(address,bool)",
"function pause()",
"function unpause()"
];
const token = new ethers.Contract(process.env.TOKEN, ABI, provider);
(async () => {
const [name, symbol, supply] = await Promise.all([
token.name().catch(() => "n/a"),
token.symbol().catch(() => "n/a"),
token.totalSupply().catch(() => 0n)
]);
// Try different owner functions
let owner = "n/a";
try { owner = await token.owner(); }
catch { try { owner = await token.getOwner(); } catch {} }
console.log({ name, symbol, totalSupply: supply.toString(), owner });
// probe risky functions by checking if they exist (will fail if not)
const probe = async (sig) => {
try { await token[sig](); return true; } catch { return false; }
};
const risky = {
mintExists: await probe("mint"),
setTaxExists: await probe("setTax"),
setMaxTxExists: await probe("setMaxTxAmount"),
blacklistExists: await probe("blacklist"),
pauseExists: await probe("pause")
};
console.log({ risky });
})();
viem — Check proxy implementation & owner (EIP-1967)
import { createPublicClient, http, getStorageAt, isAddress } from "viem";
import { mainnet } from "viem/chains";
// EIP-1967 implementation slot = bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
const IMPLEMENTATION_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc";
const client = createPublicClient({ chain: mainnet, transport: http(process.env.RPC_URL) });
const toChecksum = (hex) => "0x" + hex.slice(-40);
const main = async () => {
if (!isAddress(process.env.TOKEN)) throw new Error("Bad address");
const slot = await getStorageAt(client, { address: process.env.TOKEN, slot: IMPLEMENTATION_SLOT });
if (slot && slot !== "0x0") {
const impl = toChecksum(slot);
console.log({ proxy: true, implementation: impl });
} else {
console.log({ proxy: false });
}
};
main();
Foundry — Simulate a small swap (sell) to catch honeypot
# Pseudocode pattern; actual script depends on router ABI/paths
# Use a forked RPC (anvil --fork-url $RPC) and cast/anvil to simulate a real swap.
# If the sell path reverts, investigate tax/maxTx/blacklist toggles.
# Example idea:
# 1) Approve router for token
# 2) SwapExactTokensForETHSupportingFeeOnTransferTokens
# 3) Observe if revert happens or output is ~expected with stated tax
CLI automation won’t catch everything (e.g., upgradeable behind timelocks), but it accelerates your first-pass scan.
Risk Scoring Rubric (Printable)
| Category | Green (+2) | Yellow (+1) | Red (0) |
|---|---|---|---|
| Source/Bytecode | Verified, exact match, OZ-based | Verified but heavy custom logic | Unverified/partial |
| Admin Powers | Multisig + timelock; bounded taxes; no blacklist | Owner EOA but timelock or bounds | Unlimited mint/tax/blacklist; upgradeable by EOA |
| Liquidity | LP burned/locked ≥ 60% for months | LP partly locked | LP held by dev/fresh EOA |
| Holders | No non-contract whale > 20% | Largest whale 20–30% | > 30% whale or sudden concentration |
| Trading | Buys/sells normal; tax ≤ 10% | Tax 10–15% or tight maxTx | Honeypot/99% tax/reverts |
| Provenance | Clean deployer; audited; known template | Unknown deployer; minor history | Prior rugs; opaque history |
| Comms | Signed posts, audit PDFs, addresses | Some docs but unsigned | Badges only; no verifiable docs |
Interpretation: 11–14 = Lower risk (still crypto); 7–10 = Caution; ≤6 = Avoid.
FAQ: Common Myths & Edge Cases
“Renounced ownership = safe.”
Not always. If code already has malicious logic (e.g., anti-sell), renouncing won’t remove it. Safer when paired with simple, immutable code.
“Audited = safe.”
Audits reduce risk but don’t eliminate it. Validate the audited commit matches the deployed bytecode and that critical HIGH issues were fixed.
“Big liquidity = safe.”
Only if LP is locked or burned. Big but dev-controlled LP can still be pulled.
“TokenSniffer score is low instant scam?”
Automated scores are a screen, not a verdict. Use them to prioritize deeper manual checks.
“Taxes make it a scam.”
Many tokens levy small buy/sell taxes for treasury or LP. The issue is unbounded or secretly changeable taxes post-launch.
External Links & References
Explorers & Tools
- Etherscan • BaseScan • Arbiscan
- Revoke.cash — allowances
- Dexscreener • DexTools
- TokenSniffer • GoPlus Token Security
Audits, Threat Intel & Learning
Recap
- Don’t ask “Is it safe?” ask “What evidence says it’s not dangerous?”
- Verify source & bytecode, control admin powers, secure liquidity, check holders, simulate trades, review provenance, and demand verifiable comms.
- Two or more critical fails → walk away. Screenshots + hashes = your audit trail.
Want us to run this checklist on a specific token and deliver an evidence pack (PDF + links + hashes)?
Request a Token Safety Report →