How it works
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.
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.
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.
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.
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.
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.
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
| Signal | Applies to | Weight | How it is read |
|---|---|---|---|
| Sanctions list | any address | 34 | Membership 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 type | any address | 16 | eth_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 source | contract | 22 | Sourcify 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. |
| Upgradeability | contract | 14 | eth_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 metadata | token | 8 | name(), symbol(), decimals() and totalSupply() read directly with eth_call. |
| Privileged roles | token | 16 | Role 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 transfer | token | 14 | A 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
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.
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.
Same paywall, same silent failure. Absent rather than approximated.
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.
Reading pool depth honestly means indexing every venue on the chain. No keyless source, so no number.
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.
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.
Not on-chain. Verified source is not an audit and is never presented as one.
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.
Scoring
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.
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.