|
| 1 | +--- |
| 2 | +namespace-identifier: stacks-caip19 |
| 3 | +title: Stacks Namespace - Assets |
| 4 | +author: Friedger Müffke (@friedger), Jason Schrader (@whoabuddy) |
| 5 | +discussions-to: https://github.com/ChainAgnostic/namespaces/pull/68 |
| 6 | +status: Draft |
| 7 | +type: Standard |
| 8 | +created: 2023-05-21 |
| 9 | +updated: 2025-01-14 |
| 10 | +requires: ["CAIP-2", "CAIP-10", "CAIP-19"] |
| 11 | +--- |
| 12 | + |
| 13 | +# CAIP-19 |
| 14 | + |
| 15 | +*For context, see the [CAIP-19][] specification.* |
| 16 | + |
| 17 | +## Rationale |
| 18 | + |
| 19 | +In the Stacks ecosystem, token assets are defined within smart contracts written in [Clarity][], a decidable language with native asset primitives. |
| 20 | +A single contract can define multiple fungible tokens (FTs) and non-fungible tokens (NFTs), each identified by a unique name within the contract. |
| 21 | + |
| 22 | +Token assets are uniquely identified by combining the deployer address, contract name, and the token name declared within that contract using `define-fungible-token` or `define-non-fungible-token`. |
| 23 | + |
| 24 | +The Stacks community has established standard interfaces for tokens: |
| 25 | + |
| 26 | +- [SIP-010][]: Fungible Token Standard (analogous to ERC-20) |
| 27 | +- [SIP-009][]: Non-Fungible Token Standard (analogous to ERC-721) |
| 28 | + |
| 29 | +## Syntax |
| 30 | + |
| 31 | +After the [CAIP-2][] namespace+chainID, a slash defines an `asset_namespace` and an `asset_reference`. |
| 32 | + |
| 33 | +### Asset Namespaces |
| 34 | + |
| 35 | +| Namespace | Description | Reference Format | |
| 36 | +| :--- | :--- | :--- | |
| 37 | +| `sip010` | Fungible token ([SIP-010][]) | `{contract-principal}.{token-name}` | |
| 38 | +| `sip009` | Non-fungible token ([SIP-009][]) | `{contract-principal}.{token-name}` | |
| 39 | + |
| 40 | +### Asset Reference Components |
| 41 | + |
| 42 | +The asset reference combines the contract principal with the token identifier: |
| 43 | + |
| 44 | +``` |
| 45 | +{address}.{contract}.{token-name} |
| 46 | +``` |
| 47 | + |
| 48 | +- **address**: A valid Stacks address in [c32check][] encoding (starts with `SP` for mainnet, `ST` for testnet) |
| 49 | +- **contract**: The deployed contract name (1-40 characters, alphanumeric with hyphens and underscores, must start with a letter) |
| 50 | +- **token-name**: The identifier used in the contract's `define-fungible-token` or `define-non-fungible-token` declaration |
| 51 | + |
| 52 | +All three components are separated by periods (`.`). |
| 53 | +The first period separates the address from the contract name (forming the contract principal), and the second period separates the contract principal from the token name. |
| 54 | + |
| 55 | +Note: In Clarity source code, the fully-qualified asset identifier uses `::` as a separator (e.g., `SP...contract::token`). |
| 56 | +For CAIP-19 compatibility, this specification uses `.` as the separator since colons are not permitted in asset references per the [CAIP-19][] specification. |
| 57 | + |
| 58 | +### Token ID (NFTs) |
| 59 | + |
| 60 | +For non-fungible tokens (SIP-009), an optional token ID can be appended after a forward slash (`/`) to identify a specific token instance. |
| 61 | +Token IDs are typically unsigned integers starting from 1, as returned by the contract's `get-last-token-id` function. |
| 62 | + |
| 63 | +## RegEx |
| 64 | + |
| 65 | +The RegEx validation strings are as follows: |
| 66 | + |
| 67 | +``` |
| 68 | +asset_id: asset_type + "/" + token_id (optional for sip009) |
| 69 | +asset_type: chain_id + "/" + asset_namespace + ":" + asset_reference |
| 70 | +chain_id: namespace + ":" + blockchain_id (as defined in CAIP-2) |
| 71 | +
|
| 72 | +asset_namespace: "sip010" | "sip009" |
| 73 | +
|
| 74 | +asset_reference: address + "." + contract_name + "." + token_name |
| 75 | +address: S[PMNT][A-Z0-9]{38,39} |
| 76 | +contract_name: [a-zA-Z][a-zA-Z0-9_-]{0,39} |
| 77 | +token_name: [a-zA-Z][a-zA-Z0-9_-]{0,127} |
| 78 | +
|
| 79 | +token_id: [1-9][0-9]{0,38} |
| 80 | +``` |
| 81 | + |
| 82 | +Note: Stacks mainnet addresses start with `SP` or `SM`, while testnet addresses start with `ST` or `SN`. |
| 83 | + |
| 84 | +### Case Sensitivity |
| 85 | + |
| 86 | +Stacks addresses use [c32check][] encoding, which is case-insensitive but canonically represented in uppercase (as specified in [CAIP-10][]). |
| 87 | +However, contract names and token names in Clarity are case-sensitive. |
| 88 | + |
| 89 | +Implementations SHOULD: |
| 90 | +- Accept addresses in any case but normalize to uppercase for comparison |
| 91 | +- Preserve exact case for contract names and token names as deployed on-chain |
| 92 | + |
| 93 | +Note: The total `asset_reference` (address + contract + token name) must not exceed 128 characters per the [CAIP-19][] specification. |
| 94 | + |
| 95 | +## Semantics |
| 96 | + |
| 97 | +### Fungible Tokens (SIP-010) |
| 98 | + |
| 99 | +Fungible tokens following the [SIP-010][] standard implement a common interface for token transfers, balance queries, and metadata. |
| 100 | +The standard requires implementation of: |
| 101 | + |
| 102 | +- `transfer`: Move tokens between principals |
| 103 | +- `get-balance`: Query token balance for an address |
| 104 | +- `get-total-supply`: Query total token supply |
| 105 | +- `get-name`, `get-symbol`, `get-decimals`: Token metadata |
| 106 | + |
| 107 | +Each fungible token is uniquely identified by its contract principal and the token name declared via `(define-fungible-token <token-name>)`. |
| 108 | + |
| 109 | +### Non-Fungible Tokens (SIP-009) |
| 110 | + |
| 111 | +Non-fungible tokens following the [SIP-009][] standard represent unique digital assets. |
| 112 | +The standard requires implementation of: |
| 113 | + |
| 114 | +- `transfer`: Move NFT ownership |
| 115 | +- `get-owner`: Query current owner of a token ID |
| 116 | +- `get-last-token-id`: Query the highest minted token ID |
| 117 | +- `get-token-uri`: Query metadata URI for a token |
| 118 | + |
| 119 | +Each NFT collection is identified by its contract principal and token name declared via `(define-non-fungible-token <token-name> <token-type>)`. |
| 120 | +Individual tokens within a collection are distinguished by their token ID. |
| 121 | + |
| 122 | +## Examples |
| 123 | + |
| 124 | +``` |
| 125 | +# SIP-010 Fungible Token: sBTC on Mainnet |
| 126 | +stacks:1/sip010:SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token.sbtc-token |
| 127 | +
|
| 128 | +# SIP-009 NFT Collection: Megapont Ape Club on Mainnet |
| 129 | +stacks:1/sip009:SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.megapont-ape-club-nft.Megapont-Ape-Club |
| 130 | +
|
| 131 | +# SIP-009 NFT: Specific Megapont Ape (#4) on Mainnet |
| 132 | +stacks:1/sip009:SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.megapont-ape-club-nft.Megapont-Ape-Club/4 |
| 133 | +
|
| 134 | +# SIP-010 Fungible Token on Testnet |
| 135 | +stacks:2147483648/sip010:ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.my-token.my-ft |
| 136 | +
|
| 137 | +# SIP-009 NFT on Testnet |
| 138 | +stacks:2147483648/sip009:ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.my-nft.my-nft-token/1 |
| 139 | +``` |
| 140 | + |
| 141 | +## Backwards Compatibility |
| 142 | + |
| 143 | +This specification supersedes the approach proposed in [PR #68][], which used `sip9` and `sip10` namespaces without the token name component. |
| 144 | +The updated format provides more precise asset identification by including the token name as declared in the smart contract, which is necessary because a single Stacks contract can define multiple distinct tokens. |
| 145 | + |
| 146 | +## References |
| 147 | + |
| 148 | +- [Clarity Language Reference][Clarity] - Smart contract language documentation |
| 149 | +- [SIP-009][] - Non-Fungible Token Standard |
| 150 | +- [SIP-010][] - Fungible Token Standard |
| 151 | +- [c32check][] - Stacks address encoding |
| 152 | + |
| 153 | +[CAIP-2]: ./caip2.md |
| 154 | +[CAIP-10]: ./caip10.md |
| 155 | +[CAIP-19]: https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-19.md |
| 156 | +[Clarity]: https://docs.stacks.co/clarity/overview |
| 157 | +[SIP-009]: https://github.com/stacksgov/sips/blob/main/sips/sip-009/sip-009-nft-standard.md |
| 158 | +[SIP-010]: https://github.com/stacksgov/sips/blob/main/sips/sip-010/sip-010-fungible-token-standard.md |
| 159 | +[c32check]: https://github.com/stacks-network/c32check |
| 160 | +[PR #68]: https://github.com/ChainAgnostic/namespaces/pull/68 |
| 161 | + |
| 162 | +## Copyright |
| 163 | + |
| 164 | +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). |
0 commit comments