Skip to main content
/token-score returns one 0–100 composite describing a Base token’s market structure, computed from data planes Otto already operates. It is deterministic: no language model is anywhere in the path, so there is no narrative that can drift away from the numbers. The formula ships with every answer. Each response carries a formula block containing every factor’s weight, the exact response field it read, and the full list of breakpoints its curve interpolates between. Applying those breakpoints to the returned inputs reproduces the returned sub-scores and the composite exactly. You never have to take the number on trust, and this page is a description of that block — not a substitute for it.

What it is not

This is not a contract-security screen. It does not test for honeypots, mint authority, transfer taxes, blacklists or upgradeable proxies. A high score is not a statement that the contract is safe. That product is /token-security, and the two are complementary rather than overlapping.
It is also not predictive and not a recommendation. Every factor measures the token’s market as it stands right now. The score does not forecast price, does not rank tokens against each other, and band is a plain label for where the number falls — nothing more.

Why the key is a contract address

/token-score accepts a Base (chain 8453) ERC-20 contract address, 0x followed by 40 hex characters, and rejects a ticker symbol as malformed — uncharged. That is a correctness rule, not a limitation. The holder plane is keyed on a bare address on a named chain, while a symbol resolves through a canonical listing to whichever chain that asset’s main deployment lives on. Accepting a symbol would let one plane answer about a deployment on one chain while another answered about a different one, and the composite would fuse two tokens into one score with nothing in the response saying so. Address-keying makes all three planes provably describe the same token. For symbol lookups, use /token-price.

The seven factors

Each factor maps a raw input onto a 0–100 sub-score by linear interpolation between published breakpoints, clamped outside the ends. The composite is the weighted mean of the sub-scores that resolved, with the weights renormalised over exactly those factors. The weights are a judgement, and they are published as one. They are not the output of a backtest and no claim is made that they predict returns. Liquidity carries the largest single weight because it is the only factor that bounds whether a position can be exited at all; the two holder factors together (0.32) outweigh it because distribution is the property a market-structure score exists to surface. They are returned on every response precisely so you can reweight the sub-scores yourself.

Two deliberate choices worth knowing

Price direction is not scored. The scored factor is the size of the 24-hour move, because a score that rewarded going up would rank a pump above an established market. The signed change is returned unscored as context.priceChange24hPct. Liquidity is read from the pools, not from the price plane. Otto’s /token-price publishes the top pool’s reserve, which is the right number for a price lookup and the wrong one here: a token used mainly as a quote asset reports near nothing at the token level. Measured live on 2026-09-01, Base USDC came back with a top-pool liquidity of 0 while its matched pools held $26.6M. Summing the matched pools measures what this factor claims to measure. The price plane’s own figure still serves, unscored, as context.liquidityUsd. The pooled figure is a floor, not a total: the pool search returns one page, so a token quoted in hundreds of pools is summed over the pools it returned. context.poolsReturned and context.matchedPoolCount publish that denominator.

Absent factors are reported, never filled in

When a data plane does not answer, its factors come back with present: false, a null sub-score, and an absenceReason. They are never defaulted to a neutral value and never quietly dropped from the list, because a buyer could not otherwise tell a factor that was omitted from one that never existed. coverage.weightCoverage is the share of the full weighting that actually contributed to the number, and every present factor carries planeReadAt, the instant its own plane was read.

When the composite is withheld

When the factors that resolved carry less than half the total weighting, the composite is withheld: score is null and scoreWithheldReason is insufficient_factor_coverage. Every sub-score that did resolve is still returned, with its own source and read time.
The reason is that a “multi-factor composite” computed from a single data plane is a rename of that plane, not a composite. The price plane alone carries 0.22 of the weight — below the floor — so a token with neither a holder record nor an indexed pool returns its resolved sub-scores and no fused number. The threshold is published on every response as coverage.minWeightCoverage. The price plane is required: without it the token has no price, no liquidity and no identity, so the call is refused uncharged rather than served as a partial answer.

Score bands

band is a plain label for where the composite falls. It describes the score, not the token’s merit.

Two numbers to read carefully

Holder concentration includes contracts. Concentration is measured from the top holders as the holder index reports them, and those addresses routinely include liquidity pools, burn addresses, bridges, staking contracts and treasuries. A perfectly ordinary token can therefore look concentrated. Read the factor as what it is — how much supply sits in a few addresses — not as a claim about insiders. Turnover is returned unscored. context.turnover24h divides 24-hour volume by pooled liquidity. A very high turnover is consistent with real demand and with wash trading, and this data cannot tell those apart, so you get the ratio rather than a verdict.

Source and licensing

Every input comes from keyless public DEX data (GeckoTerminal / DexScreener) and a holder index Otto already licenses — the same planes behind /token-price, /pools-search and /holder-analytics. Nothing here is investment advice.