Skip to main content

The token catalogue

ChainOS credits deposits of a fixed, published set of tokens. The catalogue names each token, each chain it is deployed on, the contract address on that chain, and — the field everything else hangs off — the number of decimals that contract uses.

GET /v1/treasury/tokens

A deposit of a contract not in this list is not detected and not credited. That is a deliberate design choice rather than a limitation to work around: a chain carries thousands of tokens, most of them worthless, and many of them deliberately built to resemble one that is not.

Decimals are per chain, not per token

USDT is six decimals on Ethereum and eighteen on BNB Smart Chain. The same issuer, the same brand, the same ticker — a different precision.

This is why decimals appears on each deployment rather than once per token, and why you should read it from the deployment you are actually crediting. Reading Ethereum's value for a BNB Smart Chain deposit credits the customer one million-millionth of what they sent. Reading it the other way credits them a trillion times too much.

A chain can be deliberately absent

Every token response carries unsupportedChains alongside its deployments, each with a reason. A missing pair is always one or the other — listed as deployed, or listed as deliberately absent with an explanation. There is no third category of "unknown".

{
"symbol": "USDC",
"deployments": [ { "chain": "eth", "decimals": 6, "monitored": true } ],
"unsupportedChains": [
{ "chain": "bsc", "reason": "Circle does not issue native USDC on BNB Smart Chain." }
]
}

Read unsupportedChains while you are designing, not after a request fails. It exists so that a gap is something you find at integration time rather than through a 422 in production.

Bridged and deprecated deployments

Two flags on a deployment matter more than they look:

  • deprecated — superseded, usually by a native issuance, and still monitored. Deposits to a superseded bridged token are real money and are credited. A deprecated deployment is one you should stop quoting to your users, not one you can stop watching.
  • bridgeable — whether the token can be moved cross-chain. False for anything you could not redeem with its issuer. Bridging a third-party wrapper would hand you an asset nobody is obliged to honour, so the catalogue refuses to treat it as bridgeable however liquid it looks.

Polygon's bridged USDC.e was both, and was carried distinctly from native USDC until registry v2 withdrew it — crediting one as the other is exactly the error the catalogue exists to prevent, and the safest way not to make it is not to carry the wrapper at all.

Asking for a token that is not listed

POST /v1/treasury/token-requests
{ "chain": "eth", "contractAddress": "0x…", "symbol": "DAI", "decimals": 18 }
A request does not start monitoring

This records a request and puts the contract in front of a ChainOS administrator. It does not begin monitoring, and deposits of the token are not credited while it is under review. Sending funds to an address expecting them to appear will not work.

The symbol and decimals you send are recorded as your claim, not adopted as fact. The contract is read on-chain, its decimals() is compared with what you declared, and a second administrator approves the publication before anything changes. A mismatch between your declaration and the chain is precisely what that review exists to catch — so state the values as you have them, not as you think they should be.

Track a request with:

GET /v1/treasury/token-requests

The field to act on is monitored. It is false in every state but published:

statemonitoredWhat it means
under_reviewfalseWith an administrator.
acceptedfalseApproved into a pending change. Still not credited.
publishedtrueIn the catalogue. Deposits are now detected and credited.
declinedfalseReviewed and declined. outcome carries the reason.

Posting the same contract twice is a no-op — your account counts once either way.

When the catalogue changes

Publication is a versioned operation. GET /v1/treasury/routes returns the registryVersion its answer came from, and a new version reaches every node within seconds of being published. You do not need to do anything to pick it up, and a token already in the catalogue never changes its contract address or decimals: a correction is published as a new version, which is auditable, rather than edited in place, which is not.