Skip to content
On this page

Operations

In order to interact with other contracts and accounts so-called operations can be emitted. In SmartPy each such operation is of type sp.operation.

Note on operation execution

During the execution of an entrypoint, operations (e.g. sp.transfer) are not immediately executed. Instead, they are collected in a list (see below). The execution of these operations takes place only after the entrypoint has completed.

This means that changes in e.g. the contract balance are not reflected immediately:

smartpy
@sp.entrypoint
def ep(self, destination):
    b = sp.balance
    sp.transfer(sp.unit, sp.tez(5), destination)
    assert b == sp.balance  # sp.balance is unchanged at this point

Note on operation execution order

Operations are executed in FIFO (First In, First Out) order, which results in a DFS (depth first search) tree execution.

For example, suppose contract A's entrypoint first calls contract B's and then contract C's entrypoint. In turn, B's entrypoint calls one of D's entrypoints. Then the operations are executed in the following order: A, B, D, C

Operation statements

sp.transfer(argument: t, amount: sp.mutez, destination: sp.contract[t]) → 

Calls the contract at destination with argument while transferring amount to it.

smartpy
sp.transfer(100, sp.mutez(0), c)
sp.transfer(42, sp.mutez(0), sp.self_entrypoint("abc"))
sp.send(destination: sp.address, amount: sp.mutez) → 

Sends the specified amount to destination. Fails if destination is not an implicit account or a contract with an entrypoint named "default" that takes a sp.unit argument.

smartpy
sp.send(dest, sp.tez(42))

# equivalent to
sp.transfer((), sp.tez(42), sp.contract(sp.unit, dest).unwrap_some())
sp.create_contract(sp.Contract, delegate: sp.option[sp.public_key_hash], amount: sp.mutez, storage: t) → sp.address

Originates a contract with the given storage and delegate while transferring amount to it. Returns the new contract's address.

smartpy
sp.create_contract(MyContract, None, sp.tez(0), ())
sp.create_contract(MyContract, sp.Some(key_hash), sp.tez(10),
    sp.record(x=42, y="abc"))

A more detailed example:

smartpy
class MyContract(sp.Contract):
    @sp.entrypoint
    def ep(self):
        pass

class Originator(sp.Contract):
    @sp.entrypoint
    def ep(self):
        sp.create_contract(MyContract, None, sp.tez(0), ())
sp.set_delegate(d: sp.option[sp.key_hash]) → 

Sets or removes the contract's delegate.

smartpy
sp.set_delegate(sp.Some(d)) # set the delegate to d
sp.set_delegate(None)       # remove the delegate
sp.emit(event: t, tag="...", with_type=[True|False]) → 

Emits event as an event, optionally tagged with tag. If with_type=True is given the type of event is explicitly given in the compiled Michelson code.

Examples:

smartpy
sp.emit("Hello")
sp.emit("World", tag="mytag")
sp.emit(sp.record(a="ABC", b="XYZ"), tag="mytag2", with_type=True)

Manual operation management

SmartPy keeps a running list of operations in sp.operations. In most cases you don't need to deal with it directly -- the statements described in the previous section simply add new elements to the beginning of this list. At the end of the entrypoint the operations in sp.operations are then executed in reverse order.

In contrast to the staments described above, manually managed operations have to be added explicitly to sp.operations if they are meant to be executed. Otherwise, they will be ignored.

sp.operations  → 

The operation list can be accessed as sp.operations:

smartpy
sp.operations = []  # remove any previously added operations

# Add new operations:
op1 = sp.transfer_operation(100, sp.mutez(0), c)
op2 = sp.transfer_operation(100, sp.mutez(0), c)
sp.operations.push(op1)
sp.operations.push(op2)

# `sp.operations` is now `[op2, op1]`. When the entrypoint finishes,
# it is executed in reverse order: first `op1`, then `op2`

Add a list of operations

The operations in sp.oeprations are executed in reverse order. Therefore, when adding a list of operations to sp.operations, you way want to reverse it first:

smartpy
ops = []
ops.push(sp.transfer_operation(100, sp.mutez(0), c))
ops.push(sp.transfer_operation(200, sp.mutez(0), c))
for op in reversed(ops):
    sp.operations.push(op)
sp.transfer_operation(argument: t, amount: sp.mutez, destination: sp.contract[t]) → sp.operation

Returns a transfer operation.

smartpy
op1 = sp.transfer_operation(100, sp.mutez(0), c)
op2 = sp.transfer_operation(42, sp.mutez(0), sp.self_entrypoint("abc"))
sp.operations.push(op1)
sp.operations.push(op2)
sp.create_contract_operation(sp.Contract, delegate: sp.option[sp.public_key_hash], amount: sp.mutez, storage: t) → sp.record(address=sp.address, operation=sp.operation)

Returns a contract origination operation and the corresponding address.

smartpy
r = sp.create_contract_operation(MyContract, None, sp.tez(0), ())
sp.operations.push(r.operation)
# r.address contains the address of the contract.
sp.set_delegate_operation(d: sp.option[sp.key_hash]) → 

Returns an operation that sets the delegate.

smartpy
op = sp.set_delegate_operation(sp.Some(d))
sp.operations.push(op)