Token metadata
INFO
Token metadata should not be confused with contract metadata.
In an FA2 contract, each token ID is related to one token metadata object. The metadata provides information that is not directly used for a contract's operation, such as a description of the token and links to thumbnails that illustrate it. If an FA2 contract contains 150 NFTs, it must contain 150 token metadata objects in a map.
In most cases, metadata objects are stored in the contract itself or in a JSON file stored outside of the blockchain and referenced in the contract.
The FA2 library does not provide a way to store metadata JSON files. Many token creators use the InterPlanetary File System (IPFS) to store metadata in a decentralized way.
SmartPy provides tools to upload metadata to IPFS automatically; see Creating and publishing metadata.
Creating metadata
Token metadata is stored in key-value pairs in the type sp.map[sp.string, sp.bytes]
.
A few of the keys are reserved and predefined by TZIP-12:
""
(empty-string): If the token metadata is hosted somewhere as JSON outside the contract, this key should correspond to the URI of that JSON data.name
: A display name for the token as a UTF-8 stringsymbol
: A short identifier for the token as a UTF-8 string, such as XTZ or EURdecimals
: An integer (converted to a UTF-8 string in decimal) that defines the position of the decimal point in token balances for display purposes
You can add any number of other custom fields.
The library provides the utility function make_metadata
(available only outside the contract) that you can use to create the object with only the three reserved fields, as in this example:
example_md = fa2.make_metadata(
decimals=0,
name="Example token",
symbol="DFA2"
)
If you need more values in the metadata, you can create your own object, as in this example:
def bytes_of_string(s):
return sp.bytes("0x" + s.encode('utf-8').hex())
example_md = ({
"decimals": bytes_of_string("%d" % 0),
"name": bytes_of_string("Example FA2"),
"symbol": bytes_of_string("DFA2"),
"custom_field": bytes_of_string("This is a custom field")
})
Then you pass the metadata object (whether it contains the metadata fields itself or a link to the JSON metadata elsewhere) to the contract's mint
entrypoint, as in this example:
contract.mint(
[
sp.record(metadata=example_md, to_=account.address),
],
_sender=admin,
)
Advanced media
NFTs often include an image, a list of authors, and a lot of other information about the token.
The corresponding keys and values for NFTs are described in the TZIP-16 standard. Most NFT creators add this information to a JSON file, upload that file to IPFS, and reference it in the contract.