Skip to main content
The events example demonstrates how to publish events from a contract. This example is an extension of the storing data example.
Whisk ChangesWith the release of Whisk, Protocol 23, the syntax for publishing smart contract events has changed. In order to provide the most up-to-date information, this example has been updated to include the new patterns. Find more detailed information in the Rust SDK documentation.
Open in Codespaces Open in Codeanywhere

Run the Example

First go through the Setup process to get your development environment configured, then clone the main branch of the soroban-examples repository:
Or, skip the development environment setup and open this example in GitHub Codespaces or Code Anywhere. To run the tests for the example, navigate to the events directory, and use cargo test.
You should see the output:

Code

events/src/lib.rs
Ref: https://github.com/stellar/soroban-examples/tree/main/events

How it Works

This example contract extends the increment example by publishing an event each time the counter is incremented. Contract events let contracts emit information about what their contract is doing. Contracts can publish events creating a defined struct and publishing it to the smart contract environments. First, the #[contractevent] struct must be defined
Then, inside the contract’s function, we can create and publish the event with the relevant data.

Event Topics

Topics can be defined either statically or dynamically. In the sample code two static topics are used, which will be of the Symbol type: COUNTER and increment.
The topics don’t have to be made of the same type.
Topics can also be defined dynamically, inside the struct. In this case, the struct’s snake_case name will be the first topic. For example, the following event will have two topics: the Symbol “increment”, followed by an Address.

Event Data

An event also contains a data object of any value or type including types defined by contracts using #[contracttype]. In the example the data is the u32 count. The data_format = "single-value" tells the event to publish the data alone, with no surrounding data structure.
Event data will, by default, conform to the data structure in the defined struct. The data_format can also be specified as vec or single-value. Again, please refer to the Rust SDK documentation for more details.

Publishing

Publishing an event is done by calling the publish function on the created event struct. The function returns nothing on success, and panics on failure. Possible failure reasons can include malformed inputs (e.g. topic count exceeds limit) and running over the resource budget (TBD). Once successfully published, the new event will be available to applications consuming the events.
Published events are discarded if a contract invocation fails due to a panic, budget exhaustion, or when the contract returns an error.

Tests

Open the events/src/test.rs file to follow along.
events/src/test.rs
In any test the first thing that is always required is an Env, which is the Soroban environment that the contract will run in.
The contract is registered with the environment using the contract type.
All public functions within an impl block that is annotated with the #[contractimpl] attribute have a corresponding function generated in a generated client type. The client type will be named the same as the contract type with Client appended. For example, in our contract the contract type is IncrementContract, and the client is named IncrementContractClient.
The example invokes the contract several times.
The example asserts that the event was published. env.events().all() returns a ContractEvents value containing all the events published by the last contract invocation, which can be compared in a few different ways. The event struct defined with #[contractevent] can be converted to its XDR form with to_xdr and compared directly, which is the most convenient way to assert on events when the contract defines them using the macro.
filter_by_contract narrows the events down to those emitted by a specific contract address, which is useful when a contract invocation calls into other contracts that also emit events.
The event can also be compared by building its tuple form manually, as (contract_id, topics, data), which is useful when the contract does not define its events using the #[contractevent] macro.

Build the Contract

To build the contract, use the stellar contract build command.
A .wasm file should be outputted in the target directory:

Run the Contract

If you have stellar-cli installed, you can deploy the contract and invoke its functions.

Deploy

Invoke

The following output should occur using the code above.
A single event is outputted, which is the contract event the contract published. The event contains the two topics, each a Symbol, and the data object containing the u32.