Skip to content

feat(stacks): add CAIP-19 asset specification#167

Open
whoabuddy wants to merge 1 commit intoChainAgnostic:mainfrom
aibtcdev:feat/stacks-caip19
Open

feat(stacks): add CAIP-19 asset specification#167
whoabuddy wants to merge 1 commit intoChainAgnostic:mainfrom
aibtcdev:feat/stacks-caip19

Conversation

@whoabuddy
Copy link
Contributor

Summary

This PR adds a comprehensive CAIP-19 specification for Stacks token assets, addressing the feedback from #68.

  • Adds stacks/caip19.md with support for SIP-010 (fungible) and SIP-009 (non-fungible) tokens
  • Updates stacks/README.md to reference CAIP-19

Relationship to #68

This is an updated implementation that addresses all review feedback from #68:

Original Concern Resolution
Undocumented .contract syntax Clear explanation of three components: {address}.{contract}.{token-name}
Incomplete documentation Complete Rationale, Syntax, RegEx, Semantics, Examples sections
Case sensitivity Dedicated subsection explaining address normalization vs case-sensitive contract/token names

Key Design Decisions

Asset Reference Format:

{address}.{contract}.{token-name}
  • Uses . as separator (CAIP-19 compliant, since : is not permitted in asset_reference)
  • Includes token name for precise identification (Stacks contracts can define multiple tokens)
  • Documents relationship to Clarity's native :: syntax

Namespaces:

Namespace Description
sip010 Fungible tokens (SIP-010, analogous to ERC-20)
sip009 Non-fungible tokens (SIP-009, analogous to ERC-721)

Examples (verified on-chain):

# sBTC fungible token
stacks:1/sip010:SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token.sbtc-token

# Megapont Ape Club NFT #4
stacks:1/sip009:SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.megapont-ape-club-nft.Megapont-Ape-Club/4

Test plan

  • Syntax follows CAIP-19 specification (no colons in asset_reference)
  • Examples verified against Hiro API for on-chain accuracy
  • Asset reference lengths within 128 character limit
  • All reference links valid

References

🤖 Generated with Claude Code

Adds comprehensive CAIP-19 specification for Stacks token assets,
supporting SIP-010 fungible tokens and SIP-009 non-fungible tokens.

Asset reference format: {address}.{contract}.{token-name}

This addresses the feedback from PR ChainAgnostic#68 including:
- Clear documentation of all syntax components
- Case sensitivity handling (addresses vs contract/token names)
- Complete RegEx validation patterns
- Semantics section for each token type

Examples verified against on-chain data (sBTC, Megapont Ape Club).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@whoabuddy
Copy link
Contributor Author

cc @kyranjamie as well!

whoabuddy added a commit to aibtcdev/docs that referenced this pull request Jan 28, 2026
Address review feedback:
- Flatten sidebar to one level (no nested Reference group)
- Remove redundant reference index page

Directory improvements:
- AIBTC services pattern: mainnet on aibtc.com, testnet on aibtc.dev
- Fix endpoint paths: /docs, /dashboard at base route (not subdomains)
- Add Facilitator /health, Biwas /analytics endpoints
- Remove redundant repos section (link to github org instead)
- Remove redundant external resources (fold key links into More section)

Token reference:
- Add Circle Xreserve mention for USDCx
- Link to Stacks bridging docs
- Link to our CAIP-19 PR (ChainAgnostic/namespaces#167)

Network reference:
- Fix dashboard/docs paths (at base route, not subdomains)

Homepage:
- Cleaner quick reference tables
- Condensed community links

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
whoabuddy added a commit to aibtcdev/docs that referenced this pull request Jan 28, 2026
* docs: restructure as canonical reference layer

Replace tutorial/guide content with reference documentation that ties
together the AIBTC ecosystem. Landing page (aibtc.com) handles getting
started; docs.aibtc.com is now the "phone book" for looking things up.

New structure:
- /directory/ — Services, tools, SDKs, templates, repositories
- /reference/tokens/ — Contract addresses, CAIP identifiers, decimals
- /reference/networks/ — Mainnet/testnet configs, API endpoints
- /glossary/ — Term definitions (unchanged)

Removed:
- /guides/what-is-x402/ — Landing page covers this better
- /guides/services/ — Replaced by /directory/
- /guides/tokens/ — Replaced by /reference/tokens/

Homepage redesigned as navigation hub with quick reference tables.

Closes #2

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* docs: flatten navigation and refine content

Address review feedback:
- Flatten sidebar to one level (no nested Reference group)
- Remove redundant reference index page

Directory improvements:
- AIBTC services pattern: mainnet on aibtc.com, testnet on aibtc.dev
- Fix endpoint paths: /docs, /dashboard at base route (not subdomains)
- Add Facilitator /health, Biwas /analytics endpoints
- Remove redundant repos section (link to github org instead)
- Remove redundant external resources (fold key links into More section)

Token reference:
- Add Circle Xreserve mention for USDCx
- Link to Stacks bridging docs
- Link to our CAIP-19 PR (ChainAgnostic/namespaces#167)

Network reference:
- Fix dashboard/docs paths (at base route, not subdomains)

Homepage:
- Cleaner quick reference tables
- Condensed community links

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
### Token ID (NFTs)

For non-fungible tokens (SIP-009), an optional token ID can be appended after a forward slash (`/`) to identify a specific token instance.
Token IDs are typically unsigned integers starting from 1, as returned by the contract's `get-last-token-id` function.
Copy link
Collaborator

@bumblefudge bumblefudge Feb 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this say "typical starting from 1 and ranging to a maximum value, which can be attained querying for that contract with the ... function."?

that "typically" making me curious what else to expect from these integers! can tokens be destroyed or deleted, causing a gap in the counter? can a contract get fancy and only number with odd integers? etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair questions! I think I found the discrepancy looking closer at the SIP-009 spec and the underlying define-non-fungible-token function in Clarity.

At the Clarity language level the built-in function define-non-fungible-token accepts different types. The example in the docs uses a Clarity (buff 50).

In SIP-009 it's not explicitly written that integers are required but in the language for get-last-token-id we see the comment indicates limited to uint range and expected response is uint:

(define-trait nft-trait
  (
    ;; Last token ID, limited to uint range
    (get-last-token-id () (response uint uint)) ;; <-- here
    ;; URI for metadata associated with the token
    (get-token-uri (uint) (response (optional (string-ascii 256)) uint))
     ;; Owner of a given token identifier
    (get-owner (uint) (response (optional principal) uint))
    ;; Transfer from the sender to a new principal
    (transfer (uint principal principal) (response bool uint))
  )
)

SIP-009 also hints at sequential ordering in the Last Token ID section:

The returned ID can be used as the upper limit when iterating through all NFTs.

At the Clarity level in order to use a defined trait a contract is required to declare it, then implement the function name and function return value. The code between is an open question and indexers use SIP-009 as the spec to evaluate and determine if SIP-009 contracts are valid.

That should rule out anyone doing funny things with the code like those examples and one of the beautiful things about Clarity source being readily available on-chain.

Does that fully answer your questions?

token_id: [1-9][0-9]{0,38}
```

Note: Stacks mainnet addresses start with `SP` or `SM`, while testnet addresses start with `ST` or `SN`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there any case in which stacks:1/sip0009:ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM is valid, or are consumers recommended to always validate that the curtains match the drapes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No that would not be a valid identifier it was just helpful info for reference.

## Backwards Compatibility

This specification supersedes the approach proposed in [PR #68][], which used `sip9` and `sip10` namespaces without the token name component.
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.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we're all learning together! 🙌

Copy link
Collaborator

@bumblefudge bumblefudge left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great! Other than clarifying the nft index number, I'd say this is ready to go!

@whoabuddy
Copy link
Contributor Author

Added clarifications - lmk if anything else is needed on my side!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants