Operations
The final stack after a Tezos contract execution is a pair containing a new storage and a list of operations. Common types of operations that smart contracts create include:
- Transfers (calling a smart contract or transferring tez to an account)
- Deploying (originating) a smart contract
- Changing the delegation for the current smart contract
- Emitting an event
For this reason, LIGO entrypoints always return a list of operations and the new state of the contract storage. The list can include any number of operations of any type.
As described in Operations on docs.tezos.com, operations do not run immediately when the operation object is created.
Instead, operations are added to a stack of operations to run after the code of the entrypoint is complete.
For example, if a contract checks its balance with the Tezos.Next.get_balance
function, creates an operation to transfer tez to another account, and then checks its balance again in the same entrypoint execution, the balance is the same because the transfer operation has not run yet.
For more detailed examples, see Operations on docs.tezos.com.
There are no literal values of type operation.
Instead, such values are created using the following functions from the standard library: Tezos.Next.Operation.transaction
(transfer), Tezos.Next.Operation.create_contract
(origination), Tezos.Next.Operation.set_delegate
(delegation), and Tezos.Next.Operation.Emit
(emission of event).
For the operation to run, these operation values must be included in the list of operations returned at the end of the entrypoint code.
Creating transactions
The Tezos.Next.Operation.transaction
function creates a transaction operation, which can be a call to a smart contract (including the same contract) or a transfer of tez to a user account (implicit account).
Its parameters are:
- The parameter to pass
- The amount of tez to send
- The address to call
Sending tez
To send tez to a user account, pass unit
as the parameter and the address of the account as the address to call, as in this example, which sends 5 tez to the account that calls it:
Calling a contract
To call another contract, you must get the parameter to pass to the contract, which includes the entrypoint, if the contract uses them.
The following example shows two contracts, A and B.
B stores contract A's address and calls its entrypoints.
To get the correct parameter for the transaction, contract B uses the parameter_of
keyword to create a parameter that represents a call to contract A's entrypoints.
If you don't have the LIGO code of the contract to use the parameter_of
keyword, you can often get the information to call the contract from the code of the deployed contract.
For example, contract A in the previous example compiles to this Michelson code:
Michelson contracts don't have separate code for each entrypoint; instead, they accept a parameter that indicates which code to run.
In most cases, the parameter is annotated with the names of the entrypoints from the source code, whether that source code is in LIGO or another high-level Tezos language.
In this case, the annotations %sub
and %add
indicate the parameters to pass to run the code from the sub
and add
entrypoints from the source code.
LIGO can use these annotations to parse the parameter and format the call to the contract.
For example, this contract uses the Tezos.Next.get_entrypoint
function to create a contract address that includes the parameter that indicates the entrypoint.
Then it passes the parameter value for the entrypoint without the entrypoint name as the first parameter of the Tezos.Next.Operation.transaction
function:
If you don't have the source code or annotated parameter of the target contract, you must create the parameter as described in Interoperability.
For example, the parameter of contract A minus the annotations looks like this:
This code means that the contract accepts the parameter (Left int)
or (Right int)
, which correspond to the sub
and add
entrypoints in contract A.
For example, to pass 5 to the code for the sub
entrypoint, the client passes (Left 5)
to the contract.
You can construct this parameter in LIGO code with the michelson_pair
and michelson_or
types.
In this case, the parameter is a Michelson option type that takes a M_left
or M_right
value.
For example, to create the parameter (Left 5)
, use this code:
This example contract uses this method to construct the parameter for contract A from the Michelson value and then uses that parameter to call it:
For information about constructing more complicated parameters, see Interoperability.
Originating contracts
The Tezos.Next.Operation.create_contract
function creates an operation to originate a contract.
Its parameters are:
- The code of the new contract as a function
- The delegate for the new contract, as an option
- The amount of tez for the contract's initial balance
- The initial storage value for the contract
The Tezos.Next.Operation.create_contract
function returns the operation and the address of the new contract.
However, a contract cannot originate a contract and call it in the same entrypoint execution because the origination operation must run first, and as described previously, operations do not run until the entrypoint execution is complete.
Calling the Tezos.Next.get_contract_opt
function on that address returns None
until the new contract is actually originated.
This example originates a simple contract:
Changing delegation
The Tezos.Next.Operation.set_delegate
function creates an operation that changes the delegate for the current contract.
Its parameter is an option with the public key hash of the new delegate or None
to withdraw delegation.
The operation (not the function itself) fails if the new key hash is the same as the current delegate or is not registered as a delegate.
Emitting events
The Tezos.Next.Operation.Emit
function creates an event emission operation.
Its parameters are the tag for the event and the payload for the event.
For more information about events, see Events.