ARC-3: Conventions Fungible/Non-Fungible Tokens
Parameters Conventions for Algorand Standard Assets (ASAs) for fungible tokens and non-fungible tokens (NFTs).
Author | Fabrice Benhamouda |
---|---|
Discussions-To | https://github.com/algorandfoundation/ARCs/issues/3 |
Status | Final |
Type | Standards Track |
Category | ARC |
Created | 2021-08-07 |
Table of Contents
Algorand Standard Asset Parameters Conventions for Fungible and Non-Fungible Tokens
Abstract
The goal of these conventions is to make it simpler for block explorers, wallets, exchanges, marketplaces, and more generally, client software to display the properties of a given ASA.
Specification
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC-2119.
Comments like this are non-normative.
An ARC-3 ASA has an associated JSON Metadata file, formatted as specified below, that is stored off-chain.
ASA Parameters Conventions
The ASA parameters should follow the following conventions:
- Unit Name (
un
): no restriction but SHOULD be related to the name in the JSON Metadata file - Asset Name (
an
): MUST be:- (NOT RECOMMENDED) either exactly
arc3
(without any space) - (NOT RECOMMENDED) or
<name>@arc3
, where<name>
SHOULD be closely related to the name in the JSON Metadata file:- If the resulting asset name can fit the Asset Name field, then
<name>
SHOULD be equal to the name in the JSON Metadata file. - If the resulting asset name cannot fit the Asset Name field, then
<name>
SHOULD be a reasonable shorten version of the name in the JSON Metadata file.
- If the resulting asset name can fit the Asset Name field, then
- (RECOMMENDED) or
<name>
where<name>
is defined as above. In this case, the Asset URL MUST end with#arc3
.
- (NOT RECOMMENDED) either exactly
- Asset URL (
au
): a URI pointing to a JSON Metadata file.- This URI as well as any URI in the JSON Metadata file:
- SHOULD be persistent and allow to download the JSON Metadata file forever.
- MAY contain the string
{id}
. If{id}
exists in the URI, clients MUST replace this with the asset ID in decimal form. The rules below applies after such a replacement. - MUST follow RFC-3986 and MUST NOT contain any whitespace character
- SHOULD use one of the following URI schemes (for compatibility and security): https and ipfs:
- When the file is stored on IPFS, the
ipfs://...
URI SHOULD be used. IPFS Gateway URI (such ashttps://ipfs.io/ipfs/...
) SHOULD NOT be used.
- When the file is stored on IPFS, the
- SHOULD NOT use the following URI scheme: http (due to security concerns).
- MUST be such that the returned resource includes the CORS header
Access-Control-Allow-Origin: *
if the URI scheme is https
This requirement is to ensure that client JavaScript can load all resources pointed by https URIs inside an ARC-3 ASA.
- MAY be a relative URI when inside the JSON Metadata file. In that case, the relative URI is relative to the Asset URL. The Asset URL SHALL NOT be relative. Relative URI MUST not contain the character
:
. Clients MUST consider a URI as relative if and only if it does not contain the character:
.
- If the Asset Name is neither
arc3
nor of the form<name>@arc3
, then the Asset URL MUST end with#arc3
. - If the Asset URL ends with
#arc3
, clients MUST remove#arc3
when linking to the URL. When displaying the URL, they MAY display#arc3
in a different style (e.g., a lighter color). - If the Asset URL ends with
#arc3
, the full URL with#arc3
SHOULD be valid and point to the same resource as the URL without#arc3
.This recommendation is to ensure backward compatibility with wallets that do not support ARC-3.
- This URI as well as any URI in the JSON Metadata file:
- Asset Metadata Hash (
am
):-
If the JSON Metadata file specifies extra metadata
e
(propertyextra_metadata
), thenam
is defined as:am = SHA-512/256("arc0003/am" || SHA-512/256("arc0003/amj" || content of JSON Metadata file) || e)
where
||
denotes concatenation and SHA-512/256 is defined in NIST FIPS 180-4. The above definition ofam
MUST be used when the propertyextra_metadata
is specified, even if its valuee
is the empty string. Python code to compute the hash and a full example are provided below (see “Sample with Extra Metadata”).Extra metadata can be used to store data about the asset that needs to be accessed from a smart contract. The smart contract would not be able to directly read the metadata. But, if provided with the hash of the JSON Metadata file and with the extra metadata
e
, the smart contract can check thate
is indeed valid. -
If the JSON Metadata file does not specify the property
extra_metadata
, thenam
is defined as the SHA-256 digest of the JSON Metadata file as a 32-byte string (as defined in NIST FIPS 180-4)
-
There are no requirements regarding the manager account of the ASA, or its the reserve account, freeze account, or clawback account.
Clients recognize ARC-3 ASAs by looking at the Asset Name and Asset URL. If the Asset Name is
arc3
or ends with@arc3
, or if the Asset URL ends with#arc3
, the ASA is to be considered an ARC-3 ASA.
Pure and Fractional NFTs
An ASA is said to be a pure non-fungible token (pure NFT) if and only if it has the following properties:
- Total Number of Units (
t
) MUST be 1. - Number of Digits after the Decimal Point (
dc
) MUST be 0.
An ASA is said to be a fractional non-fungible token (fractional NFT) if and only if it has the following properties:
- Total Number of Units (
t
) MUST be a power of 10 larger than 1: 10, 100, 1000, … - Number of Digits after the Decimal Point (
dc
) MUST be equal to the logarithm in base 10 of total number of units.
In other words, the total supply of the ASA is exactly 1.
JSON Metadata File Schema
The JSON Medata File schema follow the Ethereum Improvement Proposal ERC-1155 Metadata URI JSON Schema with the following main differences:
- Support for integrity fields for any file pointed by any URI field as well as for localized JSON Metadata files.
- Support for mimetype fields for any file pointed by any URI field.
- Support for extra metadata that is hashed as part of the Asset Metadata Hash (
am
) of the ASA.- Adding the fields
external_url
,background_color
,animation_url
used by OpenSea metadata format.
Similarly to ERC-1155, the URI does support ID substitution. If the URI contains {id}
, clients MUST substitute it by the asset ID in decimal.
Contrary to ERC-1155, the ID is represented in decimal (instead of hexadecimal) to match what current APIs and block explorers use on the Algorand blockchain.
The JSON Metadata schema is as follows:
{
"title": "Token Metadata",
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Identifies the asset to which this token represents"
},
"decimals": {
"type": "integer",
"description": "The number of decimal places that the token amount should display - e.g. 18, means to divide the token amount by 1000000000000000000 to get its user representation."
},
"description": {
"type": "string",
"description": "Describes the asset to which this token represents"
},
"image": {
"type": "string",
"description": "A URI pointing to a file with MIME type image/* representing the asset to which this token represents. Consider making any images at a width between 320 and 1080 pixels and aspect ratio between 1.91:1 and 4:5 inclusive."
},
"image_integrity": {
"type": "string",
"description": "The SHA-256 digest of the file pointed by the URI image. The field value is a single SHA-256 integrity metadata as defined in the W3C subresource integrity specification (https://w3c.github.io/webappsec-subresource-integrity)."
},
"image_mimetype": {
"type": "string",
"description": "The MIME type of the file pointed by the URI image. MUST be of the form 'image/*'."
},
"background_color": {
"type": "string",
"description": "Background color do display the asset. MUST be a six-character hexadecimal without a pre-pended #."
},
"external_url": {
"type": "string",
"description": "A URI pointing to an external website presenting the asset."
},
"external_url_integrity": {
"type": "string",
"description": "The SHA-256 digest of the file pointed by the URI external_url. The field value is a single SHA-256 integrity metadata as defined in the W3C subresource integrity specification (https://w3c.github.io/webappsec-subresource-integrity)."
},
"external_url_mimetype": {
"type": "string",
"description": "The MIME type of the file pointed by the URI external_url. It is expected to be 'text/html' in almost all cases."
},
"animation_url": {
"type": "string",
"description": "A URI pointing to a multi-media file representing the asset."
},
"animation_url_integrity": {
"type": "string",
"description": "The SHA-256 digest of the file pointed by the URI external_url. The field value is a single SHA-256 integrity metadata as defined in the W3C subresource integrity specification (https://w3c.github.io/webappsec-subresource-integrity)."
},
"animation_url_mimetype": {
"type": "string",
"description": "The MIME type of the file pointed by the URI animation_url. If the MIME type is not specified, clients MAY guess the MIME type from the file extension or MAY decide not to display the asset at all. It is STRONGLY RECOMMENDED to include the MIME type."
},
"properties": {
"type": "object",
"description": "Arbitrary properties (also called attributes). Values may be strings, numbers, object or arrays."
},
"extra_metadata": {
"type": "string",
"description": "Extra metadata in base64. If the field is specified (even if it is an empty string) the asset metadata (am) of the ASA is computed differently than if it is not specified."
},
"localization": {
"type": "object",
"required": ["uri", "default", "locales"],
"properties": {
"uri": {
"type": "string",
"description": "The URI pattern to fetch localized data from. This URI should contain the substring `{locale}` which will be replaced with the appropriate locale value before sending the request."
},
"default": {
"type": "string",
"description": "The locale of the default data within the base JSON"
},
"locales": {
"type": "array",
"description": "The list of locales for which data is available. These locales should conform to those defined in the Unicode Common Locale Data Repository (http://cldr.unicode.org/)."
},
"integrity": {
"type": "object",
"patternProperties": {
".*": { "type": "string" }
},
"description": "The SHA-256 digests of the localized JSON files (except the default one). The field name is the locale. The field value is a single SHA-256 integrity metadata as defined in the W3C subresource integrity specification (https://w3c.github.io/webappsec-subresource-integrity)."
}
}
}
}
}
All the fields are OPTIONAL. But if provided, they MUST match the description in the JSON schema.
The field decimals
is OPTIONAL. If provided, it MUST match the ASA parameter dt
.
URI fields (image
, external_url
, animation_url
, and localization.uri
) in the JSON Metadata file are defined similarly as the Asset URL parameter au
.
However, contrary to the Asset URL, they MAY be relative (to the Asset URL).
See Asset URL above.
Integrity Fields
Compared to ERC-1155, the JSON Metadata schema allows to indicate digests of the files pointed by any URI field.
This is to ensure the integrity of all the files referenced by the ASA.
Concretly, every URI field xxx
is allowed to have an optional associated field xxx_integrity
that specifies the digest of the file pointed by the URI.
The digests are represented as a single SHA-256 integrity metadata as defined in the W3C subresource integrity specification.
Details on how to generate those digests can be found on the MDN Web Docs (where sha384
or 384
are to be replaced by sha256
and 256
respectively as only SHA-256 is supported by this ARC).
It is RECOMMENDED to specify all the xxx_integrity
fields of all the xxx
URI fields, except for external_url_integrity
when it points to a potentially mutable website.
Any field with a name ending with _integrity
MUST match a corresponding field containing a URI to a file with a matching digest.
For example, if the field hello_integrity
is specified, the field hello
MUST exist and MUST be a URI pointing to a file with a digest equal to the digest specified by hello_integrity
.
MIME Type Files
Compared to ERC-1155, the JSON Metadata schema allows to indicate the MIME type of the files pointed by any URI field.
This is to allow clients to display appropriately the resource without having to first query it to find out the MIME type.
Concretly, every URI field xxx
is allowed to have an optional associated field xxx_integrity
that specifies the digest of the file pointed by the URI.
It is STRONGLY RECOMMENDED to specify all the xxx_mimetype
fields of all the xxx
URI fields, except for external_url_mimetype
when it points to a website. If the MIME type is not specified, clients MAY guess the MIME type from the file extension or MAY decide not to display the asset at all.
Clients MUST NOT rely on the xxx_mimetype
fields from a security perspective and MUST NOT break or fail if the fields are incorrect (beyond not displaying the asset image or animation correctly). In particular, clients MUST take all necessary security measures to protect users against remote code execution or cross-site scripting attacks, even when the MIME type looks innocuous (like image/png
).
The above restriction is to protect clients and users against malformed or malicious ARC-3.
Any field with a name ending with _mimetype
MUST match a corresponding field containing a URI to a file with a matching digest.
For example, if the field hello_mimetype
is specified, the field hello
MUST exist and MUST be a URI pointing to a file with a digest equal to the digest specified by hello_mimetype
.
Localization
If the JSON Metadata file contains a localization
attribute, its content MAY be used to provide localized values for fields that need it. The localization
attribute should be a sub-object with three REQUIRED attributes: uri
, default
, locales
, and one RECOMMENDED attribute: integrity
. If the string {locale}
exists in any URI, it MUST be replaced with the chosen locale by all client software.
Compared to ERC-1155, the
localization
attribute contains an additional optionalintegrity
field that specify the digests of the localized JSON files.
It is RECOMMENDED that integrity
contains the digests of all the locales but the default one.
Examples
Basic Example
An example of an ARC-3 JSON Metadata file for a song follows. The properties array proposes some SUGGESTED formatting for token-specific display properties and metadata.
{
"name": "My Song",
"description": "My first and best song!",
"image": "https://s3.amazonaws.com/your-bucket/song/cover/mysong.png",
"image_integrity": "sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"image_mimetype": "image/png",
"external_url": "https://mysongs.com/song/mysong",
"animation_url": "https://s3.amazonaws.com/your-bucket/song/preview/mysong.ogg",
"animation_url_integrity": "sha256-LwArA6xMdnFF3bvQjwODpeTG/RVn61weQSuoRyynA1I=",
"animation_url_mimetype": "audio/ogg",
"properties": {
"simple_property": "example value",
"rich_property": {
"name": "Name",
"value": "123",
"display_value": "123 Example Value",
"class": "emphasis",
"css": {
"color": "#ffffff",
"font-weight": "bold",
"text-decoration": "underline"
}
},
"array_property": {
"name": "Name",
"value": [1,2,3,4],
"class": "emphasis"
}
}
}
In the example, the image
field MAY be the album cover, while the animation_url
MAY be the full song or may just be a small preview.
In the latter case, the full song MAY be specified by three additional properties inside the properties
field:
{
...
"properties": {
...
"file_url": "https://s3.amazonaws.com/your-bucket/song/full/mysong.ogg",
"file_url_integrity": "sha256-7IGatqxLhUYkruDsEva52Ku43up6774yAmf0k98MXnU=",
"file_url_mimetype": "audio/ogg"
}
}
An example of possible ASA parameters would be:
- Asset Unit:
mysong
for example - Asset Name:
My Song
- Asset URL:
https://example.com/mypict#arc3
orhttps://arweave.net/MAVgEMO3qlqe-qHNVs00qgwwbCb6FY2k15vJP3gBLW4#arc3
- Metadata Hash: the 32 bytes of the SHA-256 digest of the above JSON file
- Total Number of Units: 100
- Number of Digits after the Decimal Point: 2
IPFS urls of the form
ipfs://QmWS1VAdMD353A6SDk9wNyvkT14kyCiZrNDYAad4w1tKqT#arc3
may be used too but may cause issue with clients that do not support ARC-3 and that do not handle fragments in IPFS URLs.
Example of alternative versions for Asset Name and Asset URL:
- Asset Name:
My Song@arc3
orarc3
- Asset URL:
ipfs://QmWS1VAdMD353A6SDk9wNyvkT14kyCiZrNDYAad4w1tKqT
orhttps://example.com/mypict
orhttps://arweave.net/MAVgEMO3qlqe-qHNVs00qgwwbCb6FY2k15vJP3gBLW4
These alternative versions are less recommended as they make the asset name harder to read for clients that do not support ARC-3.
The above parameters define a fractional NFT with 100 shares.
The JSON Metadata file MAY contain the field decimals: 2
:
{
...
"decimals": 2
}
Example with Relative URI and IPFS
When using IPFS, it is convenient to bundle the JSON Metadata file with other files references by the JSON Metadata file. In this case, because of circularity, it is necessary to use relative URI
An example of an ARC-3 JSON Metadata file using IPFS and relative URI is provided below:
{
"name": "My Song",
"description": "My first and best song!",
"image": "mysong.png",
"image_integrity": "sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"image_mimetype": "image/png",
"external_url": "https://mysongs.com/song/mysong",
"animation_url": "mysong.ogg",
"animation_url_integrity": "sha256-LwArA6xMdnFF3bvQjwODpeTG/RVn61weQSuoRyynA1I=",
"animation_url_mimetype": "audio/ogg"
}
If the Asset URL is ipfs://QmWS1VAdMD353A6SDk9wNyvkT14kyCiZrNDYAad4w1tKqT/metadata.json
:
- the
image
URI isipfs://QmWS1VAdMD353A6SDk9wNyvkT14kyCiZrNDYAad4w1tKqT/mysong.png
. - the
animation_url
URI isipfs://QmWS1VAdMD353A6SDk9wNyvkT14kyCiZrNDYAad4w1tKqT/mysong.ogg
.
Example with Extra Metadata and {id}
An example of an ARC-3 JSON Metadata file with extra metadata and {id}
is provided below.
{
"name": "My Picture",
"description": "Lorem ipsum...",
"image": "https://s3.amazonaws.com/your-bucket/images/{id}.png",
"image_integrity": "sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"image_mimetype": "image/png",
"external_url": "https://mysongs.com/song/{id}",
"extra_metadata": "iHcUslDaL/jEM/oTxqEX++4CS8o3+IZp7/V5Rgchqwc="
}
The possible ASA parameters are the same as with the basic example, except for the metadata hash that would be the 32-byte string corresponding to the base64 string xsmZp6lGW9ktTWAt22KautPEqAmiXxow/iIuJlRlHIg=
.
For completeness, we provide below a Python program that computes this metadata hash:
import base64
import hashlib
extra_metadata_base64 = "iHcUslDaL/jEM/oTxqEX++4CS8o3+IZp7/V5Rgchqwc="
extra_metadata = base64.b64decode(extra_metadata_base64)
json_metadata = """{
"name": "My Picture",
"description": "Lorem ipsum...",
"image": "https://s3.amazonaws.com/your-bucket/images/{id}.png",
"image_integrity": "sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
"image_mimetype": "image/png",
"external_url": "https://mysongs.com/song/{id}",
"extra_metadata": "iHcUslDaL/jEM/oTxqEX++4CS8o3+IZp7/V5Rgchqwc="
}"""
h = hashlib.new("sha512_256")
h.update(b"arc0003/amj")
h.update(json_metadata.encode("utf-8"))
json_metadata_hash = h.digest()
h = hashlib.new("sha512_256")
h.update(b"arc0003/am")
h.update(json_metadata_hash)
h.update(extra_metadata)
am = h.digest()
print("Asset metadata in base64: ")
print(base64.b64encode(am).decode("utf-8"))
Localized Example
An example of an ARC-3 JSON Metadata file with localized metadata is presented below.
Base metadata file:
{
"name": "Advertising Space",
"description": "Each token represents a unique Ad space in the city.",
"localization": {
"uri": "ipfs://QmWS1VAdMD353A6SDk9wNyvkT14kyCiZrNDYAad4w1tKqT/{locale}.json",
"default": "en",
"locales": [
"en",
"es",
"fr"
],
"integrity": {
"es": "sha256-T0UofLOqdamWQDLok4vy/OcetEFzD8dRLig4229138Y=",
"fr": "sha256-UUM89QQlXRlerdzVfatUzvNrEI/gwsgsN/lGkR13CKw="
}
}
}
File es.json
:
{
"name": "Espacio Publicitario",
"description": "Cada token representa un espacio publicitario único en la ciudad."
}
File fr.json
:
{
"name": "Espace Publicitaire",
"description": "Chaque jeton représente un espace publicitaire unique dans la ville."
}
Note that if the base metadata file URI (i.e., the Asset URL) is ipfs://QmWS1VAdMD353A6SDk9wNyvkT14kyCiZrNDYAad4w1tKqT/metadata.json
, then the uri
field inside the localization
field may be the relative URI {locale}.json
.
Rationale
These conventions are heavily based on Ethereum Improvement Proposal ERC-1155 Metadata URI JSON Schema to facilitate interoperobility.
The main differences are highlighted below:
- Asset Name and Asset Unit can be optionally specified in the ASA parameters. This is to allow wallets that are not aware of ARC-3 or that are not able to retrieve the JSON file to still display meaningful information.
- A digest of the JSON Metadata file is included in the ASA parameters to ensure integrity of this file. This is redundant with the URI when IPFS is used. But this is important to ensure the integrity of the JSON file when IPFS is not used.
- Similarly, the JSON Metadata schema is changed to allow to specify the SHA-256 digests of the localized versions as well as the SHA-256 digests of any file pointed by a URI property.
- MIME type fields are added to help clients know how to display the files pointed by URI.
- When extra metadata are provided, the Asset Metadata Hash parameter is computed using SHA-512/256 with prefix for proper domain separation. SHA-512/256 is the hash function used in Algorand in general (see the list of prefixes in https://github.com/algorand/go-algorand/blob/master/protocol/hash.go). Domain separation is especially important in this case to avoid mixing hash of the JSON Metadata file with extra metadata. However, since SHA-512/256 is less common and since not every tool or library allows to compute SHA-512/256, when no extra metadata is specified, SHA-256 is used instead.
- Support for relative URI is added to allow storing both the JSON Metadata files and the files it refers to in the same IPFS directory.
Valid JSON Metadata files for ERC-1155 are valid JSON Metadata files for ARC-3. However, it is highly recommended that users always include the additional RECOMMENDED fields, such as the integrity fields.
The asset name is either arc3
or suffixed by @arc3
to allow client software to know when an asset follows the conventions.
Security Considerations
Not Applicable
Copyright
Copyright and related rights waived via CCO.
Citation
Please cite this document as:
Fabrice Benhamouda, "ARC-3: Conventions Fungible/Non-Fungible Tokens," Algorand Requests for Comments, no. 3, August 2021. [Online serial]. Available: https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0003.md.