# FAR — Free Asset Resolver > A free, static, key-less resolver between CoinGecko ids and CAIP-19 chain-agnostic asset identifiers. Give it a CoinGecko id and get every chain the asset is deployed on as a standards-compliant CAIP-19; give it a CAIP-19 and get the CoinGecko id, so on-chain data can be priced. Every lookup is a plain JSON file at a predictable URL under https://0xcounting.github.io/FAR. There is no server, no authentication, no rate limit, and every file is sha256-hashed into a Merkle-rooted manifest with a per-file inclusion proof. Names and tickers are not unique. The /name and /symbol routes therefore return a GROUP of distinct assets, and each asset carries a `family` field saying whether it is the canonical asset others are named after, a self-declared wrapper of one, or standalone. Use it to pick the right USDC out of sixty. To use it: fetch `index.json` for live counts and the route list, then fetch the route you need. Prefer one file per query over the bulk dump unless you need the whole registry. CoinGecko ids and CAIP-19s are case-sensitive as published; names and tickers are looked up by slug (lowercased, punctuation to `-`). ## Start here - [index.json](https://0xcounting.github.io/FAR/index.json): counts, source snapshot hashes, and the full route list. Fetch this first. - [openapi.json](https://0xcounting.github.io/FAR/openapi.json): OpenAPI 3.1 description of every route and response shape. - [README](https://0xcounting.github.io/FAR/README.md): the human documentation, in Markdown. - [llms-full.txt](https://0xcounting.github.io/FAR/llms-full.txt): this file plus the README and contributor guide inlined, for a single-fetch context. ## Routes - [/cg/{coingeckoId}.json](https://0xcounting.github.io/FAR/cg/tether.json): one asset by CoinGecko id, with every chain deployment as a CAIP-19, its naming family, and related assets. - [/caip/{ns}/{ref}/{assetNs}/{assetRef}.json](https://0xcounting.github.io/FAR/caip/eip155/1/erc20/0xdac17f958d2ee523a2206206994597c13d831ec7.json): the asset at an exact CAIP-19. The identifier is written as a path: `:` and `/` become `/`, and `%` becomes `~`. - [/name/{slug}.json](https://0xcounting.github.io/FAR/name/tether.json): every asset with that name. Always a group, never one asset, because names are not unique. - [/symbol/{slug}.json](https://0xcounting.github.io/FAR/symbol/usdc.json): every asset with that ticker. `usdc` returns 60+; use `family` to tell the canonical one from wrappers. - [/far.json.gz](https://0xcounting.github.io/FAR/far.json.gz): the entire registry as one gzipped JSON, about 1.8 MB. - [/search-index.json](https://0xcounting.github.io/FAR/search-index.json): compact array the site searches client-side; useful for fuzzy lookup in your own process. ## Trust - [/_platforms.json](https://0xcounting.github.io/FAR/_platforms.json): every chain mapping with its `confidence` and `evidence`. A deployment's `confidence` is inherited from its chain. - [/_namespace-gaps.json](https://0xcounting.github.io/FAR/_namespace-gaps.json): CAIP-2 and CAIP-19 namespaces this registry had to choose because no CASA specification defines them. A CAIP-19 on Cosmos, Tron, Sui, Aptos or TON is this project's proposal, not a ratified standard. - [/_platforms.json](https://0xcounting.github.io/FAR/_platforms.json): every chain mapping with its `confidence` and `evidence`. - [/_chains.json](https://0xcounting.github.io/FAR/_chains.json): CAIP-2 -> chain identity for every chain the registry can name, independent of CoinGecko platforms (Cosmos today), so an IBC voucher's origin is always nameable. - [/_ics20-unplaced.json](https://0xcounting.github.io/FAR/_ics20-unplaced.json): IBC vouchers whose mapping is verified (the ibc/ hash recomputes from path + base denom) but whose origin asset has no CoinGecko id; each carries the origin CAIP-19 it is equivalent to. Deployments with a `verified` object are this class: proven, not reviewed. ## Verification - [/manifest.json](https://0xcounting.github.io/FAR/manifest.json): sha256 of every file and the Merkle root of the release (11 MB). - [/manifest.sha256](https://0xcounting.github.io/FAR/manifest.sha256): the root on one line, for pinning. - [/proof/{path without .json}.json](https://0xcounting.github.io/FAR/proof/cg/tether.json): a file's inclusion proof (about 17 hashes) so one response can be checked against the root without the manifest. ## Optional - [Contributing](https://github.com/0xcounting/FAR/blob/main/CONTRIBUTING.md): how to map a chain, raise a confidence level, dispute an identifier, or add a native asset. Every change is a reviewed pull request with cited evidence. - [Governance](https://github.com/0xcounting/FAR/blob/main/GOVERNANCE.md): who decides, how disputes are resolved, what the project will not do. - [Sources and licences](https://github.com/0xcounting/FAR/blob/main/SOURCES.md): per-source terms. Code is MIT; curated tables are CC0; CoinGecko and chain data keep their own terms. - [/.well-known/api-catalog](https://0xcounting.github.io/FAR/.well-known/api-catalog): RFC 9727 API catalog pointing at the OpenAPI description. - [Source repository](https://github.com/0xcounting/FAR) --- # README # FAR — Free Asset Resolver **A CoinGecko ID ↔ CAIP-19 resolver, published as static files.** Give it a CoinGecko id and get every chain the asset is deployed on as a standards-compliant CAIP-19; give it a CAIP-19 and get the CoinGecko id, so on-chain data can be priced. 20,000+ assets, 41,000+ deployments, 290+ chains, 45 address formats normalised, no key, no server. | Identifier | Who issues it | How you get one | How many exist | |---|---|---|---| | **[CAIP-19](https://chainagnostic.org/CAIPs/caip-19)** | nobody — it is derived from the asset itself | deploy the token; the ID already exists | unbounded | | **CoinGecko ID** | CoinGecko | get listed | 18,090 | A CoinGecko ID is what almost every price API keys on. A CAIP-19 is the only identifier you can compute yourself from a chain ID and a contract address, without asking anyone's permission or waiting for a registry to catch up. Software that touches both ends up maintaining this mapping privately. FAR maintains it in the open instead. **Browse and test queries at ** — the site is a docs page with a live resolver that queries these same static files. ``` GET /name/tether.json GET /symbol/usdt.json GET /cg/tether.json GET /caip/eip155/1/erc20/0xdac17f958d2ee523a2206206994597c13d831ec7.json ``` Every route is a static file. There is no server, no API key, no rate limit, and no request that can fail differently from any other. The whole registry is also one file (`/far.json.gz`) if you would rather hold it locally. **If you are an agent or a tool**, start at [`/llms.txt`](https://0xcounting.github.io/FAR/llms.txt) (what this is and how to use it), then [`/openapi.json`](https://0xcounting.github.io/FAR/openapi.json) (every route and response shape). There is also an RFC 9727 catalog at `/.well-known/api-catalog`, this README at `/README.md`, and [`/llms-full.txt`](https://0xcounting.github.io/FAR/llms-full.txt) with the docs inlined. ## What is actually in it | | | |---|---| | CoinGecko coins | 21,894 | | — resolvable to at least one CAIP-19 | 20,945 (95.7%) | | CAIP-19 identities | 41,839 across 294 chains | | Native units of account | 41 chain identities | | CoinGecko platforms mapped to CAIP-2 | 306 | | — still unmapped | 10 | | Chains named by CAIP-2 independent of a CoinGecko platform | 223 | | ICS-20 vouchers verified by recomputing their hash | 7,938 | | — placed on a CoinGecko coin / already listed / origin asset has no CoinGecko id | 4,580 / 127 / 3,231 | | Published files | 101,458 | ## Read this before you trust a chain A chain is also an identity in its own right, not only a CoinGecko platform: `data/chains.json` (served as `/_chains.json`) names every mainnet in the Cosmos chain-registry by CAIP-2 — 223 chains, whether or not CoinGecko files tokens under them — so an IBC voucher's origin chain can always be named, and a platform under which CoinGecko lists no tokens (Celestia, Stride, Axelar, Sei, ...) still resolves. The CAIP-2 reference follows the cosmos profile's `hashed-` rule for chain ids that fail its direct grammar (`kava_2222-10`, `shentu-2.2`) — and because nobody writes that form by hand, the raw spelling is published as an alias that resolves on every route to the same record. Ask in either dialect; see CONTRIBUTING §4. One asset class is **verified rather than reviewed**: IBC vouchers. ICS-20 defines the voucher denom as `ibc/` + `sha256(path + "/" + base_denom)`, so a claimed mapping can be recomputed by anyone from its own two strings. 7,938 such traces are vendored, CI re-derives every one, and the deployments built from them carry a `verified` object stating the rule and its inputs (CONTRIBUTING §5). 4,584 of them place onto a CoinGecko coin through identities the registry already held; the 3,226 whose origin asset has no CoinGecko id are published at `/_ics20-unplaced.json` with the origin CAIP-19 each is equivalent to — two identifiers, one asset, no CoinGecko id needed. Every entry in `data/platforms.json` carries a `confidence`: - **`high`** — the mapping is exercised daily in a production ingest pipeline, or the CAIP-2 is defined by the CASA namespace spec itself. - **`medium`** — hand-reviewed by a person against a named source, which is recorded in `evidence`. - **`low`** — matched automatically on a chain name, or the asset namespace is provisional because **no ratified CAIP-19 exists for that ecosystem yet**. That last case is common and worth stating plainly: CASA has ratified a CAIP-2 namespace for ~48 ecosystems but a CAIP-19 asset namespace for only a handful. For Cosmos, Tron, Aptos, Sui, Algorand, Tezos, NEAR and Cardano, **this registry is choosing a namespace that no standard has blessed**. Those choices are marked `low`, documented in each entry's `note`, and are exactly the kind of thing the dispute process exists to change. ## Verifying what you fetched Every build publishes `/manifest.json`: the sha256 of every file, plus a Merkle root over `(path, hash)` pairs. Every file also has a proof at `/proof/.json`: its hash, the release root, and the ~17 sibling hashes that connect them. That is all you need to check one response belongs to the release, without the 11 MB manifest. ```bash curl -sO https:///cg/tether.json curl -sO https:///proof/cg/tether.json # ~1.3 KB node scripts/verify.js --proof-file tether.json cg/tether.json ``` Pass the root from somewhere you trust — the build log, a release, a value you pinned in CI — rather than the one inside the proof file; the latter only shows the proof is self-consistent. Two people can confirm they are looking at the same registry by comparing that one 64-character string. Builds are deterministic: the same vendored snapshots and the same curated tables produce byte-identical output and therefore the same root. ## Using it ```js const res = await fetch(`https:///name/${encodeURIComponent(name.toLowerCase())}.json`); if (res.status === 404) { /* no asset by that name */ } const { assets } = await res.json(); ``` A name is **not** unique — that is the point of the `/name/` route returning a group. `tether` is one name and several assets; `usdc` is a symbol shared by 62 of them. Each entry in a group carries its own `deployments` (the CAIP-19 on each chain it exists on) and `related`: - `related.sameName` / `related.sameSymbol` — the other coins in the collision. ## What this registry needs from the standards it uses 38 of the identifiers published here are **not defined by any CASA specification** — FAR had to choose them in order to name assets that exist. They are listed at `/_namespace-gaps.json`, and each one is a concrete proposal somebody could take to [ChainAgnostic/namespaces](https://github.com/ChainAgnostic/namespaces). **11 chain namespaces** (210 assets): `cip34` (Cardano), `near`, `radix`, `kaspa`, `movement`, `massa`, `icon`, `supra`, `aelf`, `fuel`, `kadena`. **27 asset namespaces** (999 assets) — the larger gap, because CASA has ratified a CAIP-19 for only **six** ecosystems (eip155, solana, hedera, stellar, xrpl, stacks). So `jetton` for TON's 213 tokens, `trc20` for Tron's 92, `nep141` for NEAR's 72 and two dozen more are this registry's opinion, not a standard. Tron makes the asymmetry concrete: its **CAIP-2 is ratified but its CAIP-19 is not**, so we can name the chain correctly and cannot name a token on it correctly. That is the gap CAIP-19 adoption actually faces, expressed as a count rather than an opinion. ## Contributing The registry is only as good as its curated tables, and those grow by pull request. In rough order of usefulness: 1. **Map an unmapped platform** — 106 of them, listed in `_platforms.json` under `unmapped`, worth 902 assets. 2. **Raise a `low`-confidence platform to `medium`** by citing a source. 3. **Add a missing native** — `data/natives.json`. See [CONTRIBUTING.md](CONTRIBUTING.md) for how, and [GOVERNANCE.md](GOVERNANCE.md) for who decides and how disputes are resolved. ## Sources and licences Code is MIT. **The data is not under one licence and you should read [LICENSE-DATA](LICENSE-DATA) before redistributing any of it.** In short: the mapping tables and CAIP-19 identifiers this project constructs are CC0; CoinGecko ids and contract mappings, ethereum-lists and SLIP-0044 keep their own terms. [SOURCES.md](SOURCES.md) records what each source permits, how this project obtained it, and the sha256 of the exact snapshot every build consumed. FAR is not affiliated with, endorsed by, or speaking for CoinGecko or the Chain Agnostic Standards Alliance. --- # CONTRIBUTING # Contributing Everything published is built from four vendored snapshots plus two curated tables. **You only ever edit the curated tables.** `dist/` is generated and is not in git. ``` data/platforms.json CoinGecko platform -> CAIP-2 chain + asset namespace data/natives.json coins that ARE a chain's unit of account (BTC, ETH, …) data/chains.json CAIP-2 -> chain identity, independent of CoinGecko (Cosmos today) — GENERATED by scripts/gen-chains.js; only `curated: true` rows are hand-edited data/sources/*.gz upstream snapshots — replaced by the refresh job, not by hand ``` Setup is `git clone` and nothing else — Node 22+, zero dependencies. ```bash node src/validate.js # the CI gate; run it before you push node src/build.js # writes dist/ (~79k files, ~10s) node scripts/propose-platforms.js # suggests candidates for unmapped platforms ``` ## The five useful contributions ### 1. Map an unmapped platform 106 CoinGecko platforms have no CAIP-2, covering 902 assets. They are listed in `data/platforms.json` under `unmapped`, biggest first. ```json "the-open-network": { "caip2": "ton:-239", "assetNamespace": "jetton", "nativeAsset": "slip44:607", "addressFormat": "ton-address", "confidence": "low", "evidence": ["TON whitepaper: mainnet workchain -239", "no CASA namespace for TON"], "note": "TON has no ratified CAIP-2. Both the chain ID and 'jetton' are provisional." } ``` Then remove the entry from `unmapped`. If the address shape needs handling that `src/lib/caip.js` does not have, add a case to `normalizeAddress` — and make it **reject** anything that does not match the expected shape. A malformed CAIP-19 is worse than a missing one: it looks authoritative and will not round-trip. Run `node src/build.js` and check the `rejected addresses` line. If your platform appears there, the shape check is wrong. ### 2. Raise a low-confidence platform 84 platforms were matched on chain name alone by `scripts/propose-platforms.js` and are marked `low`. Confirming one is quick and the evidence is concrete: - Find a token on that chain in `/caip/…`, look the address up on the chain's own explorer, confirm the chain ID the explorer reports. - Update `confidence` to `medium` and add what you checked to `evidence`. Name matching has already been wrong here at least once — `core` matched "MemeCore" (4352) instead of CoreDAO (1116) — so this is not busywork. ### 3. Add a missing native `data/natives.json` covers 28 coins. Cardano, TON, Polkadot and others are missing. A native needs a CAIP-2 you can cite and a SLIP-0044 coin type (`data/sources/slip44.json.gz`). ### 4. Name a chain CoinGecko does not have a platform for `data/platforms.json` is keyed by CoinGecko platform slug, so a chain only existed there if CoinGecko filed tokens under it. `data/chains.json` names a chain as an identity in its own right — today every mainnet in the Cosmos chain-registry — so an IBC voucher's origin, or a chain whose native coin is the only CoinGecko asset on it, can still be resolved. The table is **generated** (`node scripts/gen-chains.js`) from `data/sources/cosmos-chain-registry.json.gz`; do not hand-edit generated rows, they are overwritten. Two things are worth a PR: - A chain the live registry no longer carries (a killed or migrated chain whose identifiers still appear in ledgers). Add it with `"curated": true`, the chain_id, and evidence naming where the id was read — the generator preserves curated rows. Stargaze is the worked example. - A CoinGecko asset-platform that is a Cosmos chain but has no `platforms.json` entry. Run `node scripts/add-cosmos-platforms.js --dry-run`: it joins `asset_platforms.native_coin_id` to the chain's `coingecko_id` and adds an entry only when the pairing is unique in both directions. If your chain does not join (no native coin id on either side), add the platform entry by hand with the chain-registry line as evidence. **Which spelling is canonical, and why both are published.** The CAIP-2 reference follows the **cosmos profile**, not the generic CAIP-2 grammar: the direct-reference charset is `[-a-zA-Z0-9]{1,32}`, so a chain_id containing `_` or `.` (`kava_2222-10`, `shentu-2.2`, 47 chains today) is canonically `cosmos:hashed-` + the first 16 hex of its sha256, per `cosmos/caip2.md`. Nobody writes that form by hand: wallets, explorers and humans write the raw chain-id. Publishing only the hashed form would make FAR speak a dialect nobody else speaks; publishing only the raw form would mean a consumer implementing the spec never finds the row. Both are the same failure — someone asks in a reasonable dialect and gets nothing — so the registry publishes **both**: - the **hashed form is the canonical key** — every record (`caip2`, `caip19`) carries it, and it is what `chains.json` is keyed by; - the **raw spelling is an `aliases` entry** on that row, and every route answers under it too: `/caip/cosmos/kava_2222-10/...` returns the same record as `/caip/cosmos/hashed-6d4e837e169119f0/...`, plus an `alias` object saying what was asked for and what it resolved to. `/_chains.json` carries the full `aliases` map. An alias can never collide with a real conformant reference: it only exists because the raw id contains a character the direct grammar forbids, and CI refuses an alias that looks like a hashed key, equals another chain's key, or is duplicated. Write platform entries with the canonical key (CI rejects the alias dialect there and names the key to use). `cosmosCaip2()` in `src/lib/caip.js` is the one place the rule is implemented. ### 5. A voucher mapping you can check yourself IBC vouchers (`ibc/` denoms) are the one asset class in this registry whose mapping is **verifiable rather than asserted**: the chain that minted the voucher defines `HASH = uppercase(hex(sha256(path + "/" + base_denom)))`, so given the path and the base denom anyone can recompute the hash and either it matches or the claim is false. `data/sources/ibc-denom-traces.json.gz` carries 7,938 such rows; CI re-derives every one of them. Deployments built from it carry a `verified` object: ```json "verified": { "method": "ics20-denom-trace", "rule": "uppercase(hex(sha256(path + \"/\" + baseDenom))) reproduces the hash in the denom", "path": "transfer/channel-0", "baseDenom": "uatom", "origin": "cosmos:cosmoshub-4/bank:uatom", "resolvedBy": "derive:denom_traces+bank_metadata:cosmoshub-4", "placedVia": "origin-identity" } ``` Read it as two claims of different strength. `path` + `baseDenom` -> `denom` is **proven** (recompute it). `origin` and the CoinGecko id the voucher was placed under are **derived**: the origin comes from walking the path through the chain-registry's channel tables, and `placedVia` says which already-known identity the base denom matched (`origin-identity`: the origin chain's own denom; `eth-erc20`: an Ethereum contract the base denom embeds; `ibc-canonical`: a CoinGecko-listed voucher for the same origin pair). Dispute the derived half like any other mapping; the proven half you can only dispute by producing a different `(path, baseDenom)` that hashes to the same denom, which is a SHA-256 collision. `/_ics20-unplaced.json` lists the verified vouchers whose origin asset has no CoinGecko id this registry knows, each with the origin CAIP-19 it is `equivalentTo`. Placing one is a contribution: find the CoinGecko coin for the origin asset (usually a `bank:` denom on a chain CoinGecko has no platform for), and the build will place every voucher rooted there on the next run once the identity is known — via a platform entry, a native, or the chain table's `coingeckoNativeCoinId`. **This is stronger than `high`.** The confidence tiers describe how a mapping was *reviewed*; `verified` describes a mapping that needs no reviewer. It is kept as a separate field rather than a fifth tier because the voucher inherits its chain's confidence (the hash proves nothing about which chain `osmosis-1` is), and a field can say both things where a single enum cannot. ## Rules that CI enforces - Every platform entry has non-empty `evidence`. - `high` confidence requires production or CASA-spec evidence. - Every curated link has a `rationale` and a `decidedIn`. - The same pair is never both accepted and rejected. - Every CAIP-2 and CAIP-19 matches the grammar. - Every `chains.json` key is exactly what its `chainId` derives to under the cosmos profile, and every Cosmos platform in `platforms.json` points at a chain the table knows. - Every vendored ICS-20 trace reproduces its own `ibc/` from `sha256(path + "/" + baseDenom)`, is unique per chain, and names a chain the chain table knows. - Every native is `/slip44:` and its CAIP-2 agrees with its own field. - Route slugs round-trip. ## What gets a PR rejected - A mapping with no evidence, or evidence that is "I know this". - Editing `data/sources/*` by hand. Those are snapshots; the refresh job replaces them wholesale so the recorded sha256 stays meaningful. - Editing `dist/`. It is generated. - Adding a dependency. The build is dependency-free on purpose: this thing is meant to still build in five years. ## Conduct Argue about evidence, not about people. Someone disputing your mapping is doing the job. A maintainer with a commercial interest in an outcome says so and steps back from deciding it.