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

ARC-0053 Decentralized, Self-declared, & Verifiable Tokens, Collections, & Metadata #244

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
263 changes: 263 additions & 0 deletions ARCs/arc-0053.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
---
arc: 53
title: Metadata Declarations
description: A specification for a decentralized, Self-declared, & Verifiable Tokens, Collections, & Metadata
author: Kyle Breeding aka krby.algo (@kylebeee)
status: Living
type: Meta
created: 2023-09-12
---

## Abstract

This ARC describes a standard for a self-sovereign on-chain project & info declaration. The declaration is an ipfs link to a JSON document attached to a smart contract with multi-wallet verification capabilities that contains information about a project, including project tokens, FAQ, NFT collections, team members, and more.

## Motivation

In our current ecosystem we have a number of centralized implementations for parts of these vital pieces of information to be communicated to other relevant parties. All NFT marketplaces implement their own collection listing systems & requirements. Block explorers all take different approaches to sourcing images for ASA's; The most common being a github repository that the Tinyman team controls & maintains. This ARC aims to standardize the way that projects communicate this information to other parts of our ecosystem.

We can use a smart contract with multi-wallet verification to store this information in a decentralized, self-sovereign & verifiable way by using custom field metadata & IPFS. A chain parser can be used to read the information stored & verify the details against the verified wallets attached to the contract.

## Specification
The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in <a href="https://datatracker.ietf.org/doc/html/rfc2119">RFC 2119</a>.

This proposal specifies an associated off-chain JSON metadata file, displayed below. This metadata file contains many separate sections and escape hatches to include unique metadata about various businesses & projects. For the purposes of requiring as few files & ipfs uploads as possible the sections are all included within the same file. The file is then added to IPFS and the link saved in a custom field on the smart contract under the key `project`.

| Field | Schema | Description | Required
| --- | --- | --- | --- |
| version | string | The version of the standard that the metadata is following. | true |
| associates | array\<Associate> | An array of objects that represent the associates of the project. | false |
| collections | array\<Collection> | An array of objects that represent the collections of the project. | false |
| tokens | array\<Token> | An array of objects that represent the tokens of the project. | false |
| faq | array\<FAQ> | An array of objects that represent the FAQ of the project. | false |
| extras | object | An object that represents any extra information that the project wants to include. | false |

##### Top Level JSON Example
```json
{
"version": "0.0.2",
"associates": [...],
"collections": [...],
"tokens": [...],
"faq": [...],
"extras": {...}
}
```

### Version
We envision this is an evolving / living standard that allows the community to add new sections & metadata as needed. The version field will be used to determine which version of the standard the metadata is following. This will allow for backwards compatibility & future proofing as the standard changes & grows. At the top level, `version` is the only required field.

### Associates
Associates are a list of wallets & roles that are associated with the project. This can be used to display the team members of a project, or the owners of a collection.

The associates field is an array of objects that contain the following fields:

| Field | Schema | Description | Required
| --- | --- | --- | --- |
| address | string | The algorand wallet address of the associated person | true |
| role | string | A short title for the role the associate plays within the project. | true |


eg:
```json
"associates": [
{
"address": "W5MD3VTDUN3H2FFYJR2NDXGAAV2SJ44XEEDGBWHIZKH6ZZXF44SE7KEPVP",
"role": "Project Founder"
},
...
]
```

### Collections
NFT Collections have no formal standard for how they should be declared. This section aims to standardize the way that collections are declared & categorized. The collections field is an array of objects that contain the following fields:

| Field | Schema | Description | Required
| --- | --- | --- | --- |
| name | string | The name of the collection | true |
| network | string | The blockchain network that the collection is minted on.<br>*Default*: `algorand`<br>*Special*: `multichain` | false |
| prefixes | array\<string> | An array of strings that represent the prefixes to match against the `unit_name` of the NFTs in the collection. | false |
| addresses | array\<string> | An array of strings that represent the addresses that minted the NFTs in the collection. | false |
| assets | array\<uint64> | An array of strings that represent the asset_ids of the NFTs in the collection. | false |
| excluded_assets | array\<uint64> | An array of strings that represent the asset_ids of the NFTs in the collection that should be excluded. | false |
| artists | array\<string> | An array of strings that represent the addresses of the artists that created the NFTs in the collection. | false |
| banner_image | string | An IPFS link to an image that represents the collection.<br>*if set `banner_id` should be unset & vice-versa* | false |
| banner_id | uint64 | An asset_id that represents the collection. | false |
| avatar_image | string | An IPFS link to an image that represents the collection.<br>*if set `avatar_id` should be unset & vice-versa* | false |
| avatar_id | uint64 | An asset_id that represents the collection. | false |
| explicit | boolean | A boolean that represents whether or not the collection contains explicit content. | false |
| royalty_percentage | uint64 | A uint64 with a value ranging from 0-10000 that represents the royalty percentage that the collection would prefer to take on secondary sales. | false |
| properties | array\<CollectionProperties> | An array of objects that represent traits from an entire collection. | false |
| extras | object | An object of key value pairs for any extra information that the project wants to include for the collection. | false |

eg:
```json
"collections": [
{
"name": "My Collection",
"networks": "algorand",
"prefixes": [
"AKC",
...
],
"addresses": [
"W5MD3VTDUN3H2FFYJR2NDXGAAV2SJ44XEEDGBWHIZKH6ZZXF44SE7KEPVP",
...
],
"assets": [
123456789,
...
],
"excluded_assets": [
123456789,
...
],
"artists": [
"W5MD3VTDUN3H2FFYJR2NDXGAAV2SJ44XEEDGBWHIZKH6ZZXF44SE7KEPVP",
...
],
"banner_image": "ipfs://...",
"avatar": 123456789,
"explicit": false,
"royalty_percentage": "750", // ie: 7.5%
"properties": [
{
"name": "Fur",
"values": [
{
"name": "Red",
"image": "ipfs://...",
"image_integrity": "sha256-...",
"image_mimetype": "image/png",
"animation_url": "ipfs://...",
"animation_url_integrity": "sha256-...",
"animation_url_mimetype": "image/gif",
"extras": {
"key": "value",
...
}
},
...
]
}
...
],
"extras": {
"key": "value",
...
}
},
...
]
```

#### Collection Scoping

Not all collections have been consistent with their naming conventions. Some collections are minted across multiple wallets due to prior asa minting limitations. The following fields used together offer great flexibility in creating a group of NFTs to include in a collection. `prefixes`, `addresses`, `assets`, `excluded_assets`. Combined, these fields allow for maximum flexibility for mints that may have mistakes or exist across wallets & dont all conform to a consistent standard.

`prefixes` allows for simple grouping of a set of NFTs based on the beginning part of the ASAs `unit_name`. This is useful for collections that have a consistent naming convention for their NFTs. Every other scoping field modifies this rule.

`addresses` scope down the collection to only include ASAs minted by the addresses listed in this field. This is useful for projects that mint different collections across multiple wallets that utilize the same prefix.

`assets` is a direct entry in the collection for NFTs that dont conform to any of the prefix rules.

`excluded_assets` is a direct exclusion on an NFT that may conform to a prefix but should be excluded from the collection.

`banner_image`, `banner_id`, `avatar_image`, `avatar_id` are all very self explanatory. They allow for a glancable preview of the collection to display on NFT marketplaces, analytics sites & others. Both `banner` & `avatar` field groups should be one or the other, not both. `banner_image` or `banner_id` (likely an ASA id from the creator). `avatar_image` or `avatar_id` (likely an ASA id from the collection).

`explicit` is a boolean that indicates whether or not the collection contains explicit content. This is useful for sites that want to filter out explicit content.

`properties` is an array of objects that represent traits from an entire collection. Many new NFT collections are choosing to use [ARC-19](./arc-0019.md) and mint their NFTs as blank slates. This can prevent sniping but also has the adverse affect of obscuring the trait information of a collection. This field allows for a collection to declare its traits, values, image previews of the trait it references and extra metadata.

#### Collection Properties
| Field | Schema | Description | Required
| --- | --- | --- | --- |
| name | string | The name of the property | true |
| values | array\<CollectionPropertyValue> | An array of objects that represent the values of the property. | true |

#### Collection Property Values
| Field | Schema | Description | Required
| --- | --- | --- | --- |
| name | string | The name of the value | true |
| image | string | An IPFS link to an image that represents the value. | false |
| image_integrity | string | A sha256 hash of the image that represents the value. | false |
| image_mimetype | string | The mimetype of the image that represents the value. | false |
| animation_url | string | An IPFS link to an animation that represents the value. | false |
| animation_url_integrity | string | A sha256 hash of the animation that represents the value. | false |
| animation_url_mimetype | string | The mimetype of the animation that represents the value. | false |
| extras | object | An object of key value pairs for any extra information that the project wants to include for the property value. | false |

### Tokens

Tokens are a list of assets that are associated with the project. This can be used to verify the tokens of a project and for others to easily source images to represent the token on their own platforms.

| Field | Schema | Description | Required
| --- | --- | --- | --- |
| asset_id | uint64 | The asset_id of the token | true |
| image | string | An IPFS link to an image that represents the token. | false |
| image_integrity | string | A sha256 hash of the image that represents the token. | false |
| image_mimetype | string | The mimetype of the image that represents the token. | false |

eg:
```json
"tokens": [
{
"asset_id": 123456789,
"image": "ipfs://...",
"image_integrity": "sha256-...",
"image_mimetype": "image/png",
}
...
]
```

### FAQ

Frequently Asked Questions for the project to address the common questions people have about their project and help inform the community.

| Field | Schema | Description | Required
| --- | --- | --- | --- |
| q | string | The question | true |
| a | string | The answer | true |

eg:
```json
"faq": [
{
"q": "What is XYZ Collection?",
"a": "XYZ Collection is a premiere NFT project that..."
},
...
]
```

### Extras

Custom Metadata for extending & customizing the declaration for your own use cases. This object can be found at several levels throughout the specification, The top level, within collections & within collection property value objects.

| Field | Schema | Description | Required
| --- | --- | --- | --- |
| key | string | The key of the extra information | true |
| value | string | The value of the extra information | true |

eg:
```json
"extras": {
"key": "value",
...
}
```

### Contract Providers

Custom metadata needs to be verifiable and many projects use many wallets as a means of separating concerns. Providers are smart contracts that have the capability of verifying multiple wallets & thus provide evidence to parsers of the authenticity of such data. Providers that support this standard will be listed on the <a href="https://arc.algorand.foundation/">ARC compatibility matrices</a> site.

## Rationale
See the motivation section above for the general rationale.

## Security Considerations
None

## Copyright

Copyright and related rights waived via <a href="https://creativecommons.org/publicdomain/zero/1.0/">CCO</a>.
Loading