In this chapter, we will stress at the interoperability issue with Michelson which occurs when contracts are interacting between each other. We will see some built-in functions provided in the LIGO language in order to address this topic.
Tezos smart contracts are written in Michelson language. The LIGO transpiler helps developers to produce Michelson scripts. However LIGO data structures might have different representations in Michelson. For this reason, some interoperability issues can occur when contracts communicate between each other.
LIGO allows to define a record (a structure containing many fields) but once transpiled in Michelson this record is transformed in a pair of pairs, and there can be many pairs of pairs representing the same record. Interoperability issues can occur because of this multiplicity of representation.
For example a record containing 3 fields A, B and C could be transpiled into right combed pairs :
or a left combed pairs :
These two representations have different structures.
When interacting with other contracts the representation (left or right combed) must be specified in order to match the required type of the invoked entrypoint. This is done by using some built-in functions of the LIGO language.
Interacting with an other contract
In chapters 28 to 30, we will see in detail the Financial Application standard (called FA2) which allows to create a standardized token contract. This FA2 token contract provides a Transfer entrypoint for transfering the token ownership between users. This entrypoint requires parameters that must respect a right combed representation of Ligo records.
For example, if a third-party contract (called Caller contract) wants to interact with a FA2 token contract (called token contract), it would use the entrypoint Transfer which expects parameters with a right combed representation of Ligo records. So, when the Caller contract sends a transaction to the token contract, it must transform parameters of the called entrypoint into the expected representation.
The snippet of code below is part of the standard FA2 interface, and defines transfer parameters using michelson_pair_right_comb function for specifying the Michelson representation used by the Transfer entrypoint.
We will see in detail the Financial Application standard in chapters 28 to 30.
Let’s go deeper into the Michelson representation and related LIGO helper functions.
Michelson types and annotations
Michelson types consist of ors and pairs, combined with field annotations. Field annotations add contraints on a Michelson type, for example a _pair of (pair (int %foo) (string %bar))_ will only work with the exact equivalence or the same type without the field annotations.
For example, the following pair
will accept these definitions and fail with the ones that does not respect the typing or the order of pair fields:
Entrypoints and annotations
As seen in the chapter Polymorphism, a contract can be called by another contract. The predefined function Tezos.get_entrypoint_opt allows to call a specific entry point of the called contract.
Here is an example. Let’s consider the following “Counter” contract :
The following contract sends a transaction to the “Counter” contract.
⚠️ Notice how we directly use the %left entrypoint without mentioning the %right entrypoint. This is done with the help of annotations. Without annotations it wouldn’t be clear what our int would be referring to.
These annotations work for ors or variant types in LIGO.
Interoperability with Michelson
To interoperate with existing Michelson code or for compatibility with some development tooling, LIGO has two special interoperability types: michelson_or and michelson_pair. These types give the flexibility to model the exact Michelson output, including field annotations.
Take for example the following Michelson type that we want to interoperate with:
To reproduce this type we can use the following LIGO code:
If you don’t want to have an annotation, you need to provide an empty string.
To use variables of type michelson_or you have to use M_left and M_right. M_left picks the left or case while M_right picks the right or case. For michelson_pair you need to use tuples.
Default LIGO output#
By default LIGO translates its datatypes into a alphabetically left balanced tree. So, for example:
will translate to:
Right combed tree output
If you want to change the data representation in Michelson to a location retaining right combed tree, like this:
you can use the layout:comb attribute:
The layout:comb attribute can also be used on record types:
Different Michelson annotations
If the Michelson annotation should be different from the LIGO representation, the annot: attribute can be used. For example:
will result into:
The annot: attribute can also be used on record field annotations:
If the layout:comb and annot: attributes are not adequate enough for your use case, LIGO has more advanced advanced interop features which we will we discuss next.
Manual data structure conversion
If you want to get your hands dirty, it’s also possible to do manual data structure conversion.
The following code can be used as inspiration:
Here is a simple contract that changes the item in storage. The contract possesses a single entry point ChangeItem.
Take a look at the ligo command that sompiles storage to Michelson :
which outputs to:
You need to create item type that will produces such output. Use storage from command below as a hint: