Chain Check

How it works

Six calls, and a list of the things we will not pretend to know.

Chain Check reads public state on Base. There is no indexer behind it, no scraped feed, and no model anywhere near the verdict. What follows is every call it makes, and the measurement behind every refusal.

  1. 01

    Read the code at the address

    One eth_getCode, read three ways. Empty means a plain wallet. A 0xef0100 prefix means an EIP-7702 wallet that executes another contract's code — a real Base wallet returned exactly that during the build, and the classic 'code is not empty, so it is a contract' test mislabels it. Anything else is contract code.

  2. 02

    Screen the sanctions list

    OFAC SDN membership, fetched fresh and validated for size and shape before it is allowed to answer anything. The on-chain sanctions oracle everyone reaches for is not deployed on Base — eth_getCode on it returns empty, and a call to a codeless address returns empty too, which ABI-decodes to false. That integration would report every address as clean, forever, with no error.

  3. 03

    Read the contract, if there is one

    Published source from Sourcify v2, then a sweep of 5 standard proxy slots plus both admin pointers. A sweep, not one slot: probing EIP-1967 alone reports USDC as non-upgradeable, and USDC is a proxy — its implementation pointer lives in the older ZeppelinOS slot.

  4. 04

    Ask which powers exist

    11 role getters plus AccessControl member counts. A getter that answers with a live account is proof that role exists. An empty answer proves nothing at all, so it is never reported as absence — this is the one signal that can never come back clean.

  5. 05

    Actually do the transfer

    For a token, we simulate a real transfer with an eth_call state override — funding a probe contract, sending to a second address, and measuring what arrives. Verified in both directions before shipping: USDC delivered in full, and a synthetic token built to keep ten per cent measured at exactly ten per cent.

  6. 06

    Fold it into a band, and say what is missing

    A pure function turns the signals into a band. Every signal carries its weight, its value and its evidence, so you can recompute the number. Everything we could not observe is returned beside it, with the reason.

The signals

Every one, with the call behind it.

SignalApplies toWeightHow it is read
Sanctions listany address34Membership of the OFAC SDN digital-currency address list, fetched fresh and validated for length and shape before it is allowed to answer.OFAC publishes no BASE tag, so a Base address is screened against the ETH-tagged entries. Correct practice, and an inference.
Account typeany address16eth_getCode, read three ways: empty is a plain wallet, an 0xef0100 prefix is an EIP-7702 wallet that delegates to another contract, anything else is contract code.
Verified sourcecontract22Sourcify v2 for chain 8453.Verified means the published source compiles to the deployed bytecode. It is not an audit and says nothing about whether the code is safe.
Upgradeabilitycontract14eth_getStorageAt across 5 standard proxy slots (EIP-1967, EIP-1822, ZeppelinOS, beacon, Safe singleton) plus both admin slots.Nothing found means nothing in the STANDARD places. A bespoke proxy keeping its pointer elsewhere would not appear.
Token metadatatoken8name(), symbol(), decimals() and totalSupply() read directly with eth_call.
Privileged rolestoken16Role getters (owner, pauser, blacklister, master minter, minter, rescuer, governance, timelock) plus AccessControl member counts. A getter that answers with a live account is proof that role exists.PRESENCE ONLY. This signal can never come back clean: an empty return means 'no such function' on one contract, 'a fallback swallowed it' on another, and 'no code here' on a third. We will tell you a token HAS a pauser. We will never tell you it has none.
Fee on transfertoken14A real transfer, simulated with an eth_call state override, measuring what the recipient actually receives. Verified against a synthetic 10% fee token as well as against a clean one.Measures the plain wallet-to-wallet path at this moment. A token that taxes only sells, only pair routes, or only above a threshold would still come back clean.

What we cannot check

Every one of these was measured, not assumed.

A product that quietly omits what it could not do is indistinguishable from one that checked and found nothing. These are returned in the response body of every single call.

CHECKEDsanctionsaccount typeverified sourceupgradeableroles presenttransfer feeNOT CHECKEDaddress agetransaction countholder concentrationliquiditythe explorer API refuses free accesson Base — and does it with an HTTP 200so we return nothing rather than a guess

Address age and first activity

Needs an indexed transaction history. Etherscan/Basescan V2 refuses free access on Base and does it SILENTLY — HTTP 200 with a body reading {"status":"0","message":"NOTOK"}, so a client checking res.ok reads the refusal as data. We hold no paid explorer key. Rather than estimate it, we do not have it.

Transaction count and history

Same paywall, same silent failure. Absent rather than approximated.

Holder concentration

Needs the full holder set, which is an explorer or an indexer. There is no keyless route to it, so no top-holder percentage is reported.

Liquidity and market depth

Reading pool depth honestly means indexing every venue on the chain. No keyless source, so no number.

Scam reports and reputation feeds

No free, machine-readable scam-report feed is usable here. There is no reputation signal beyond OFAC membership, and inventing one would be worse than having none.

Proof that a token has NO privileged roles

Structurally impossible with the reads available. See the privileges signal: an empty eth_call return is produced by three different situations, one of which is a mistyped address.

Whether the code has been audited

Not on-chain. Verified source is not an audit and is never presented as one.

A honeypot verdict

We simulate a transfer and report what it delivered. We do not simulate a buy-then-sell across a liquidity venue, so we do not issue a honeypot verdict — the fee-on-transfer signal is the honest subset of that question.

WEIGHTS3416221481614roles = insufficient → its 16 leaves the denominator, it is NOT a zeroscore = 100 × Σ(value × weight) ÷ Σ(weight over resolved) = 100 × 103.4 ÷ 108 = 96 → clear (6 of 7 signals resolved)

Scoring

Arithmetic, not judgement.

Score equals 100 times the sum of value times weight, divided by the sum of weights, over resolved signals only. Any hard failure — today, an OFAC hit — forces the high band outright, because a sanctions match is not something a good showing elsewhere should be allowed to average away.

A signal we could not observe leaves the denominator. It is never a zero. That is why the response always tells you how many signals resolved and how much of the weight they carried — a band is always a band of the signals that resolved.

What this is not.

A diligence signal. Not a verdict on a counterparty, not a security audit, and never financial advice. A clear band means every signal that resolved looked ordinary — read what did not resolve before you treat it as an all-clear, and remember that verified source means the published code matches the deployed bytecode, not that the code is safe.

5 credits an address, 8 a token contract. A check the chain would not answer refunds in full.