|
| 1 | +--- |
| 2 | +caip: 390 |
| 3 | +title: Minimal Cross-Chain Asset Metadata Standard |
| 4 | +status: Draft |
| 5 | +type: Standard |
| 6 | +category: Interface |
| 7 | +author: Yan (@xzensh) |
| 8 | +created: 2025-12-22 |
| 9 | +requires: 2, 19 |
| 10 | +--- |
| 11 | + |
| 12 | +## Simple Summary |
| 13 | + |
| 14 | +A standardized JSON schema for retrieving and verifying off-chain metadata (profile, visual assets, and links) for crypto assets, with built-in support for cross-chain identity discovery. |
| 15 | + |
| 16 | +## Abstract |
| 17 | + |
| 18 | +This proposal defines a minimal, chain-agnostic JSON structure for asset metadata. It addresses the fragmentation of token information across Web3 by standardizing how wallets and dApps fetch essential data (logo, name, symbol, decimals) and extended data (links, cross-chain locations). The standard prioritizes URI-based resource referencing and introduces a "locations" field to map a single asset's existence across multiple blockchains using [CAIP-19] identifiers. |
| 19 | + |
| 20 | +## Motivation |
| 21 | + |
| 22 | +Currently, asset metadata is fragmented across various repositories (Coingecko, CoinMarketCap, TrustWallet Assets, Tokenlists.org), each using proprietary JSON structures. |
| 23 | + |
| 24 | +1. **Inconsistency**: A developer must integrate multiple APIs to get a token's logo, website, and social links. |
| 25 | +2. **Cross-Chain Fragmentation**: Assets bridged across layers (e.g., L1 to L2) or chains are often treated as entirely separate entities by wallets, making portfolio views difficult to aggregate. |
| 26 | +3. **Ambiguity**: Link data is often unstructured (e.g., keys like `twitter`, `social_twitter`, `x_url`), requiring complex parsing logic. |
| 27 | + |
| 28 | +We propose a unified schema that is compatible with existing NFT standards (ERC-721/OpenSea) while adding specific support for fungible token needs and cross-chain peer discovery. |
| 29 | + |
| 30 | +## Specification |
| 31 | + |
| 32 | +The metadata MUST be returned as a JSON object. The schema is defined as follows: |
| 33 | + |
| 34 | +### Schema Definition |
| 35 | + |
| 36 | +```json |
| 37 | +{ |
| 38 | + "$schema": "http://json-schema.org/draft-07/schema#", |
| 39 | + "title": "CAIP Asset Metadata", |
| 40 | + "type": "object", |
| 41 | + "required": ["name", "symbol", "decimals", "image"], |
| 42 | + "properties": { |
| 43 | + "name": { |
| 44 | + "type": "string", |
| 45 | + "description": "Human-readable name of the asset." |
| 46 | + }, |
| 47 | + "symbol": { |
| 48 | + "type": "string", |
| 49 | + "description": "Abbreviated symbol of the asset (ticker)." |
| 50 | + }, |
| 51 | + "decimals": { |
| 52 | + "type": "integer", |
| 53 | + "minimum": 0, |
| 54 | + "description": "The number of decimals for the token balance. MUST be 0 for non-divisible assets (NFTs)." |
| 55 | + }, |
| 56 | + "image": { |
| 57 | + "type": "string", |
| 58 | + "format": "uri", |
| 59 | + "description": "URI to the asset's logo or primary image. WebP, SVG or PNG formats are RECOMMENDED." |
| 60 | + }, |
| 61 | + "description": { |
| 62 | + "type": "string", |
| 63 | + "maxLength": 1000, |
| 64 | + "description": "Brief description of the asset." |
| 65 | + }, |
| 66 | + "external_url": { |
| 67 | + "type": "string", |
| 68 | + "format": "uri", |
| 69 | + "description": "URL to the official website or external resource of the asset. Compatible with ERC-721 metadata." |
| 70 | + }, |
| 71 | + "links": { |
| 72 | + "type": "array", |
| 73 | + "description": "A list of auxiliary links related to the asset.", |
| 74 | + "items": { |
| 75 | + "type": "object", |
| 76 | + "required": ["name", "url", "rel"], |
| 77 | + "properties": { |
| 78 | + "name": { |
| 79 | + "type": "string", |
| 80 | + "description": "Display label for the link." |
| 81 | + }, |
| 82 | + "url": { |
| 83 | + "type": "string", |
| 84 | + "format": "uri", |
| 85 | + "description": "The destination URL." |
| 86 | + }, |
| 87 | + "rel": { |
| 88 | + "type": "string", |
| 89 | + "description": "Relationship type used for semantic classification.", |
| 90 | + "enum": [ |
| 91 | + "homepage", |
| 92 | + "whitepaper", |
| 93 | + "documentation", |
| 94 | + "source_code", |
| 95 | + "governance", |
| 96 | + "audit", |
| 97 | + "social", |
| 98 | + "browser", |
| 99 | + "exchange", |
| 100 | + "bridge" |
| 101 | + ] |
| 102 | + } |
| 103 | + } |
| 104 | + }, |
| 105 | + "uniqueItems": true |
| 106 | + }, |
| 107 | + "locations": { |
| 108 | + "type": "array", |
| 109 | + "description": "List of CAIP-19 identifiers representing this asset's peer contracts across different chains.", |
| 110 | + "items": { |
| 111 | + "type": "string", |
| 112 | + "pattern": "^[-a-z0-9]{3,8}:[-_a-zA-Z0-9]{1,32}/[-a-z0-9]{3,8}:[-.%a-zA-Z0-9]{1,128}$" |
| 113 | + }, |
| 114 | + "uniqueItems": true |
| 115 | + } |
| 116 | + } |
| 117 | +} |
| 118 | +``` |
| 119 | + |
| 120 | +### Field Descriptions |
| 121 | + |
| 122 | +#### Core Fields |
| 123 | +* **`decimals`**: This field is mandatory. For NFTs or non-divisible assets, it MUST be set to `0`. This eliminates ambiguity for consumers (wallets) regarding whether a value is missing or intentionally zero. |
| 124 | +* **`external_url`**: Used instead of "website" to maintain compatibility with existing NFT metadata standards (e.g., OpenSea). |
| 125 | + |
| 126 | +#### `links` Object |
| 127 | +To prevent key-name fragmentation (e.g., `twitter_url` vs `socials.twitter`), links are defined as an array of objects containing a mandatory `rel` attribute. |
| 128 | + |
| 129 | +Recommended values for `rel`: |
| 130 | +* `homepage`: Main project website. |
| 131 | +* `whitepaper`: Technical paper or economic model. |
| 132 | +* `documentation`: Developer docs or wikis. |
| 133 | +* `source_code`: Code repositories (GitHub, GitLab). |
| 134 | +* `governance`: Voting portals or forums. |
| 135 | +* `audit`: Security audit reports. |
| 136 | +* `social`: Social media profiles (X/Twitter, Discord, Telegram). |
| 137 | +* `browser`: Block explorer links. |
| 138 | +* `exchange`: Direct links to trading pairs on DEXs or CEXs (e.g., Uniswap Pool, Binance Spot). |
| 139 | +* `bridge`: Interfaces allowing users to bridge this asset across chains. |
| 140 | + |
| 141 | +#### `locations` (Cross-Chain Discovery) |
| 142 | +This field allows an asset to declare its "peer" contracts on other networks. The value MUST be an array of valid [CAIP-19] strings. |
| 143 | +* Example: A `USDT` token on Ethereum mainnet can list its representations on BNB Chain and Solana in this field. |
| 144 | +* This enables wallets to aggregate balances of the "same" asset across chains without relying on centralized bridge mappings. |
| 145 | + |
| 146 | +## Example |
| 147 | + |
| 148 | +```json |
| 149 | +{ |
| 150 | + "name": "ICPanda", |
| 151 | + "symbol": "PANDA", |
| 152 | + "decimals": 8, |
| 153 | + "image": "https://panda.fans/_assets/logo.svg", |
| 154 | + "description": "Building the open-source stack for AI agents to remember, transact, and evolve as first-class citizens in Web3.", |
| 155 | + "external_url": "https://panda.fans", |
| 156 | + "links": [ |
| 157 | + { |
| 158 | + "name": "Twitter", |
| 159 | + "url": "https://x.com/ICPandaDAO", |
| 160 | + "rel": "social" |
| 161 | + }, |
| 162 | + { |
| 163 | + "name": "Source Code", |
| 164 | + "url": "https://github.com/ldclabs/ic-panda", |
| 165 | + "rel": "source_code" |
| 166 | + }, |
| 167 | + { |
| 168 | + "name": "ICPSwap", |
| 169 | + "url": "https://app.icpswap.com/swap/pro?input=ryjl3-tyaaa-aaaaa-aaaba-cai&output=druyg-tyaaa-aaaaq-aactq-cai", |
| 170 | + "rel": "exchange" |
| 171 | + }, |
| 172 | + { |
| 173 | + "name": "Official Bridge", |
| 174 | + "url": "https://1bridge.app/?token=PANDA", |
| 175 | + "rel": "bridge" |
| 176 | + } |
| 177 | + ], |
| 178 | + "locations": [ |
| 179 | + "icp:1/token:druyg-tyaaa-aaaaq-aactq-cai", |
| 180 | + "eip155:56/bep20:0xe74583edaff618d88463554b84bc675196b36990", |
| 181 | + "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:PANDAvvWniWYKRbrCYQEAyeSJ5uUk1nc49eLqT6yQyL" |
| 182 | + ] |
| 183 | +} |
| 184 | +``` |
| 185 | + |
| 186 | +## Rationale |
| 187 | + |
| 188 | +### URI-First for Visuals |
| 189 | +We opted for a single `image` URI string rather than a complex object containing thumbnails or themes. Modern UI frameworks and CDNs handle image resizing and format negotiation efficiently. Sticking to a single string simplifies the parsing logic for wallets. |
| 190 | + |
| 191 | +### Structured Links vs. Flat Keys |
| 192 | +Arbitrary keys in a JSON object (e.g., `"twitter": "..."`) lead to a chaotic ecosystem where consumers must maintain a mapping of thousands of non-standard keys. Using a structured array with a `rel` property enforces a controlled vocabulary while allowing flexibility for new types in the future. |
| 193 | + |
| 194 | +### Peer-to-Peer Locations |
| 195 | +Existing token lists often treat bridged assets as separate entries. By including `locations`, we embed the "cross-chain graph" directly into the asset's metadata. We use [CAIP-19] because it is the standard for uniquely identifying asset instances in a multi-chain environment. |
| 196 | + |
| 197 | +## Backwards Compatibility |
| 198 | + |
| 199 | +* **ERC-721**: The usage of `name`, `description`, `image`, and `external_url` aligns with the widely adopted OpenSea metadata standard. |
| 200 | +* **Token Lists**: The structure implies that an array of these objects can easily be transformed into a Uniswap-style Token List. |
| 201 | + |
| 202 | +## Security Considerations |
| 203 | + |
| 204 | +1. **Phishing Risks**: Consuming applications (wallets) MUST exercise caution when rendering `external_url` or `links`. We recommend displaying the domain clearly to the user before redirection. |
| 205 | +2. **Image Validation**: Applications should sanitize SVG images referenced in the `image` field to prevent XSS attacks via embedded scripts. |
| 206 | +3. **Trust**: This standard defines the *format* of the data, not the *validity*. Consumers should verify the source of this JSON (e.g., ensuring it is served from a trusted domain or a verifiable on-chain registry). |
| 207 | + |
| 208 | +## Copyright |
| 209 | + |
| 210 | +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). |
| 211 | + |
| 212 | +[CAIP-19]: https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-19.md |
0 commit comments