Skip to content

Latest commit

 

History

History
412 lines (340 loc) · 29.2 KB

zrc-7.md

File metadata and controls

412 lines (340 loc) · 29.2 KB
ZRC Title Status Type Author Created (yyyy-mm-dd) Updated (yyyy-mm-dd)
7 NFT Metadata Standard Implemented Standard Neuti Yoo
noel@zilliqa.com
Elliott Green
elliott@zilliqa.com
Jun Hao Tan
junhao@zilliqa.com
2021-10-11 2022-03-09

Table of Contents

I. What is Metadata and Token URI?

Metadata is data that provides information about other data. Metadata allows NFTs to have additional properties e.g. name, resource, and attributes. The example is the following:

{
  "name": "Creature #101",
  "resources": [
    { "uri": "ipfs://QmZILGa7zXUbixvYJpgkRkaSCYEBtSwgVtfzkoD3YkNsE1" }
  ],
  "attributes": [
    {
      "trait_type": "Background",
      "value": "Black"
    },
    {
      "trait_type": "Eyes",
      "value": "Big"
    },
    {
      "trait_type": "Mouth",
      "value": "Grin"
    }
  ]
}

The above is a JSON blob of data with the metadata for the NFT. It is returned by a token URI which is an IPFS, HTTP, or data URL. The examples are the following:

  • ipfs://QmZIL4tcBsMqLRuCQtPmPe84bpSjrC3Ky7t3JWuHXYB4aA/1
  • ipfs://QmZILw65yBXgyfG2ZBg5TrfB2hPjrDQH3RCQFJGkARStAE
  • ar://ZILsR4OrYvODj7PD3czIAyNJalub0-vdV_JAg5NqA-o
  • https://ipfs.io/ipfs/QmZIL4tcBsMqLRuCQtPmPe84bpSjrC3Ky7t3JWuHXYB4aA/1
  • https://foo.mypinata.cloud/ipfs/QmZILYgURKVnLWBm1aXH1BqKqFgmj7j1K6MWAFTkf9xm8A/1
  • https://creatures-api.zilliqa.com/api/creature/1
  • data:application/json;base64,ewogICJuYW1lIjogIkNyZWF0dXJlICMxMDEiLAogICJyZXNvdXJjZXMiOiBbCiAgICB7ICJ1cmkiOiAiaXBmczovL1FtWklMR2E3elhVYml4dllKcGdrUmthU0NZRUJ0U3dnVnRmemtvRDNZa05zRTEiIH0KICBdCn0=
  • data:application/json,%7B%22name%22%3A%22Creature%20%23101%22%2C%22resources%22%3A%5B%7B%22uri%22%3A%22ipfs%3A%2F%2FQmZILGa7zXUbixvYJpgkRkaSCYEBtSwgVtfzkoD3YkNsE1%22%7D%5D%7D

Token URIs can be space-efficient and gas-efficient with the concatenation of ZRC-6 compliant base URI and token ID. The concatenated token URI is <base_uri><token_id>.

Base URI
ipfs://QmZILCdt3yb6mZitzWBmQr65AW6Wska295Dg9nbS0M3UrI/

When the base URI is the above, the token URIs are the following:

Token ID Token URI
1 ipfs://QmZILCdt3yb6mZitzWBmQr65AW6Wska295Dg9nbS0M3UrI/1
2 ipfs://QmZILCdt3yb6mZitzWBmQr65AW6Wska295Dg9nbS0M3UrI/2
3 ipfs://QmZILCdt3yb6mZitzWBmQr65AW6Wska295Dg9nbS0M3UrI/3

Token URI optimization by using base URI

By using base URI, a ZRC-6 contract state can use less space for token URIs. Let's assume the following contract state contains n token URIs where n is the number of tokens:

"base_uri": "",
"token_uris": {
  "1": "ipfs://QmZILCdt3yb6mZitzWBmQr65AW6Wska295Dg9nbS0M3UrI/1",
  "2": "ipfs://QmZILCdt3yb6mZitzWBmQr65AW6Wska295Dg9nbS0M3UrI/2",
  "3": "ipfs://QmZILCdt3yb6mZitzWBmQr65AW6Wska295Dg9nbS0M3UrI/3",
  "4": "ipfs://QmZILCdt3yb6mZitzWBmQr65AW6Wska295Dg9nbS0M3UrI/4",
  "5": "ipfs://QmZILCdt3yb6mZitzWBmQr65AW6Wska295Dg9nbS0M3UrI/5"
}

This can be optimized by using base_uri as the following:

"base_uri": "ipfs://QmZILCdt3yb6mZitzWBmQr65AW6Wska295Dg9nbS0M3UrI/",
"token_uris": {}

It is space-efficient because the contract state can only contain a base URI, instead of n token URIs. Also, it is gas-efficient since token_uris is not mutated, resulting in less gas cost for minting or burning.

Limitations

However, there are cases where this optimization is not possible e.g., randomized or dynamic minting.

Note that a token can have its own token URI when a base URI cannot be used as the following:

Token ID Token URI
1 ipfs://QmZILCdt3yb6mZitzWBmQr65AW6Wska295Dg9nbS0M3UrI
2 ipfs://QmZILw65yBXgyfG2ZBg5TrfB2hPjrDQH3RCQFJGkARStAE
3 ipfs://QmZILGa7zXUbixvYJpgkRkaSCYEBtSwgVtfzkoD3YkNsE1
"base_uri": "",
"token_uris": {
  "1": "ipfs://QmZILCdt3yb6mZitzWBmQr65AW6Wska295Dg9nbS0M3UrI"
  "2": "ipfs://QmZILw65yBXgyfG2ZBg5TrfB2hPjrDQH3RCQFJGkARStAE"
  "3": "ipfs://QmZILGa7zXUbixvYJpgkRkaSCYEBtSwgVtfzkoD3YkNsE1"
}

Also, it is possible that some tokens use the concatenated URIs while some tokens use their own token URIs as the following:

Token ID Token URI
1 ipfs://QmZILCdt3yb6mZitzWBmQr65AW6Wska295Dg9nbS0M3UrI/1
2 ipfs://QmZILCdt3yb6mZitzWBmQr65AW6Wska295Dg9nbS0M3UrI/2
3 ipfs://QmZILw65yBXgyfG2ZBg5TrfB2hPjrDQH3RCQFJGkARStAE
"base_uri": "ipfs://QmZILCdt3yb6mZitzWBmQr65AW6Wska295Dg9nbS0M3UrI/",
"token_uris": {
  "3": "ipfs://QmZILw65yBXgyfG2ZBg5TrfB2hPjrDQH3RCQFJGkARStAE"
}

In this case, Token ID 1 and Token ID 2 use the concatenated URIs with ZRC-6 base_uri field while Token ID 3 uses its own token URI by using ZRC-6 token_uris field.

II. Abstract

ZRC-7 standardizes the NFT metadata structure.

III. Motivation

The consistent metadata structure can help the NFT creators and builders to handle the NFT metadata more simply.

IV. Specification

A. Metadata Structure

There are two types of metadata structure to be described: collection metadata, token metadata

Type Description Required
Collection Metadata Contract-level metadata for the NFT collection. It is returned by a URI of this format: <base_uri>metadata.json. For example, if ipfs://QmZILGa7zXUbixvYJpgkRkaSCYEBtSwgVtfzkoD3YkNsE1/ is the ZRC-6 compliant base_uri, then collection metadata JSON file is returned by ipfs://QmZILGa7zXUbixvYJpgkRkaSCYEBtSwgVtfzkoD3YkNsE1/metadata.json.

It can be space-efficient to use collection metadata. It's because the redundant data in the token metadata can be stored in the collection metadata instead.

This is optional. If there is no base_uri, the collection metadata cannot be accessed.
Token Metadata Token-level metadata for a specific NFT. It is returned by a token URI e.g., ipfs://QmZILCdt3yb6mZitzWBmQr65AW6Wska295Dg9nbS0M3UrI/1

1. Collection Metadata Structure (Optional)

Collection metadata must be structured as the following:

Property Type Description Required
name String Name of the collection.
description String A human readable description of the collection.
external_url String A URL that points to an external website presenting the collection.
animation_url String A URL to a multi-media attachment for the collection. The examples of file extensions are GLTF, GLB, WEBM, MP4, M4V, OGV, OGG, MP3, WAV, and OGA.

Also, animation_url can be HTML pages for interactive NFTs using JavaScript canvas, WebGL, etc.
Examples

Minimal

{
  "name": "Unique and Diverse Creatures"
}

Basic

{
  "name": "Unique and Diverse Creatures",
  "description": "10,000 unique and diverse creatures living on the blockchain.",
  "external_url": "https://example.com/creature",
  "animation_url": "https://animation.example.com/creature"
}

Other Properties

Note that it is valid to have other properties for several use cases.

{
  "name": "Unique and Diverse Creatures",
  "foo": "bar"
}

2. Token Metadata Structure

Token metadata must be structured as the following:

Property Type Description Required
name String Name of the asset.
resources Array of Objects An array of resources. Each resource has the following properties:

  • uri : String (required)
    An IPFS, HTTP, or data URL which returns the asset's resource. The examples of URIs are the following:
    • ipfs://QmZILGa7zXUbixvYJpgkRkaSCYEBtSwgVtfzkoD3YkNsE1
    • https://example.com/creature/101.png
    • data:image/png;base64,iVBORw0KGgo...

  • mime_type : String (optional)
    A MIME type of the asset's resource (discrete type only). The examples of MIME types are the following:
    • image/png
    • audio/mpeg
    • video/mp4
    • model/3mf
    • font/otf
    • application/pdf

  • integrity : String (optional)
    A Base64 encoded SHA digest of the file pointed by the uri. This is an integrity metadata. For example, if the SHA-256 is the hash function and 8z5D++W8NDHzFm5rY4/JxkXlIlU2cSQ65XjighJVk9U= is the Base64 encoded SHA digest of the resource file, then the integrity is sha256-8z5D++W8NDHzFm5rY4/JxkXlIlU2cSQ65XjighJVk9U=. If uri is a centralized URI, then consider using this property to ensure the integrity of the resource.
attributes Array of Objects An array of attributes. Each attribute has the following properties:

  • trait_type : String (optional)
    The name of the trait.

  • value : String, Number, or Boolean (required)
    The value of the trait. When the value is Number, it should be integer or float.

  • mime_type : String (optional)
    A MIME type of the value (discrete type only). If the value is a URI, then consider using this field.

  • integrity : String (optional)
    A Base64 encoded SHA digest of the file pointed by the value. If the value is a centralized URI, then consider using this field.

  • display_type : String (optional)
    The display type of the trait. If the display type is timestamp, then consider using unix timestamp.
description String A human readable description of the asset.
external_url String A URL that points to an external website presenting the asset.
animation_url String A URL to a multi-media attachment for the asset. The examples of file extensions are GLTF, GLB, WEBM, MP4, M4V, OGV, OGG, MP3, WAV, and OGA.

Also, animation_url can be HTML pages for interactive NFTs using JavaScript canvas, WebGL, etc.
transitions Array of Objects An array of transitions that can be executed by the token owner. Each transition has the following properties:

  • vname : String (required)
    The name of the transition.

  • params : Array of Objects (required)
    An array of parameters. Each parameter has the following properties:
    • type : String (required)
      The type of the parameter.
    • vname : String (required)
      The name of the parameter.
    • default_value : String, Object, Array of Strings, or Array of Objects (optional)
      The default value of the parameter.
Examples

Minimal

{
  "name": "Creature #101",
  "resources": [
    { "uri": "ipfs://QmZILGa7zXUbixvYJpgkRkaSCYEBtSwgVtfzkoD3YkNsE1" }
  ]
}

Basic

{
  "name": "Creature #101",
  "resources": [
    {
      "uri": "ipfs://QmZILGa7zXUbixvYJpgkRkaSCYEBtSwgVtfzkoD3YkNsE1",
      "mime_type": "image/png"
    }
  ],
  "attributes": [
    {
      "trait_type": "Background",
      "value": "Black"
    },
    {
      "trait_type": "Eyes",
      "value": "Big"
    },
    {
      "trait_type": "Mouth",
      "value": "Grin"
    },
    {
      "display_type": "timestamp",
      "trait_type": "Birthday",
      "value": 1546360800
    }
  ]
}
{
  "name": "Sound #101",
  "resources": [
    {
      "uri": "ipfs://QmZILGa7zXUbixvYJpgkRkaSCYEBtSwgVtfzkoD3YkNsE1",
      "mime_type": "audio/mpeg"
    }
  ],
  "attributes": [
    {
      "trait_type": "Cover",
      "value": "https://storage.googleapis.com/sound-prod.appspot.com/sound/101/cover.png",
      "mime_type": "image/png",
      "integrity": "sha256-8z5D++W8NDHzFm5rY4/JxkXlIlU2cSQ65XjighJVk9U="
    }
  ]
}

Resource Integrity

Note that resource is stored on centralized storage.

{
  "name": "Creature #101",
  "resources": [
    {
      "uri": "ipfs://QmZILGa7zXUbixvYJpgkRkaSCYEBtSwgVtfzkoD3YkNsE1"
      "mime_type": "image/png",
    },
    {
      "uri": "https://storage.googleapis.com/creature-prod.appspot.com/creature/101.png"
      "mime_type": "image/png",
      "integrity": "sha256-8z5D++W8NDHzFm5rY4/JxkXlIlU2cSQ65XjighJVk9U="
    }
  ],
}

Description

{
  "name": "Creature #101",
  "resources": [
    { "uri": "ipfs://QmZILGa7zXUbixvYJpgkRkaSCYEBtSwgVtfzkoD3YkNsE1" }
  ],
  "description": "10,000 unique and diverse creatures living on the blockchain."
}

External & Animation URL

{
  "name": "Creature #101",
  "resources": [
    { "uri": "ipfs://QmZILGa7zXUbixvYJpgkRkaSCYEBtSwgVtfzkoD3YkNsE1" }
  ],
  "external_url": "https://example.com/creature/101",
  "animation_url": "https://animation.example.com/creature/101"
}

Transitions

{
  "name": "Creature #101",
  "resources": [
    { "uri": "ipfs://QmZILGa7zXUbixvYJpgkRkaSCYEBtSwgVtfzkoD3YkNsE1" }
  ],
  "transitions": [
    {
      "vname": "Foo",
      "params": [
        {
          "vname": "x",
          "type": "Uint256",
          "default_value": "1"
        }
      ]
    }
  ]
}

Other Properties

Note that it is valid to have other properties for several use cases.

{
  "name": "Creature #101",
  "resources": [
    { "uri": "ipfs://QmZILGa7zXUbixvYJpgkRkaSCYEBtSwgVtfzkoD3YkNsE1" }
  ],
  "id": 101
}
{
  "name": "Creature #101",
  "resources": [
    { "uri": "ipfs://QmZILGa7zXUbixvYJpgkRkaSCYEBtSwgVtfzkoD3YkNsE1" }
  ],
  "properties": {
    "base": "cat",
    "rich_property": {
      "name": "eyes",
      "value": "big",
      "display_value": "Big"
    }
  }
}
{
  "name": "Creature #101",
  "resources": [
    { "uri": "ipfs://QmZILGa7zXUbixvYJpgkRkaSCYEBtSwgVtfzkoD3YkNsE1" }
  ],
  "attributes": [
    {
      "trait_type": "Pupil Color",
      "value": "Deep Sea Green",
      "colors": [
        {
          "name": "Pupil",
          "value": "#07595c"
        }
      ]
    }
  ]
}

V. References

VI. Copyright

Copyright and related rights waived via CC0.