Events

A contract may emit events throughout its execution. Each event contains the following fields:

  • from_address: address of the contract emitting the events

  • keys: a list of field elements

  • data: a list of field elements

The keys can be used for indexing the events, while the data may contain any information that we wish to log (note that we are dealing with two separate lists of possibly varying size, rather than a list of key-value pairs).

Emitting events

Events can be defined in a contract using the @event decorator. Once an event E has been defined, the compiler automatically adds the function E.emit(). The following example illustrates how an event is defined and emitted:

#[event]
fn Transfer(from: ContractAddress, to: ContractAddress, value: u256) {}
Transfer(12345, 12345, 1)

The emit function emits an event with a single key, which is an identifier of the event, given by \(\text{sn_keccak(event_name)}\), where \(\text{event_name}\) is the ASCII encoding of the event’s name and \(\text{sn_keccak}\) is defined here.

To emit custom keys, one should use the low level emit_event system call:

use starknet::syscalls::emit_event_syscall;

let keys = array!['key', 'deposit'];
let values = array![1, 2, 3];
emit_event_syscall(keys, values).unwrap_syscall();

The above code emits an event with two keys, the strings key and deposit (think of those as identifiers of the event that can be used for indexing) and three data elements 1, 2, 3.

When using the higher level emit syntax, the event’s data may be of complex types, for example:

struct Point:
    member x : felt
    member y : felt
end

@event
func message_received(arr_len : felt, arr: felt*, p: Point):
end

# ...

let (data : felt*) = alloc()
assert data[0] = 1
assert data[1] = 2
let p = Point(3,4)
message_received.emit(2, data, p)

The emitted events are part of the transaction receipt.

Event ABI

The event definition appears in the contract’s ABI. It contains the list of data fields (name and type) and the list of the custom keys (that is, all keys except the event identifier discussed above). Below is an example of an event inside the ABI:

{
  "type": "event",
  "name": "Transfer",
  "inputs": [
    {
      "name": "from",
      "type": "core::starknet::contract_address::ContractAddress"
    },
    {
      "name": "to",
      "type": "core::starknet::contract_address::ContractAddress"
    },
    {
      "name": "value",
      "type": "core::integer::u256"
    }
  ]
}

Event hash

The event hash is given by:

\[h(h(h(h(0,\text{from_address}),\text{keys_hash}),\text{data_hash}),3)\]

Where:

  • \(\text{keys_hash}\), \(\text{data_hash}\) are the hashes of the keys list and data list correspondingly (see array hashing).

  • \(h\) is the Pedersen hash function.

The event hashes are included in the event_commitment field of a block.