Events
An event is a record type that can be logged. Declare it with event, and log it with emit:
import "std/evm";
event Transfer of record {
indexed from : address;
indexed to : address;
amount : uint;
}
storage is record {
balances : map(address, uint);
}
external function send(const to : address; const amount : uint) is {
storage.balances[Evm.sender()] := storage.balances[Evm.sender()] - amount;
storage.balances[to] := storage.balances[to] + amount;
emit Transfer { from = Evm.sender(); to = to; amount = amount; };
}Events compile to standard EVM logs. The first topic is the event signature's hash, so Transfer above is the ERC-20 Transfer(address,address,uint256) event.
Indexed fields
indexed fields become topics that clients can filter on. An event can have at most three:
event Foo of record {
indexed a : uint;
indexed b : uint;
indexed c : uint;
indexed d : uint;
}
storage is record {
n : uint;
}
external function go() is { skip }event `Foo` declares 4 indexed fieldsA field that isn't indexed can hold any ABI value, nested lists and records included. The data fields are ABI-encoded, as a function's arguments are.
As in Solidity, an indexed string or bytes is logged as the keccak256 of its bytes. An indexed list, record, or tuple is logged as the keccak256 of its in-place encoding: each member padded to a word, with no offsets or lengths:
import "std/evm";
event Renamed of record {
indexed name : string;
by : address;
}
storage is record {
name : string;
}
external function rename(const name : string) is {
storage.name := name;
emit Renamed { name = name; by = Evm.sender(); };
}An anonymous event logs no signature topic, as Solidity's anonymous does. That leaves room for four indexed fields, and costs one topic less, but a client can only find its logs by the contract's address and the topics its fields give:
import "std/evm";
anonymous event Moved of record {
indexed from : address;
indexed to : address;
indexed id : uint;
indexed kind : uint;
}
storage is record {
owners : map(uint, address);
}
external function move(const to : address; const id : uint) is {
storage.owners[id] := to;
emit Moved { from = Evm.sender(); to = to; id = id; kind = 1; };
}indexed belongs on the declaration only. It is an error on an emit, and on any record that is not an event.
Emitting
emit Name { field = value; ... } names every field. An event with no fields is declared event Name of record {} and emitted as emit Name {};.
Events are recorded where emit runs and logged in source order after the transition's storage writes, before any deferred call. emit requires a stateful function, and a view cannot emit.
Events in modules
A module's events are part of the module. Contracts that use the module log them under the same signatures, so a standard module's Transfer is the standard Transfer.

