Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CHIP-0007: Off-chain metadata format for NFT1 #26

Merged
merged 14 commits into from
Oct 1, 2022
102 changes: 102 additions & 0 deletions CHIPs/chip-will-riches-metadata.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
CHIP Number | 0007
:-------------|:----
Title | Off-chain metadata format for NFT1
Description | A standard for formatting off-chain metadata for NFT1-compliant NFTs on Chia's blockchain
Author | [Will Riches](https://github.com/wriches)
Comments-URI | [https://github.com/Chia-Network/chips/pull/26](https://github.com/Chia-Network/chips/pull/26)
Status | Review (Fast Track)
Category | Process
Sub-Category | Other
Created | 2022-06-25
Requires | 0005
Replaces | None
Superseded-By | None

## Abstract
The Chia NFT1 standard enables an off-chain metadata file to be referenced by Non-Fungible Tokens (NFTs) on chain, along with a hash of the file that ensures its immutability. This CHIP describes a standard format for off-chain metadata files. It is intended to be used with image-based NFTs but could be used with other types of media.

## Motivation
The NFT1 standard does not require compliant NFTs to reference an off-chain metadata file. If an off-chain metadata file **is** used, it is not required to be in any particular file format or conform to a particular data model or schema.

For projects in the Chia ecosystem to be able to create, display and interact with NFTs in a consistent manner, some coordination of metadata file formats is necessary.

## Backwards Compatibility
If this CHIP is accepted and the data format becomes widely used by projects in the Chia NFT ecosystem, it is possible that non-compliant NFTs which have already been minted will not be displayed correctly, or at least may not have their full metadata displayed. However, the same risk is present without this CHIP being put forward, since there would be little standardization.

## Rationale
* For wide compatibility with developers, JSON format was selected.
* To avoid low quality data being used unnecessarily, only a minimal set of fields are required to be compliant with the format.
* A collection object is included, which would result in collection information being duplicated across each NFT in the collection. Although storage is not a large problem since the metadata is off chain, this data structure is not ideal since NFT tools will have to parse collection information from each NFT and potentially deal with mismatches. However, this is seen as an acceptable interim measure until collection information is directly referenced on chain.
* Collection data is optional, but if it is included it must include both a collection `id` and `name` to enable collections to be grouped more easily.

## Specification
The metadata file must be in JSON format. Typically, the metadata file will have a `.json` extension, but this is not required.

In this section, the schema of the root JSON object is described.

### Properties

| Property | Type | Required | Description |
|---------------------|-------------------------|----------|----------------------------------------------------------------------|
| `format` | string | **Yes** | CHIP number of the metadata format Possible values are: `CHIP-0007`. |
| `name` | string | **Yes** | Name of the NFT |
| `description` | string | **Yes** | Description of the NFT |
| `attributes` | [object](#attributes)[] | No | Attributes of the NFT |
| `collection` | [object](#collection) | No | NFT collection information |
| `minting_tool` | string | No | Name or short tag of the minting tool used to create this NFT |
| `sensitive_content` | boolean or string[] | No | Indicator for sensitive content within the NFT |

### `attributes`
Attributes of the NFT

#### Properties

| Property | Type | Required | Description |
|--------------|-------------------|----------|--------------------------------------------------------------------------------------------|
| `trait_type` | integer or string | **Yes** | Name of the NFT attribute |
| `value` | integer or string | **Yes** | Value of the NFT attribute |
| `min_value` | integer | No | Minimum value of the NFT attribute in relation to other NFTs. Only applicable to integers. |
| `max_value` | integer | No | Maximum value of the NFT attribute in relation to other NFTs. Only applicable to integers. |

### `collection`
NFT collection information

#### Properties

| Property | Type | Required | Description |
|--------------|-------------------------|----------|----------------------------------|
| `id` | string | **Yes** | ID of the NFT collection |
| `name` | string | **Yes** | Name of the NFT collection |
| `attributes` | [object](#attributes)[] | No | Attributes of the NFT collection |

#### `attributes`
wriches marked this conversation as resolved.
Show resolved Hide resolved
Attributes of the NFT collection

##### Properties

| Property | Type | Required | Description |
|----------|-------------------|----------|---------------------------------------|
| `type` | integer or string | **Yes** | Name of the NFT collection attribute |
| `value` | integer or string | **Yes** | Value of the NFT collection attribute |


## Reference Implementation
The schema is [made available for consumption as a JSON Schema dialect](../assets/chip-0007/schema.json). The dialect can be used to validate that metadata files are compliant with the schema.

An [example metadata file](../assets/chip-0007/example.json) has also been included.

## Security
Currently, there are no requirements of the metadata's file format or data structure. From a security perspective, introducing a standard format is only a net gain.

This format includes collection information, which itself does not verify the legitimacy of the collection. It is incumbent on NFT tools and services to combine this collection information with verifiable ownership data, such as the DID of the creator. The risk of NFT tools not implementing these checks is not introduced by this format, but it's possible that the availability of collection information in a standard metadata format could infer that this information is verified. This can be prevented by providing clear information and documentation to developers.

## Additional Assets
* JSON Schema dialect: [assets/chip-0007/schema.json](../assets/chip-0007/schema.json)
* Example off-chain metadata file: [assets/chip-0007/example.json](../assets/chip-0007/example.json)

## Copyright
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).




49 changes: 49 additions & 0 deletions assets/chip-0007/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"format": "CHIP-0007",
"name": "Pikachu",
"description": "Electric-type Pokémon with stretchy cheeks",
wriches marked this conversation as resolved.
Show resolved Hide resolved
"minting_tool": "SuperMinter/2.5.2",
"sensitive_content": false,
"attributes": [
wriches marked this conversation as resolved.
Show resolved Hide resolved
{
"trait_type": "Species",
"value": "Mouse"
},
{
"trait_type": "Color",
"value": "Yellow"
},
{
"trait_type": "Friendship",
"value": 50,
"min_value": 0,
"max_value": 255
}
],
"collection": {
"name": "Example Pokémon Collection",
"id": "e43fcfe6-1d5c-4d6e-82da-5de3aa8b3b57",
Copy link
Contributor

Choose a reason for hiding this comment

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

Based on the confusion between series and edition we should add the series information into the collection object here:

"series_number": 1,
"series_total": 10000,

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've added the series_number and series_total properties, but I added them at the document root rather than in the collection object, since I think the collection object should be the same for every NFT within the collection.

Choose a reason for hiding this comment

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

Shouldn't the series_total field be moved to the collection object? It still guarantees that the collection object is the same for every NFT, yet it makes more sense for this field to be there since it is a property of the whole collection.

Copy link
Contributor Author

@wriches wriches Jul 21, 2022

Choose a reason for hiding this comment

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

series_total is not necessarily the same for the whole collection, since you can have multiple series within a single collection. For example, you might have a collection called "Photos of New York", and within that a series of photos of taxis, a series of photos of buildings, etc. Quite often a collection will contain a single series, but not always.

Copy link

@DrakoPensulo DrakoPensulo Jul 24, 2022

Choose a reason for hiding this comment

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

If a collection contains several series/sequences then more than one NFT from that collection may have identical series_number. If, additionally series_total are equal (for these NFTs) then it is not possible to determine which NFT belongs to which series. I see three possible solutions o distinguish sequences within a collection.

  1. Do not allow sequences of the same size within a collection (that is, use series_total to distinguish sequences)
  2. Introduce a new field to metadata, series_id or series_name to distinguish sequences.
  3. Recommend creators to use name of the NFT in a way which allows series identification.
    It seems to me that solution 2 is the best from the point of view of online services dealing with NFTs. Solution 1 seems to be unnecessarily and artificially restrictive. Solution 3 means essentially "do nothing, let creators to deal with that anyway they want". However, it will make automatic aggregation difficult in some case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed that solution 1 is too restrictive and arbitrary. Solution 2 will not be necessary when collections can be handled in a more verifiable manner, such as through Datalayer. If you introduce a series ID into the off-chain metadata file, there's also an argument to introduce an edition ID. Currently, marketplaces verify the collection by using the ID along with the creator DID, but having to do the same for a series ID (and edition ID) and handle conflicts seems to not be worth the effort. It's worth it for collections, but I expect very few collections will make use of multiple series at this point.

Solution 3 is effectively the status quo (it's common for NFTs to be titled as "Chia Friends #123", for example, both in and outside of the Chia ecosystem) and seems like a sensible approach until something like Datalayer is available for collection and series data.

"attributes": [
wriches marked this conversation as resolved.
Show resolved Hide resolved
{
"type": "description",
"value": "Example Pokémon Collection is the best Pokémon collection. Get yours today!"
},
{
"type": "icon",
wriches marked this conversation as resolved.
Show resolved Hide resolved
"value": "https://examplepokemoncollection.com/image/icon.png"
},
{
"type": "banner",
wriches marked this conversation as resolved.
Show resolved Hide resolved
"value": "https://examplepokemoncollection.com/image/banner.png"
},
{
"type": "twitter",
"value": "ExamplePokemonCollection"
},
{
"type": "website",
"value": "https://examplepokemoncollection.com/"
}
]
}
wriches marked this conversation as resolved.
Show resolved Hide resolved
}
125 changes: 125 additions & 0 deletions assets/chip-0007/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
{
"$id": "https://raw.githubusercontent.com/Chia-Network/chips/main/assets/chip-0007/schema.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "CHIP-0007",
"description": "Chia NFT off-chain metadata format",
"type": "object",
"properties": {
"format": {
"type": "string",
"enum": [
"CHIP-0007"
],
"description": "CHIP number of the metadata format"
},
"name": {
"type": "string",
"description": "Name of the NFT"
},
"description": {
"type": "string",
"description": "Description of the NFT"
},
"minting_tool": {
"type": "string",
"description": "Name or short tag of the minting tool used to create this NFT"
},
"sensitive_content": {
"type": [
"boolean",
"array"
],
"description": "Indicator for sensitive content within the NFT",
"items": {
"type": "string",
"description": "List of types of sensitive content within the NFT"
}
},
"attributes": {
"type": "array",
"description": "Attributes of the NFT",
"items": {
"type": "object",
"properties": {
"trait_type": {
"type": [
"integer",
"string"
],
"description": "Name of the NFT attribute"
},
"value": {
"type": [
"integer",
"string"
],
"description": "Value of the NFT attribute"
},
"min_value": {
"type": "integer",
"description": "Minimum value of the NFT attribute in relation to other NFTs. Only applicable to integers."
},
"max_value": {
"type": "integer",
"description": "Maximum value of the NFT attribute in relation to other NFTs. Only applicable to integers."
}
},
"required": [
"trait_type",
"value"
]
}
},
"collection": {
"type": "object",
"description": "NFT collection information",
"properties": {
"name": {
"type": "string",
"description": "Name of the NFT collection"
},
"id": {
"type": "string",
"format": "uuid",
"description": "ID of the NFT collection"
},
"attributes": {
"type": "array",
"description": "Attributes of the NFT collection",
"items": {
"type": "object",
"properties": {
"type": {
"type": [
"integer",
"string"
],
"description": "Name of the NFT collection attribute"
},
"value": {
"type": [
"integer",
"string"
],
"description": "Value of the NFT collection attribute"
}
},
"required": [
"type",
"value"
]
}
}
},
"required": [
"name",
"id"
]
}
},
"required": [
"format",
"name",
"description"
]
}