The language used in smart contracts on Tezos is Michelson, a stack-based language. However, this kind of language is not commonly used by developers and as the code becomes complex and longer, it gets increasingly harder to keep readable and clean code in Michelson. However, the Tezos ecosystem provides a number of high level languages, which make smart contracts development as easy as any application development. LIGO is one of these languages.
In this chapter, we will focus on smart contract development with the LIGO language (and particularly the PascaLigo syntax). The most important aspects of LIGO will be covered here.
If you want to learn the complete LIGO syntax, you can take a look at:
- The official Ligolang documentation: a complete reference maintained by the developing team.
- Tezos Academy: a gamified interactive tutorial with 30 examples.
This chapter has been written with a smart contract development approach. Each part starts with an explanation of the LIGO syntax (called LIGO prerequisite sections) that are later used for smart contract development.
The LIGO prerequisite parts can be skipped if you do not want to learn the PascaLigo syntax.
DISCLAIMER: This smart contract is meant for educational purpose only, and is not suitable for any other use. OpenTezos cannot be held responsible for any other use.
In this chapter, a simple raffle example is considered. A raffle is a gambling game, where players buy tickets. The winning ticket is then drawn. In our case, a raffle will be developed in a smart contract with those rules:
- An administrator (with his public address) wants to organize a raffle, which reward is some Tez.
- The administrator pays the reward to the winner with his own funds.
- Anyone can participate in the raffle, and the participation fee is the same for everyone. However, each address can participate only once.
- Each ticket has the same probability of being picked.
- After a given time, defined at the beginning of the raffle, the administrator will close the raffle, and send the reward to the winner.
This raffle can be divided into three steps:
- A raffle is opened, with a reward, for a given time.
- During the allowed time, anyone can buy a raffle ticket.
- The raffle is closed, the winner is randomly selected and rewarded with the prize.
Only one raffle session can be ongoing.
Some choices have been made for educational purposes.
About the word ticket: A ticket is a reserved word in Michelson and LIGO, introduced by the Edo protocol. In this chapter, the word ticket only refers to a raffle ticket.
When developing smart contracts, two tools are extremely useful:
- a LIGO syntax support for your IDE
- a LIGO compiler
These two tools will point out syntax errors and type-checking errors. However, it is recommended to compile aLigosmart contract as often as possible. The compilation will detect errors that the IDE linter won't. Thus, errors will be found early and should be more easily addressed.
We're about to see everything that is required to create an empty smart contract:
- Types, built-in types
- Constants, Variables
- Introduction to functions
- main function -Ligocompilation
A Tezos smart contract has three parts:
- parameter: possible invocations (function calls) of the smart contract.
- storage: persistent on-chain data structure. Note that anyone can read this, but only the contract can change it.
- code: a sequence of Michelson instructions to be executed when invoking a smart contract.
Compiling a LIGO smart contract will provide us all three parts.
Let's get started! The first step is to create a .ligo file. Let's create a file called
raffle.ligo which will contain a minimaly viable contract.
LIGO is strongly and statically typed. This means that the compiler checks how a contract processes data, ensuring that each function's expectations are met. If it passes the test, the contract will not fail at run-time due to some inconsistent assumptions on the data. This is called type-checking.
LIGO types are built on top of the Michelson's type system.
LIGO supports all Michelson types, from basic primitives (such as
int) to composite types (such as
map), including contract-specific types (such as
You can find all built-in types on the LIGO gitlab.
Below is a table of the most used built-in types. Most of them will be used in the raffle smart contract:
|carries no information|
|value of some type or none|
|Sequence of character|
|Address of an implicit account|
|Positive or negative integer|
|Amount in tz or mutez|
|Boolean: true or false|
|Timestamp (bakers are responsible for providing the given current timestamp)|
|Sequence of bytes|
|List definition. The same element can be found several times in a list|
|Set definition. The same element cannot be found several times in a list|
|Map an element of type |
|Map an element of type |
As you may have noticed, there is no
floatis not deterministic as its precision depends on the hardware that it runs on.
Type aliasing consists in giving a new name to a given type when the context calls for a more precise name.
It can be used to express our intent more clearly: for instance, a
coordinates type defined by a tuple of two integers is meaningful than just using a tuple.
Tuples will be explained later.
It is also helpful to define a type for complex structures, such as the expected input and return of a function or the contract storage.
Constants are by design immutable, which means they can only be assigned once, at their declaration. A constant is defined by a name, a type, and a value:
Variables, unlike constants, are mutable. They cannot be declared in a global scope, but they can be declared and used within functions or as function parameters.
⚠️ The assignment operator is different:
:= for variables, instead of
= for constants.
As in many other language, LIGO allows to create functions. There are several ways to define a function, but the header is always the same:
Functions will be detailed below. At this point, since the main function does nothing, it will use a blockless function definition.
Every LIGO smart contract must define a
main function. This
main function defines operations and updates the contract storage, depending on the contract parameter. It takes two parameters, the contract parameter and the on-chain storage, and returns a pair made of a list of operations and a (new) on-chain storage.
FIGURE 1: Main function
The contract parameter and storage type are up to the contract designer, but the type for the list of operations is not.
The return type of the
main function is as follows (assuming that the
storage type has already been defined elsewhere).
TheLigocode above should now compile with this command:
If the compilation is successful, the output will be the Michelson code of the contract.
It is recommended to run this command as often as possible to check the code syntax and the types.
Now that we have introduced some basic LIGO concepts (
function and the
main function), let's design our Raffle smart contract.
The first step is to define the storage. Contract storage holds the contract data: it can be a single value or a complex structure. The storage definition is a
type instruction. First, the storage will be as simple as possible: empty.
⚠️ The word unit is a reserved word of the language and represents an empty type.
The parameter definition lists all the entrypoints of a smart contract, i.e., the names of the functions that can be called from the exterior.
At this point, the parameter definition will be skipped. It will be defined later on in this chapter.
To define a smart contract without any parameter definition:
The last part of a smart contract is the code definition. A smart contract can execute no instruction, but it must always return two things:
- a list of operations
- the storage
TheLigocompiler expects the smart contract to have at least one function, which is the
main function. It does not have to be named that way but it is good practice to do so:
main function returns return an empty list of operations and the same storage as provided as input.
The raffle smart contract can now be compiled:
The three Michelson parts have an equivalence in LIGO.