Metadata in SmartPy

SmartPy.io
3 min readNov 28, 2020

SmartPy is an intuitive and powerful smart contract development platform for Tezos.

TQ Tezos has introduced, in https://medium.com/tqtezos/contract-metadata-on-tezos-e4c692e2f6ba, the metadata standard for Tezos smart contracts TZip16.

Such metadata can be read and queried with the TZComet explorer.

SmartPy has implemented a few elements to support this initiative: a simple yet very effective way to compute metadata files and a way to easily link to off-chain metadata.

The SmartPy explorer https://SmartPy.io/explorer.html automatically links to TZComet when metadata is found in a contract storage.

The features described in this document are visible on the Metadata template https://smartpy.io/ide?template=metadata.py.

Metadata on Tezos are still a work in progress. We will add new improvements in the future.

Creation of metadata files

init_metadata

To create metadata files, we can use self.init_metadata in the __init__ section.

class MyContract(sp.Contract):
def __init__(self, ...):
self.init_metadata("meta_0", {"foo": "bar"})
self.init_metadata("meta_1", {"a" : 12, "c" : True)
...

It takes a name and a Python expression and creates a JSON of the right form.

With the SmartPy CLI, it creates corresponding files. In https://SmartPy.io/ide, it adds new metadata tabs inside the contract output.

Off-chain views

Metadata can contain off-chain views as described in the TZip16 standard.
They have at most one parameter and can contain doc-strings.

They are introduced by doing:

    @sp.offchain_view
def get_x(self, params):
"""blah blah ' fdsfds " """
sp.result(sp.record(a = self.data.x, b = 12 + params))
@sp.offchain_view
def get_storage(self):
sp.result(self.data.x)
@sp.offchain_view
def get_cst(self):
"""42"""
sp.result(42)

Meta-programming, typing and metadata

When we write such a command in a contract:

self.init_metadata("a_name", expr)

the Python expression expr is split into:

Python dictionaries
They are not supposed to be properly typed and are mapped to JSON dictionnaries.

Python lists
They are not supposed to be properly typed and are mapped to JSON lists.

Off-chain views
They are typed by SmartPy and are converted to the expected structure from TZip-16 standard.

Anything else
Anything else is converted to a SmartPy expression. It is then properly typed and converted to JSON as expected.

A rather complete example

class MyContract(sp.Contract):
def __init__(self, **kargs):
self.init_metadata("meta_0", {"foo": "bar"})
meta_1 = {"some": "string",
"some_dict" : {1, 2, 3},
"a": sp.key("tz1..."),
"foo" : (),
"views" : [self.get_x,
self.get_cst,
self.get_storage],
"f": lambda x : x + 2
}
self.init_metadata("meta_1", meta_1)
self.init(**kargs)
@sp.entry_point
def incr(self):
self.data.x += 1
@sp.entry_point
def change_metadata(self, params):
self.data.metadata[""] = params
@sp.offchain_view
def get_x(self, params):
"""blah blah ' fdsfds " """
sp.result(sp.record(a = self.data.x, b = 12 + params))
@sp.offchain_view
def get_storage(self):
sp.result(self.data.x)
@sp.offchain_view
def get_cst(self):
"""42"""
sp.result(42)
...

Linking of metadata files

It is possible to embed metadata files in a smart contract’s storage but it’s rather inefficient. It’s better to link to such a file by, e.g., storing this file on IPFS.

This is supported by SmartPy as well by including a field metadata of a proper type by doing:

metadata = sp.metadata_of_url(
"ipfs://QmWDcp3BpBjvu8uJYxVqb7JLfr1pcyXsL97Cfkt3y1758o")

A Real Example

Here is a live example on TZComet: KT1CUB3CP67JwhG5JcBVbVX3zq744theGQh5.

--

--

SmartPy.io

An intuitive and effective smart contracts language and development platform for Tezos. In Python.