Contract events

Contract events provide a way for smart contracts to deliver live information to external applications. This mechanism allows off-chain applications to react to Mavryk contracts execution.

Note

Contract events should not be confused with log events, which are generated by the various Mavkit tools to include information about their execution in their own logs.

This page explains how events can be generated using specific support in the Michelson language. For using events in higher-level languages for smart contracts, consult their own documentation.

Emitting events

Contracts can create event emission operations by invoking the Michelson instruction EMIT. EMIT %tag ty pops an item of type ty off the stack and pushes an operation onto the stack. The type ascription ty is special since annotations in ty are preserved and eventually transmitted in the event so that indexers have a choice to present the event body with appropriate labels. Both the ty type ascription and %tag are optional. If ty is absent, this type is inferred from the type of the top element of the stack. If %tag is absent, no tag is attached to the event.

To actually send out the events, most importantly, the produced operations must be included in the list of operations returned by the contract, along with TRANSFER_TOKEN operations for example.

Upon successful contract execution, the events appearing in the resultant list of operations will be attached, in the order of appearance, to the transaction receipt. There, the events are made ready for consumption by services observing the chain.

Example

Suppose a contract wants to emit events with the following type:

or (nat %int) (string %str)

Then, this contract may generate an event emission operation with the following instructions:

PUSH string "right";
RIGHT nat;
EMIT %notify_client (or (nat %int) (string %str));

Note that the EMIT instruction will emit an event with a tag notify_client. The additional tags int and str, allow indexers to recognise the two variants and present the values with the appropriate variant labels.

Retrieving events

Events successfully emitted can be read off from transaction results.

This is typically achieved by making JSON RPCs to the block service. It will return a list of operations, each including the event entries with the information above.

Here is a sample result from a call, corresponding to the example above.

{
  "protocol": "ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK",
  "hash": "opNX59asPwNZGu2kFiHFVJzn7QwtyaExoLtxdZSm3Q3o4jDdSmo",
  // ... fields elided for brevity
  "contents": [
    {
      "kind": "transaction",
      // ... fields elided for brevity
      "metadata": {
        // ... fields elided for brevity
        "internal_operation_results": [
          {
            "kind": "event",
            // ... fields elided for brevity
            "source": "KT1M1ynE3YXkM7qLZoMppq6szMbBvxX9yQVL",
            "nonce": 0,
            "type": {
               "prim": "or",
               "args": [
                 {
                   "prim": "nat",
                   "annots": [
                     "%int"
                   ]
                 },
                 {
                   "prim": "string",
                   "annots": [
                     "%str"
                   ]
                 }
               ]
            },
            "tag": "notify_client",
            "payload": {
              "prim": "Right",
              "args": [
                {
                  "string": "right"
                }
              ]
            },
            "result": {
              "status": "applied",
              "consumed_milligas": "1000000"
            }
          }
        ]
      }
    }
  ]
}

Note that the operation produced by EMIT does not constitute a call to any other contract.