Multichain assets
Assets and variants, chain ids and CAIP-2, <chain>:<address> keys, capability flags, primary variant selection, and how per-chain stats roll up.
The v2 asset surface is chain-native: the same curated assets as v1, with their tokens on Solana, Ethereum, Base, Arbitrum, Polygon and BNB. This page is the model; the routes are on Chains, Assets and Variants, and the TypeScript types are in Shared shapes.
Two nouns
- An asset is the curated, chain-agnostic thing:
usd,bitcoin,tesla. It lives underGET /v2/assetsandGET /v2/assets/{assetId}. - A variant is one token on one chain that represents an asset. It has exactly one identifier,
the key
<chain>:<address>(solana:EPjF…,base:0x8335…), and lives underGET /v2/variants/{chain}/{address}and the batchGET /v2/variants?keys=.
Every v2 asset is curated. There are no synthetic per-mint assets: an address-shaped {assetId}
is 400 invalid_asset_id, and a token the registry does not know is 404 variant_not_found (or
missing[] in a batch). For unregistered Solana tokens use
token lists or search.
Chains and CAIP-2 ids
The chain list is compiled into the API, so adding a chain is a release, never a data change.
Cache GET /v2/chains freely.
id | caip2 | Family | Explorer |
|---|---|---|---|
solana | solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp | svm | Solana Explorer |
ethereum | eip155:1 | evm | Etherscan |
base | eip155:8453 | evm | Basescan |
arbitrum | eip155:42161 | evm | Arbiscan |
polygon | eip155:137 | evm | Polygonscan |
bnb | eip155:56 | evm | BscScan |
The id column is the chain value on every variant and the value every chain= param and
<chain>:<address> key accepts. Provider-side slugs (polygon-pos, arbitrum-one, bsc) are
not accepted and return 400 with details.code: "invalid_chain". Each chain also publishes a
caip2 id (CAIP-2), an evmChainId (null for
Solana) and an explorer URL template with an {address} placeholder.
Variant keys
A 0x address is the same string on every EVM chain, so no v2 input is a bare address: the chain
is a path segment (/v2/variants/{chain}/{address}) or the key prefix (keys=base:0x…).
- EVM addresses are
0xplus 40 hex characters. They are accepted in any casing and always returned lowercase. Compare keys, not checksummed strings. - Solana addresses are case-sensitive base58, as in v1.
- A malformed address is
400 invalid_addresswithdetails.expectedset tobase58or0x40hex.
Capabilities per chain
GET /v2/chains publishes a capability flag set per chain. The flags are the contract for what
the rest of the surface can return for a variant on that chain; gate your UI on them, not on
chain === 'solana'.
| Flag | Meaning |
|---|---|
markets | Per-variant market snapshot (price, liquidity, volume) |
dexMarkets | Per-pool DEX market lists |
ohlcv | Candles |
risk | Risk summary and details; also required for pegHealth |
executionQuality | Fill-quality snapshots |
swap | Swap and trade links, execution routing; defines the "executable" pool below |
firstPartyLogos | tokens.xyz-hosted logo mirror |
Solana has every capability. The EVM chains have markets only: no OHLCV, risk, DEX market
lists, execution quality, swap routing or first-party logos. When an EVM capability is switched on
it flips in GET /v2/chains first, so a client that gates on the flags needs no code change.
What this means for variants: market is populated on every chain where a snapshot exists.
Execution quality and peg health are opt-in on the asset detail
(GET /v2/assets/{assetId}?include=executionQuality,pegHealth, plus preStocks for Solana
PreStocks tokens) and are null on chains without the executionQuality or risk capability.
OHLCV, risk, DEX market lists and swap routing are not exposed on v2 variants; use the v1 asset
routes for Solana mints.
All chains by default
An asset's chains, per-chain chainStats, cross-chain aggregate, stats, primaryVariant
and primaryVariantByChain are always computed from its full variant set.
chain= narrows what is listed, never what is summed. On GET /v2/assets it keeps only
assets with at least one variant on that chain and, with include=variants, lists only that
chain's variants. On GET /v2/assets/{assetId}/variants it filters the rows. The numbers above do
not change, and each variant's rank stays its liquidity rank within the whole asset across
chains.
Per-chain stats, aggregate and reference market
chainStats.<chain>is that chain's on-chain view. Liquidity, 24h volume and trade count are summed over every variant that passes the quality guard; market cap, FDV and supply only over variants whoseissuanceisnative. A bridged or wrapped token is a claim on supply issued elsewhere, and a derivative (liquid staking token, ETF share, leveraged or basket product) is exposure to the asset rather than its supply.excludedFromSupplyCountsays how many were left out andexcludedByIssuancewhy. Issuance comes from an explicit tag, else a curated per-deployment override, else the variant kind. A derivative kind only means "derivative of this asset" when the asset has some other deployment: when every variant is a yield, ETF, leveraged or basket token (a standalone treasury fund, say) those variants are the asset and count asnative. Commodities are the exception, since an ETF share is never the metal.- The quality guard. Before a market row enters any sum it must be fresh (a successful provider
write within 2 h on Solana, 3 h on EVM), not dust (liquidity and 24h volume both under $1k, unless
nothing else survives), and priced within 25% of the reference price, or without one, of the
surviving rows' liquidity-weighted median. Derivatives skip the price check because they are not
priced in the asset's units. A failing row leaves every sum and average, including market cap and
supply, and says so in
market.quality;excludedCountandexcludedByQualitycount them per chain and in aggregate. aggregateis the sum ofchainStatsacross chains, with averages weighted by chain liquidity, pluschainCountandexcludedFromSupplyCount: the one guarded, issuance-aware on-chain figure.referenceMarketis the off-chain reference (v1'scanonicalMarket): CoinGecko for crypto, the stock feed for one-share-per-token equities and ETFs (source: "stock"replaces v1'sclickhouse_stock), the PreStocks mark for pre-IPO equities. Keep a default branch when you switch onsource.statsis the reference-first headline. Price, market cap, FDV, 24h change and supply come fromreferenceMarketwhen there is one; liquidity, DEX volume, trades and the 1h change fromaggregate; anything the reference lacks falls through toaggregate. For an equity the market cap is the company's andfdvisnull(the tokenized float isaggregate.marketCap), and supply is the tokenized issued supply.stats.sourcesays where each figure came from. A native coin's home-chain row (ETH on Ethereum) has no pool and carries the reference's supply, sochainStats.ethereumis not empty.volume30dUSDsums each chain's 30-day DEX volume over the chains in the window (traded in the last 24h, or with accepted volume in the window). It isnulluntil every such chain has at least 28 sampled days for each variant that matters to its total, refreshed within 48 h; rows the quality guard rejects are left out.volume30dScopesays whether it covers every chain or Solana alone.
Primary variant and primaryScope
primaryVariant is the variant to trade. Selection has two steps: pick a candidate pool, then
rank inside it.
With the default primaryScope=executable, candidates are drawn from chains whose swap
capability is on (Solana), taking the first non-empty pool:
executable_active— actively traded variants on executable chainsactive— actively traded variants on any chainexecutable— any variant on an executable chainall— everything
"Actively traded" means at least $100 of 24h volume and 5 trades. primaryScope=global skips the
executable pools and gives the cross-chain liquidity winner.
Inside the pool the applied primaryVariantStrategy ranks: liquidity by default,
stock_redeemability for equities (redeemable tiers first, then liquidity), or
execution_quality. A variant with no market data never outranks one that trades, and
compromised or blocked variants are skipped while a safe sibling exists; when every candidate is flagged, the least-bad flagged variant is returned rather than none. primaryVariantSelection reports the pool
and the deciding rule so the choice is reproducible, and primaryVariantByChain runs the same
ranking inside each chain.
Advisories
Advisories are keyed by Solana mint, so EVM variants always carry advisory: null. An asset's
advisories[] lists every flagged variant, most severe first, including blocked siblings that
list surfaces hide.
| Status | Meaning | What the API does |
|---|---|---|
caution | Trade with care: a known concern that does not make the token unsafe. | Returned everywhere; never changes ranking or inclusion. |
compromised | The token or its issuer was exploited or has otherwise lost integrity. | Never the primary variant; excluded from trending; still readable with the advisory attached. |
blocked | Do not trade: operators have withdrawn the token from the surface. | Never the primary variant; excluded from trending, search and curated lists; still readable by id. |
Each advisory carries status, reason, an optional url with more detail, since (unix milliseconds the current status was set), and source (admin for a human operator, webacy_depeg for the Webacy depeg monitor, peg_guard for the tokens.xyz peg monitor). System sources only ever set caution; escalation is a human decision. Read endpoints annotate; they never refuse. Treat compromised and blocked as do-not-trade in your UI.
On the v2 asset surface: GET /v2/assets omits blocked variants from every row and drops an
asset whose variants are all blocked; GET /v2/assets/{assetId}, the /variants sub-route and
the variant routes serve them with the advisory attached. The long form is in
Advisories.