A LIGO smart contract is made of a series of constant and function declarations. Only functions having a special type can be called when the contract is activated: we call them entry points. An entry point function takes two parameters, the contract parameter and the on-chain storage, and returns a pair made of a list of operations and a (new) storage value.
A smart contract can export more than one entry point function.
An entry point can be selected by specifying its name when calling the contract.
For example, the following contract exports two functions, named
increment function can be called by passing
Increment (10) to the contract (notice the capitalization of
More examples on how to perform this call are given below.
When the contract is originated, the initial value of the storage is provided. When an entry point is later called, only the parameter is provided by the user, and the blockchain (or testing framework) supplies the current storage value as a second argument.
The type of the contract parameter and the storage are up to the
contract designer, but the type for the list of operations is not.
The return type of an entry point is as follows, assuming that the type
storage has been defined elsewhere. (Note that you can use any type
with any name for the storage.)
The contract storage can only be modified by activating an entry point: given the state of the storage on-chain, an entry point function specifies how to create another state for it, depending on the contract's parameter.
Calling a contract
Using the dry-run command
In order to call the
increment entry point of the smart contract, we can pass the
-m IncDec option to specify the module and the
Increment(...) constructor to specify the entry point (note the capitalization of
In the command above,
0 is the initial
5 is the
Calling an on-chain contract
When a contract is deployed on-chain, the Michelson value for the parameter can be obtained with:
In the command above,
Increment is the (capitalized) name of the entry point to call, and
5 is the
Using the WebIDE
ligo run test command
A LIGO program can instantiate a new contract (or obtain an existing contract from its address),
and call one of its entry points by passing e.g. the parameter
The file above can be run with e.g. the
ligo run test sub-command.
For more control over the contract's API, it used to be possible to declare
one main function called
main, that dispatches the control flow
according to its parameter. When declaring entrypoints using the
@entry annotation, LIGO automatically generates a
but it used to be possible to write such a function by hand instead of using
This feature is now deprecated, future versions of LIGO will not allow the declaration of a single
main function. A workaround is given at the end of this section.
While it is still possible to define a single function called
main and mark it as the sole entry point using
@entry, this is not what most programs should do. The following paragraphs are intended for programs which need more fine control over the behaviour of the entire program than what is possible using the automatic
As an analogy, in the C programming language, the
main function is
the unique main function and any function called from it would be an
Usually, the parameter of the contract is then a variant type, and, depending on the constructors of that type, different functions in the contract are called. In other terms, the unique main function dispatches the control flow depending on a pattern matching on the contract parameter.
In the following example, the storage contains a counter of type
and a name of type
string. Depending on the parameter of the
contract, either the counter or the name is updated.
Workaround for the deprecation of the
In most cases, adding
[@entry] for CameLIGO or
@entry for JsLIGO
before the existing
main function should suffice. However in cases
where it is not possible or desiarable to convert an existing
contract_main contract to the new
@entry format (e.g. generated
code or a code review process that forbids making changes to an
already-audited file), the deprecation can be circumvented by adding a
proxy file which declares a single entry point and calls the existing
main function, as follows:
The contract can then be compiled using the following command:
Notice that to compile a parameter for this contract, now we need to
pass the either
-e proxy or construct a value using the
A LIGO smart contract can query part of the state of the Tezos blockchain by means of built-in values. In this section you will find how those built-ins can be utilised.
Accepting or Declining Tokens in a Smart Contract
This example shows how
failwith can be used to
decline any transaction that sends more tez than
0tez, that is, no
incoming tokens are accepted.
This example shows how
Tezos.get_sender can be used to deny access to an
Note that we do not use
Tezos.get_source, but instead
Tezos.get_sender. In our tutorial about security you can read more about it.
It would be somewhat misleading to speak of "contract calls", as this wording may wrongly suggest an analogy between contract "calls" and function "calls". Indeed, the control flow returns to the site of a function call, and composed function calls therefore are stacked, that is, they follow a last in, first out ordering. This is not what happens when a contract invokes another: the invocation is queued, that is, follows a first in, first out ordering, and the dequeuing only starts at the normal end of a contract (no failure). That is why we speak of "contract invocations" instead of "calls".
It is possible to obtain the behaviour of normal function "calls" using views, which are pure functions that do not modify the callee's on-chain state. However, this section describes inter-contract invocations which are queued, and may modify the callee's state.
The following example shows how a contract can invoke another by emitting a transaction operation at the end of an entrypoint.
The same technique can be used to transfer tokens to an implicit account (tz1, ...): all you have to do is use a unit value as the parameter of the smart contract.
In our case, we have a
counter contract that accepts an action of
parameter, and we have a
proxy contract that accepts the same
parameter type, and forwards the call to the deployed counter