In Cairo contracts, an event
is a mechanism for notifying the outside world about a specific occurrence within the contract. Events provide a way for a contract to emit information about its internal state changes, which can be used by external applications outside of Starknet.
To define an event in Cairo, we use the Attribute #[event]
followed by #[derive(starknet::Event)]
attribute. All the different contract events (ie events we want to emit) are defined under the Event enum
, which implements the starknet::Event trait
Here's an example of how we can define an event in Cairo using ProgressContract
:
mod ProgressContract {
use starknet::ContractAddress;
#[storage]
struct Storage {
stage: u128,
}
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
IncreasedProgress: IncreasedProgress,
DecreasedProgress: DecreasedProgress
}
#[derive(Drop, starknet::Event)]
struct IncreasedProgress {
progress: u128 // single varible ie 128 bit integer
}
#[derive(Drop, starknet::Event)]
struct DecreasedProgress {
progress: u128
}
fn increase_progress(ref self: ContractState, progress: u128) {
let current = self.stage.read();
self.stage.write(current + progress);
self.emit(Event::IncreasedProgress(IncreasedProgress { progress }));
}
}
From the contract above, we can see enum Event
. The variants IncreasedProgress and DecreasedProgress
which are of types IncreasedProgress and DecreasedProgress
respectively, becomes the events we want our contract to emit, value(s) emitted (progress
) is a variable of type u128 defined within the IncreasedProgress and DecreasedProgress
structs . Name of the variants acts as the key of the emitted events which gets indexed.
After defining events, we'll need to emit them in the desired function. Emitting events in Cairo 1.0 is a bit different from how it's done in Cairo 0.x:
fn increase_progress(ref self: ContractState, progress: u128) {
let current = self.stage.read();
self.stage.write(current + progress);
self.emit(Event::IncreasedProgress(IncreasedProgress { progress }));
}
from the Increase_progress
function above, the ContractState
type is generated by the compiler, and gives access to the storage variables defined by the Storage struct.
ContractState
which is a representation of the contract’s state gives us the ability to emit events.
In our instance, self.emit(Event::IncreasedProgress(IncreasedProgress { progress:4 }))
will emit an event with one key, and one data element, 4, based on the generated implementation of the Event trait for the IncreasedProgress
type.
Things to keep in mind while using Events:
=> The Event type must be an enum
=> Each variant type has to be a struct, and of the same name as the variant