NFT spec
When Asteroid Protocol initially launched, there was no way to create collections or to combine specific inscriptions/NFTs into groups. This changed with the launch of NFT collections on March 28, 2024. NFT collections use the following specification:
Specification requirements
Easy to identify which collection any given NFT belongs to
Possible to find all NFTs that belong to a given collection
Collection metadata such as its name, description, and image
NFT metadata such as name, description, image, and traits
Open collection - not all collection NFTs have to be known/minted when creating a collection
Backwards compatible with existing inscriptions
NFTs in Asteroid Context
Asteroid protocol already supports arbitrary data inscription with an option to specify a parent and metadata like name, description and mime type (media type of inscribed content)
Let’s define Generic inscription transaction specification to see all the details of what’s available.
Generic Inscription transaction
Inscription transaction MUST specify Inscription operation, optionally CAN provide Inscription data, and optionally CAN require Inscription fee to be paid
Example inscription operation:
urn:{metaprotocol}:{chain-id}@{version};{operation}${param}={value},{param}={value}
Key | Description | Example |
---|---|---|
metaprotocol | A protocol identifier | inscription |
chain-id | The chain ID for the Cosmos Hub | cosmoshub-4 |
version | The current version | v1 |
operation | A protocol operation | inscribe |
param(s) | Operation params | h=hash |
Inscription data:
Key | Description | Example |
---|---|---|
Parent | Link to the parent | An account address, collection address |
Metadata | Inscription metadata | { “name": "asteroid", "description": "asteroid", "mime": "image/png" } |
Content | Base64 encoded data content | Image, Audio, Text file |
Inscription fee:
Key | Description |
---|---|
Receiver | Fee receiver account address |
Denom | Token denomination |
Amount | Token amount |
IBC Channel | Optional IBC channel |
Create a new Inscription transaction
Inscription operation:
urn:inscription:{chain-id}@v1;inscribe$h={hash}
Key | Value | Description |
---|---|---|
chain-id | cosmoshub-4 | The chain ID for the Cosmos Hub |
version | v1 | The current version |
operation | inscribe | Inscribe new content |
Params:
Param | Description | Restrictions |
---|---|---|
h | The hash of the content being inscribed | Must be SHA-256(base64(JSON metadata) + base64(content)) |
Inscription data:
Key | Value | Description |
---|---|---|
Parent | An account address | Link to the parent |
Metadata | Inscription metadata | |
Content | Image, Audio, Text file | The actual base64 encoded content |
Metadata:
Key | Description | Restrictions |
---|---|---|
Name | Inscription name | |
Description | Inscription description | |
Mime | The media type of inscribed content | |
Explicit content | Explicit content flag (currently not in spec, but I would propose to add it so it could be checked when uploading the image and creating the inscribe transaction) | true/false |
Attributes | List of Inscription traits (see below) |
Inscriptions also support custom "attributes” which can be displayed alongside your artwork. This allows for unique features including rarity traits for collections.
To generate attributes, include them as an array within your metadata:
Here trait_type
is the name of the trait, value
is the value of the trait, and display_type
is an optional field indicating how you would like it to be displayed. For string
traits, you don't have to worry about display_type
.
Collections
Collections enable NFTs to be grouped together and for that information to be verified on-chain. Additionally, it makes it easier to manage these collections by allocating data for them on-chain
To group NFTs, we must first create a Collection NFT whose purpose is to store any metadata related to that collection. A collection is itself, an NFT.
Inscription data / Metadata:
Key | Description | Restrictions |
---|---|---|
Symbol | Collection symbol (i.e. BAYC could be the symbol for Bored Ape Yacht Club) | Must be unique |
Name | Collection name | Must be unique |
Description | Collection description | |
Mime | The media type of the inscribed collection logo | |
Explicit content | Explicit content flag | |
Royalty percentage | Optional royalty. Defaults to creator address or user can specify an overriding payment address. Enforcement happens on marketplace level (marketplaces should honor the creator’s intent). | |
Payment address | Optional royalty payment address | |
Minter | Optional minter address, when minter is different from the creator (for example when minting is done by off-chain service) | |
Optional Twitter URL | ||
Discord | Optional Discord URL | |
Website | Optional Website URL | |
Telegram | Optional Telegram URL |
Associating and Verifying Collection NFTs
To associate NFT with collection we set NFT Inscription data / Parent
to Collection transaction hash
Indexer must verify if NFT is a valid part of the collection since anyone can set the Inscription data / Parent
and pretend their NFT to be part of any collection
NFT is a valid part of the Collection when one of the following conditions is true:
Inscribed by the Collection owner
Contains signature signed with Collection minter private key (details TBD)
Backwards compatibility and Migration of existing inscriptions
All new inscriptions will be inscribed with V2 version
There would be a new operation to perform migration (
migrate
)Migration operation is allowed only once
We support v1, migration is optional
Anyone could migrate their inscription to v2 and change parent to collection or/and add additional metadata like traits
Updates
Add a way to do mass migrations (i.e. how can I update traits for 100 pre-existing NFTs?)
Updating traits on legacy NFTs can only be done once via migration. Only the creator can do it.
Add to front-end a checkbox that says: “I own the rights to publish this image.”
This model would support packs (a collection would have pack subcollections). “Opening the pack” would be at the moment of minting. Or we could explore having the packs on-chain.
Rarity score
Rarity score for a trait = 1 / number of NFTs with the trait value / total number of nfts in the collection Rarity score for a nft = sum of rarity scores of all of its trait value
Math representation:
Last updated