Michelson Encoder

The purpose of the Michelson-Encoder package is to create an abstraction over the Michelson Language. It allows converting Michelson data into javascript-looking objects which are easier to use and reason about.

Its integration into the main Taquito package makes it easier to write the storage when deploying a contract and the parameter when calling a contract entry-point.

How it works?#

There are three main classes in the Michelson Encoder:

  • Token
  • ParameterSchema
  • Schema

Here is a class diagram showing their members, methods, and relations.

A specific token class in the package represents each different Michelson type (i.e., nat, list, pair, or, ...). Each of these classes extends the abstract class Token and needs to implement these four inherited abstract methods:

  • Execute: To convert Michelson data into familiar-looking javascript data
  • Encode: To convert javascript array data to JSON Michelson
  • EncodeObject: To convert javascript object data to JSON Michelson
  • ExtractSchema: To show how the data should be structured in the javascript format

We can reason about Michelson types and data as tree structures. Thus, the methods of the Token class use recursion to iterate over a Michelson parameter and create a specific token for each Michelson type encountered (i.e., each node and leaf of the tree).

The constructors of the ParameterSchema and Schema classes take a MichelsonV1Expression as a parameter (i.e., a Michelson type in JSON format). These two classes have a composition relationship with the Token class as they have a private member named root, which is a Token instance corresponding to the root type of the Michelson parameter. The root is the starting point of the recursive calls.

The Schema class#

In this section, we will use the schema class to represent the storage of a smart contract.

Create a Schema instance#

We can create an instance of Schema representing a contract's storage using the constructor and passing the storage type in Michelson JSON format or using the fromRPCResponse method. This second way allows creating the Schema instance with the script of the contract obtained from the getScript method of the RpcClient class.

Here are examples:

const storageType = {
prim: 'pair',
args: [
{ prim: 'nat', annots: [ '%stored_counter' ] },
{
prim: 'pair',
args: [
{ prim: 'nat', annots: [ '%threshold' ] },
{ prim: 'list', args: [ { prim: 'key' } ], annots: [ '%keys' ] }
]
}
]
};
const storageSchema = new Schema(storageType);

or

const script = await Tezos.rpc.getScript('KT1MTFjUeqBeZoFeW1NLSrzJdcS5apFiUXoB');
const storageSchema = Schema.fromRPCResponse({ script });

The ExtractSchema method#

We can use this method to obtain indications on how to write the storage when deploying a contract.

Here is an example with a contract storage having annotations and a pair at its root. The ExtractSchema method returns an object where the keys are the annotations, and the values show the corresponding type.

Live Editor
Result

When there is no annotation, the keys of the object are indexes starting from 0.

Live Editor
Result

Note that for big_map, an object is returned where the key is the type of the big map key and the value is the type of the big map value.

Live Editor
Result

Here is another example using a complex storage:

Live Editor
Result

The Typecheck method#

We can use the Typecheck method to validate the storage object. The method takes the storage object as a parameter and returns true if the storage object is compliant with the schema type or false. Validation of the properties is done. For example, the key used in the following code snippet is invalid, so the returned value of the Typecheck method is false.

Live Editor
Result

The Encode method#

We use the Encode method to transform data from a javascript object to Michelson data. Here is an example:

Live Editor
Result

The Execute method#

We use the Execute method to transform data from Michelson to a javascript object. Here is an example:

Live Editor
Result

The Execute method takes an optional parameter of type Semantic. It allows overriding the default representation returned by the Michelson Encoder for specific types.

Here is an example for the big_map type: If we have a contract having a big map in its storage, when we fetch the contract's storage with the RPC, the returned value looks like the following { int: big_map_id }. In the Taquito main package, the getStorage method of the ContractProvider class uses the semantic parameter to override the representation of big map in the storage. When we fetch the storage of a contract using Tezos.contract.getStorage('contractAddress'), an instance of the BigMapAbstraction class is returned for the big map instead of its id.

Live Editor
Result

Here is an example for the ticket type:

Live Editor
Result

How the Schema class is used inside Taquito#

The Schema class is internally used in Taquito:

  • When calling Tezos.contract.getStorage(): It allows returning a well-formatted JSON object of the contract storage using the Execute method to convert the Michelson data into familiar-looking javascript data.
  • When fetching a bigmap key with BigMapAbstraction.get() or RpcContractProvider.getBigMapKey(): It transforms the key we want to fetch into Michelson using the EncodeBigMapKey method, and it transforms the fetched value into a javascript object using the ExecuteOnBigMapValue.
  • When deploying a contract: The Encode method allows transforming the javascript object used for the storage into Michelson data.
  • In the tzip16 package: The FindFirstInTopLevelPair method allows finding a value in the storage matching a specified type (in this case, the big map named metadata).

The ParameterSchema class#

The ParameterSchema class is used to represent the smart contract methods. This class is similar to the Schema class except that the Encode method expects flattened parameters instead of a javascript object.

Here is an example:

Live Editor
Result

How the ParameterSchema class is used inside Taquito#

The ParameterSchema class is internally used in Taquito:

  • When we call a method, or a view of a contract using the ContractAbstraction class, the Encode method is used to transform the parameters into Michelson data.
  • In the tzip16 package, when we execute a Michelson view, the Encode method is used to transform the parameters into Michelson data.