Methodology

How this scanner
reaches its numbers

Every check, where its data comes from, and what it cannot know. Pons Scanner never says a token is safe — it reports what is readable on-chain and links you to the source.

The two numbers

Score and coverage are separate and are never combined into a single badge.

Coverage, 0–100%
Purely deterministic: the share of attempted checks that returned real data. No model is involved. A check that returns Unknown lowers coverage automatically.
Risk score, 0–100
Findings are detected by rules. Each carries a point band rather than a fixed value, and a model allocates within those bands and writes the interpretation. The score is the exact sum of the allocations. Every allocation is validated against its band before anything renders; a malformed or out-of-band response is retried once, and a second failure falls back to band midpoints, which the report labels as rule-derived.

Unknown is never a risk signal

This is the rule the rest of the design bends around.

Any finding whose confidence is unknown has its point band forced to zero in code, before the model is ever shown it. An Unknown lowers coverage and appears in the report with the reason it is unknown. It can never add points.

The reason is concrete. A token that is legitimately hard to index would otherwise score as critical purely for being unreadable, with the same missing data counted twice — once as reduced coverage, and again as risk. That is a real failure mode in existing tools, and this scanner is built not to reproduce it.

Every Unknown in a report states why it is unknown. A bare “Unknown” is treated as a bug.

Checks, sources, and limits

What each module reads, and what it cannot see.

Contract

Source. Chain (bytecode, ERC-20 getters, EIP-1967 storage slots) and Blockscout (verification metadata).

Cannot know. If the source is not verified, nothing about the contract’s behaviour can be established from the bytecode alone. Verification also does not mean the code is correct or benign — only that it is readable.

Ownership and permissions

Source. Chain for owner() and role state. Verified source for capabilities, parsed for access-control modifiers and reachability.

Cannot know. Capabilities are read from the source only. Where the source is unverified, every capability is reported Unknown — we do not guess from the ABI selector list, because a function called mint() that always reverts is not mint authority, and a differently named function guarded by onlyOwner may well be. Deeply indirect authority (a call through an external contract) may be missed.

Transfer mechanics

Source. Chain. 35 getter names are probed across the common tax-token conventions.

Cannot know. There is no standard for how tax values are stored. Where the contract exposes no denominator, the scale is inferred and the assumption is printed alongside the raw value. A token using a getter name outside the probed set reports Unknown rather than zero.

Holder distribution

Source. Blockscout supplies the holder addresses; every balance is then re-read from the contract, because indexed balances go stale.

Cannot know. Only the top holders the explorer returns are examined. Wallets controlled by one person across several addresses are counted separately — on-chain data cannot tell them apart.

Liquidity

Source. Chain. The Uniswap V3 factory is asked for every combination of 3 quote tokens and 4 fee tiers.

Cannot know. Only Uniswap V3 pools against the listed quote tokens are found. Liquidity on another venue, another AMM, or against an unlisted quote token is invisible to this check. Depth is the quote side only, valued using the explorer’s ETH reference price.

V4 liquidity

Source. Chain. V4 keeps every pool inside one contract, so pools are found from its Initialize logs — both currencies are indexed — and price, fee and liquidity are read out of that contract’s storage directly.

Cannot know. Reserves cannot be read per pool, because every V4 pool’s tokens sit in the same balance. Depth is therefore established by simulating a sale of a fixed share of supply through the quoter, and only the deepest pools are simulated; the rest are listed with what was read. A pool’s hook is reported as present, never interpreted — this scanner does not read hook code.

LP status

Source. Chain. Position NFTs are resolved through the V3 position manager and their owners classified.

Cannot know. Lock duration and release terms are not read — a position held by a locker may unlock tomorrow. A contract we cannot identify is reported as unidentified rather than assumed safe. Positions minted directly to a pool rather than through the position manager cannot be resolved as NFTs.

Deployer

Source. Blockscout for the creation transaction, creator, counters and history.

Cannot know. Account age is only knowable when the account’s full history fits inside the bounded page walk; beyond that it is reported Unknown. The whole module also runs against a four-second budget and reports Unknown if the explorer does not answer inside it. A new account is not evidence of intent, and an old one is not evidence of good intent.

pons launch

Source. Chain. The pons launch factories, the launched-token record, the token itself, and the locker.

Cannot know. Every parameter is read per token — none is assumed from documentation, because they vary. Creator-supplied links are stored on-chain but are not verified by anyone. Creator history across launches needs an index and is not built yet.

Two block numbers

Robinhood Chain is an Arbitrum Orbit chain, and mixing its two block counters produces plausible-looking wrong answers.

Anything a contract stores or emits — a launch block, a restriction end block — is in the L1 namespace, because that is what Solidity’s block.number returns. Anything from eth_blockNumber or an event log is L2.

We measured 0.1s per L2 block against 11.93s per L1 block — the two counters tick about 119× apart, yet their absolute values currently sit within roughly 10% of each other because the L2 started later. A mistaken comparison therefore yields a believable wrong answer rather than an obviously absurd one, so the two are separate types in this codebase and cannot be compared by accident.

Point bands are provisional

Stated plainly rather than implied to be settled.

The bands below have not been calibrated against a real distribution of tokens yet. They are a starting point. A calibration script exists to scan a large sample and report the score distribution and where in each band the model tends to land; bands that always resolve to the same end will be collapsed to fixed values.

Treat the score as a way to rank what to read first, not as a measurement.

FindingSeverityBand
Source code is not verified

Nobody outside the deployer can read what this contract actually does. Behaviour cannot be checked against its bytecode.

contract.unverified
high622
Source is only partially verified

The explorer matched the source without an exact metadata hash, so the published source may differ in comments or compiler settings.

contract.partially_verified
low14
Contract is an upgradeable proxy

The logic behind this address can be replaced by whoever controls the proxy admin. Today’s behaviour is not a guarantee of tomorrow’s.

contract.proxy_upgradeable
medium412
Proxy points at an unverified implementation

The proxy is readable but the logic it delegates to is not. Verifying the proxy alone tells you nothing about what actually runs.

contract.proxy_impl_unverified
high620
Ownership is not renounced

A single address still holds the owner role. Whether that matters depends entirely on what the owner-only functions can do.

ownership.not_renounced
medium310
Supply can be increased

A privileged function can create new tokens, diluting every existing holder.

ownership.mint_authority
high620
Addresses can be blocked from transferring

A privileged function can stop specific addresses from moving their tokens.

ownership.blacklist_authority
high418
Transfers can be paused or gated

A privileged function can halt trading for everyone.

ownership.pause_authority
high418
Fees can be changed after launch

Current tax rates are not fixed. A privileged function can raise them.

ownership.fee_change_authority
medium312
Transaction or wallet limits can be changed

Maximum transaction and wallet sizes can be adjusted by a privileged address.

ownership.limit_change_authority
low16
Implementation can be swapped

A privileged function can repoint the proxy at entirely different logic.

ownership.upgrade_authority
high620
High transfer tax

A large share of each trade is taken as tax.

transfer.high_tax
high418
Moderate transfer tax

A noticeable share of each trade is taken as tax.

transfer.moderate_tax
medium29
Small transfer tax

A small tax applies to trades.

transfer.low_tax
low03
Sell tax is much higher than buy tax

Buying is cheap and selling is expensive, which makes exiting a position materially worse than entering one.

transfer.asymmetric_tax
high416
Maximum transaction size is restrictive

Single transfers are capped at a small fraction of supply, which constrains how quickly a position can be exited.

transfer.restrictive_max_tx
medium28
Maximum wallet size is restrictive

Any one address can hold only a small fraction of supply.

transfer.restrictive_max_wallet
medium28
One wallet holds a majority of circulating supply

A single independent address can move the market on its own. Pools, burn addresses and the token contract are excluded from this figure.

holders.single_wallet_majority
high620
One wallet holds a large share of supply

The largest independent holder is big enough to move price substantially.

holders.single_wallet_large
medium312
Top ten wallets hold most of the supply

Supply is concentrated among a small number of independent addresses.

holders.top_ten_concentrated
medium312
Very few holders

The holder count is low enough that there is little distribution to speak of.

holders.very_few
medium210
No liquidity pool found

No Uniswap V3 pool exists for this token against any quote token we check, at any fee tier. That is the only venue this scanner reads, so it means no readable V3 market — not that no market exists anywhere.

liquidity.none_found
high220
Very thin liquidity

Pool depth is small enough that an ordinary trade would move the price sharply.

liquidity.very_thin
high416
Thin liquidity

Pool depth is modest; larger trades will suffer noticeable slippage.

liquidity.thin
medium29
Liquidity position is held by a regular wallet

The LP NFT sits in an externally-owned account, so whoever holds the key can withdraw the pooled liquidity at any time.

lp.withdrawable_by_eoa
high620
Liquidity position is held by an unidentified contract

The LP NFT is held by a contract we could not identify as a locker. It may or may not be able to withdraw.

lp.held_by_contract
medium210
Liquidity position is burned

The LP NFT was sent to a burn address, so the position cannot be withdrawn. This is a fact about the position, not a statement about the token.

lp.burned
info00
Liquidity position is held by a locker contract

The LP NFT is held by a contract that looks like a locker. Lock terms and expiry are not read by this scanner.

lp.locked
info00
V4 pools exist but could not fill a sale

Every V4 pool for this token was asked, by simulation, to buy a small fixed share of supply, and none could complete it. Pooled tokens are present but the quote side is too thin to sell into at that size.

v4.no_fill
medium08
V4 pool fee takes most of the trade

A Uniswap V4 pool sets its own swap fee, and this token has pools charging a fee large enough that selling into them returns almost nothing. The liquidity is real and the pool quotes — the fee is what makes the position unexitable, which is a trap structure rather than a depth problem.

v4.extreme_fee
high518
V4 pool runs a hook contract

A V4 hook runs on every swap against the pool and can change what a trade does, including blocking it. This scanner reads that a hook is attached, not what it does — so this is a pointer to read the hook, not a finding about behaviour.

v4.hooked
low14
Deployer account is new

The deploying account has little history on this chain, so there is nothing to judge it by.

deployer.new_account
medium28
Deployer has little transaction history

The deploying account has made few transactions.

deployer.low_activity
low15
Creator bought a large share at launch

The launch configuration gave the creator a sizeable opening position.

pons.large_creator_buy
medium210
Launch restrictions are still active

Per-token buy limits from the launchpad are still in force. They expire on their own.

pons.restriction_window_open
info00
Creator fee payout has been redirected

Fee income no longer goes to the original creator address, which normally indicates a community takeover.

pons.fee_redirected
info00
Launch has not graduated

Paired principal has not reached the graduation threshold configured for this launch.

pons.not_graduated
info00

Determinism

Why the same token scanned twice returns the same score.

The model is pinned to claude-opus-5, and the prompt is versioned (2026-07-30.1). Assessments are cached against a stable hash of the sorted finding ids, their evidence, their bands, the model and the prompt version — identical evidence returns the identical assessment.

The scoring model is pinned and called with no sampling parameters; the current API rejects temperature outright. Identical evidence returns an identical cached assessment.

What the model may not do

Enforced in the prompt and validated on the output.

  • It may not output verdict words. Responses containing them are rejected and retried.
  • It may not invent a finding it was not given, or allocate to an unknown finding id.
  • It may not allocate outside a band, and the score must equal the sum of allocations.
  • It may not reference data it was not supplied.
  • It never sees a finding’s band as anything but zero when that finding is Unknown.