Behavioral token testing, in the open. Pick a blockchain and a token — or paste any contract address — and BlockProof runs the industry's behavioral test against it on a fork of that chain: a fresh wallet buys the token through a live V3 router, transfers it between two fresh wallets, and sells it back. Every result is published with its complete evidence, so anyone — holders, builders, researchers, listing teams — can verify a token's observed behavior for themselves instead of trusting a black-box verdict. No account, no key, no charge.
Token scanners — Blockaid, GoPlus, honeypot.is, Token Sniffer and the rest — run roughly the same tests BlockProof runs. The difference is what you are given afterwards. They hand you a conclusion: a flag, a score, a “honeypot: yes/no” — with no way to see how it was reached, no evidence to check, and no recourse when it is wrong. BlockProof hands you the experiment: every transaction, every revert reason, every execution trace, at a stated block, reproducible by anyone. Concretely:
| Typical commercial scanner | BlockProof | |
|---|---|---|
| What you receive | A flag / score | Outcomes + complete evidence |
| How it was produced | Undisclosed | Fully transparent and replayable |
| Reproducible by you | No | Yes — any public RPC endpoint |
| Revert attribution (token vs. infrastructure) | None | Control swap, every time |
| Wallet-to-wallet transfer test | No | Yes |
| Editorial labels (“honeypot”, “malicious”) | Yes | Never — facts only |
| Historical record | Overwritten | Append-only, public, forever |
| Cost / API key | Varies | Free, open CORS, no key |
Follow value out of a wallet, hop by hop — the view you need when funds have been stolen. Give it the wallet, the chain, and the date to trace from; BlockProof walks the outgoing transfers (the native coin, or one specific token) through the recipients, examining each address it meets: plain wallet, contract, or a well-known service. Where on-chain continuity genuinely breaks — a DEX swap, a bridge, a mixer, an exchange deposit — the trace says so at that node rather than pretending to follow through. Every hop carries its transaction hashes, so the whole tree is verifiable on the explorer.
Two sections. Observed by BlockProof: because the crawler re-tests the busiest tokens on every chain continuously, BlockProof notices when a token's behavior changes — a token that sold cleanly last week whose sells now revert, a pause capability appearing after an upgrade, an LP lock falling away, a third-party flag flipping. Each entry is a dated, factual statement of what changed, linked to the immutable before-and-after scan records that prove it. Industry incidents: recent major exploits and hacks across the ecosystem.
Everything on this page comes from a free, unauthenticated, GET-only JSON API with open CORS (Access-Control-Allow-Origin: *), so you can call it from a browser, a bot, a listing pipeline, or curl. Base URL: https://blockproof.lemnicoin.com/v2
| Call | Returns |
|---|---|
| GET /v2/chains | Supported chains: [{chain_id, name, slug, token_count}] |
| GET /v2/chains/<chainId>/tokens | Known tokens on that chain (for dropdowns): address, symbol, name, last scan time and status. |
| GET /v2/scan/<chainId>/<address> | THE main call. A cached result returns immediately; otherwise the scan is queued and you poll the same URL. Add ?refresh=1 to force a re-scan (subject to a per-token cooldown). |
| GET /v2/history/<chainId>/<address> | The token's append-only scan history: [{id, scanned_at, status}]. |
| GET /v2/scan-record/<id> | One immutable historical scan, in full (evidence included). |
| GET /v2/trace/<chainId>/<wallet>?from=YYYY-MM-DD[&token=0x…][&depth=1-6] | Fund tracing: walks outgoing transfers of the native coin (or token) from the wallet, starting at from, up to depth hops (default 3, max 6, top 5 recipients per hop; a leaf that hits the hop limit carries everything needed to continue the trace from that address). Returns 202 {status:"running"} while it works — poll the same URL; then {status:"complete", result} where result.nodes maps each address to its label/kind, arrival time, children (amount, first_transfer_at, tx_hashes), any continuity_break (swap/bridge/mixer/exchange/burn, with the reason), or funds_at_rest. Example: curl "…/v2/trace/137/0xWALLET?from=2026-04-01". Cached 24 h; EVM chains only. |
| GET /v2/incidents?limit=50 | The incident feed: observed — behavior changes BlockProof detected between its own scans of the same token (kind, dated summary, and evidence.before/after links to the two immutable scan records); industry — recent major incidents across the ecosystem. |
| GET /v2/address/<chainId>/<address> | Address screening — the check to run BEFORE sending funds to an address or approving it: facts.sanctioned_ofac (OFAC SDN list, refreshed daily — true is a hard stop), is_contract, tx_count, first_seen / age_days (a very young wallet asking for funds is the classic drainer pattern). Facts with sources, no reputation scores. Cached 1 h. |
| GET /v2/health | Liveness and current queue depth. |
# Scan LEMNI on Polygon (chain id 137): curl -s "https://blockproof.lemnicoin.com/v2/scan/137/0x02011c7B7D9C6dfc563c92197557e8BE490a85b4"
// Browser / Node — poll until complete:
async function blockproof(chainId, address) {
const url = `https://blockproof.lemnicoin.com/v2/scan/${chainId}/${address}`;
for (;;) {
const r = await (await fetch(url)).json();
if (r.status === "complete") return r.result; // done (fresh or cached)
if (r.status === "queued" || r.status === "running") // live scan in progress:
await new Promise(s => setTimeout(s, 5000)); // wait 5 s and poll again
else throw new Error(JSON.stringify(r)); // error_cached / rate limited
}
}
The envelope's status field is the state machine: complete (result attached; cached: true with age_hours when served from cache) · queued / running (poll the same URL every ~5 s; a previous result, if any, rides along as stale) · error_cached (the last attempt failed; retry_after_hours says when a retry unlocks). HTTP 429 with error: scan_rate_limited or queue_full means you've hit the per-IP scan budget or the global queue cap — cached reads are never limited that way. Inside result, the fields that matter:
{
"schema": "blockproof/1",
"chain_id": 137, "chain": "Polygon",
"address": "0x…", "scanned_at": "…", "fork_block": 67012345,
"token": { "name": "…", "symbol": "…", "decimals": "18", "totalSupply": "…" },
"behavioral": {
"venue": { "venue_name": "Uniswap V3", "pool": "0x…",
"counter_symbol": "USDC", "fee_tier": 3000 },
"outcomes": { // ← read these first
"dex_buy": "succeeded | reverted | not_run",
"transfer_between_fresh_wallets": "succeeded | reverted | not_run",
"sell": "succeeded | reverted | not_run",
"sell_fraction": "100% | 50% | 10% | null",
"round_trip_cost_pct": 2.58, // pool fees + price impact, full round trip
"venue_control": "not_needed | succeeded | failed",
"attribution_note": "…" // present whenever a trade reverted
},
"steps": [ { // the evidence, step by step
"name": "sell_100pct", "ok": false, "txHash": "0x…",
"revert": { "kind": "Error(string)", "reason": "…",
"vm_error": "…", "call_path": [ "CALL 0x…" ] },
"trace": { } // full callTracer execution trace
} ]
},
"characteristics": { // code shape, not behavior
"method": "diamond_loupe | bytecode_scan",
"is_diamond": true, "eip1967_proxy": false,
"characteristics": [ { "signature": "pause()", "category": "trading-control",
"naive_scanner_reading": "transfers can be halted" } ]
},
"metrics": { // the usual market/holder numbers
"market": { "price_usd": "…", "liquidity_usd": 0, "volume_24h": 0, "fdv": 0 },
"holders": { "holder_count": 0, "top10_pct": "…", "largest_holder_pct": "…",
"top_holders": [ { "address": "0x…", "percent": "…", "locked": true, "tag": "…" } ] },
"lp": { "locked_percent": "…", "lp_holders": [ ] }, // V2-style LP tokens (V3 = NFT positions)
"pool_share_of_supply_pct": "…"
},
"third_party": { "goplus": { "status": "ok",
"summary": { "is_honeypot": "0", "buy_tax": "0", "sell_tax": "0", "…": "…" } } },
"disclaimer": "…"
}
Interpretation guide: if outcomes.sell = "succeeded", a fresh wallet demonstrably sold on the live venue at the fork block — the behavioral test the industry's scanners run, passed, with the receipts attached. If it is "reverted", check venue_control first: "failed" means the venue itself was unhealthy and the result says nothing about the token; "succeeded" means the revert is attributable to the token's own code — and the step's revert.reason and trace show exactly which check raised it. The characteristics block is code shape only (what pattern-matchers key on), never proof of behavior — the behavioral block is the behavior.