signed issuer-power checks for B20 tokens on Base b20check.com
00

verify console

x402 v2

Some B20 tokens keep issuer backdoors. There's no source to read.

Mint, freeze, seize, pause: B20 Check reads these rights straight from the chain and returns a signed verdict per token. $0.01 a call, EIP-712 signature, so you can recover the signer and verify the answer instead of trusting the API.

Started as an internal check for my own agents, now it's just open.

Try the API no API keys, no subscription
live demo same handler as the paid endpoint, free route, 20 req/min per IP /v1/demo
# paid route, the x402 exchange
> GET /v1/verify/{address}
< HTTP/1.1 402 Payment Required
  PAYMENT-REQUIRED: eyJ4NDAyVmVyc2lvbiI6Miw…
  decoded: {
    scheme   "exact"
    network  "eip155:8453"
    price    "$0.01 USDC"
    payTo    0x26B57af5022250F01497F3e19dd537d01d124BA1
    asset    0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
  }
> GET again, X-PAYMENT: USDC payment signature
< HTTP/1.1 200, signed verdict

# this console calls the free demo route
> GET /v1/demo/{address}
< awaiting run

example response · run a check to replace it

B20 Check verdictcaution
address0xb2000000000000000000001fd821494127f35af0
isB20true
dataSourceindexed
adminActivetrue
flags
  • ADMIN_ACTIVE issuer admin role is active
  • VIA_LAUNCHER deployed through a launcher
attestation · signed=true · signer 0x1388d1e3751512955A53C7c2795Eaf8a3B029e6A · pinned to a Base block, ~10 min TTL
free demo route, 20 requests/min per IP · the paid route runs the same check without the rate limit
01

The live index

source /v1/stats · cached 10 min
B20 tokens indexed 11,498
snapshot block #48,659,045
past the snapshot rebuilt nightly · newer tokens resolve live

A token minted a minute ago still gets a verdict: anything newer than the snapshot is scanned live at request time. A check that cannot complete returns not_indexed, never a silent ok.

how to verify

Snapshot block and token count are returned by the free stats route:

curl · b20check stats
curl -s https://b20check.com/v1/stats
02

One request, one payment, one signed verdict

x402 exact scheme · eip155:8453

The x402 flow in four steps. No account setup on either side.

01 agent server Agent requests GET /v1/verify/0x…
02 server agent Server replies 402 price + payTo in the PAYMENT-REQUIRED header
03 agent chain Pay USDC on Base USDC via the x402 exact scheme
04 server agent Signed verdict EIP-712 attestation, pinned to a Base block
03

What the verdict covers

15 flags · 4 groups

B20 tokens are protocol-native on Base: no deployed source on an explorer, and the issuer can keep live control after launch. That leaves four groups of facts worth checking before any value moves.

6 flags

Issuer powers

Whether the issuer can mint, freeze, seize or pause, whether admin rights are active, supply cap status and transfer restrictions. Reported as structured booleans, not prose.

ADMIN_ACTIVE CAN_PAUSE CAN_SEIZE FREEZE_ACTIVE TRANSFER_RESTRICTED UNCAPPED_MINT
5 flags

Identity

Imposter and lookalike detection on names and symbols, plus recognition of canonical assets such as native USDC.

CANONICAL_ASSET COPYCAT_NON_NATIVE NAME_IMPOSTER SYMBOL_LOOKALIKE SYMBOL_UNREADABLE
3 flags

Activity

Observed on-chain issuer actions: mints, burns, freezes, seizures, pauses, role changes, and the block of the last action. What actually happened, not what could.

FRESH_CREATOR VIA_LAUNCHER ZERO_ACTIVITY
1 flag

Data freshness

Every response states its data source: indexed, live, or not_indexed. A token that cannot be fully checked is never signed as ok. Missing data fails closed, never false-clean.

NOT_INDEXED
04

Verify the signature, not this page

EIP-712 · ~10 min TTL

Every verdict ships an EIP-712 attestation pinned to a Base block, with a roughly 10-minute TTL and a deterministic content id. To trust it, recompute the hash from the payload and recover the signer; the booleans in the response are just a convenience.

signer 0x1388d1e3751512955A53C7c2795Eaf8a3B029e6A
EIP-712 domain name "B20 Check Attestation", version "1", chainId 8453
pinning attestation.pinnedBlock, expiresAt about 10 minutes out
recover the signer, three steps
// 1. fetch the attestation from any verify response (paid or free demo)
// 2. recompute payloadHash from the canonical payload (UTF-8, no unicode escaping)
// 3. rebuild the EIP-712 message, recoverTypedDataAddress, compare to 0x1388d1e3751512955A53C7c2795Eaf8a3B029e6A
// 4. check now < expiresAt (a valid signature over an expired verdict is stale)

The full EIP-712 types, domain, and canonical-payload recipe are published at /v1/schema (field x-attestationVerification), so you can recompute the hash without this repo.

05

Call it from code

discovery · CDP x402 Bazaar

No signup, no keys, no subscription. Discover the price straight from the endpoint:

curl · price discovery
curl -i https://b20check.com/v1/verify/0xb2000000000000000000001fd821494127f35af0
# returns 402 with a base64 PAYMENT-REQUIRED header carrying price, payTo, asset

Or let an x402 client pay automatically:

node · @x402/fetch
import { privateKeyToAccount } from "viem/accounts";
import { wrapFetchWithPayment, x402Client } from "@x402/fetch";
import { ExactEvmScheme } from "@x402/evm";

const account = privateKeyToAccount(process.env.AGENT_KEY);
const client = new x402Client().register("eip155:8453", new ExactEvmScheme(account));
const fetchPaid = wrapFetchWithPayment(fetch, client);

const res = await fetchPaid("https://b20check.com/v1/verify/" + token); // auto-pays on the 402
const check = await res.json();
schemaGET /v1/schema, the full JSON response schema
payTo0x26B57af5022250F01497F3e19dd537d01d124BA1
assetUSDC 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
discoveryit is in the CDP x402 Bazaar too, so agents can find it on their own
06

Or add it to your assistant

MCP · Claude / ChatGPT

No code needed: the check speaks the Model Context Protocol. Add it once as a connector, then ask in plain language whether a B20 token is safe. The assistant runs the check and reads you the verdict.

Paste this connector URL into Claude, under Settings then Connectors, or add it in ChatGPT as a custom MCP connector:

remote MCP · free, 20 checks/min
https://b20check.com/mcp

Prefer a local server? The same tools ship as an npm package. For Claude Desktop and other clients that launch MCP servers themselves, add this to the config:

local MCP · npx, same free tier
{ "mcpServers": { "b20check": { "command": "npx", "args": ["-y", "b20check-mcp"] } } }
ask"is 0xb20... a safe B20 token?" and the assistant runs verify_b20_token for you
freethe connector uses the rate-limited demo route, no wallet, no keys
unmeteredthe paid /v1/verify endpoint (x402) has no rate limit
registrieslisted in the official MCP Registry as com.b20check/b20check and on Smithery