Events allow for data to be logged publicly to the blockchain. Log entries provide the contract's address, a series of up to four topics, and some arbitrary length binary data. The Stylus Rust SDK provides a few ways to publish event logs described below.
Using the evm::log
function in the Stylus SDK is the preferred way to log events. It ensures that an event will be logged in a Solidity ABI-compatible format. The log
function takes any type that implements Alloy SolEvent
trait. It's not recommended to attempt to implement this trait on your own. Instead, make use of the provided sol!
macro to declare your Events and their schema using Solidity-style syntax to declare the parameter types. Alloy will create ABI-compatible Rust types which you can instantiate and pass to the evm::log
function.
1// sol! macro event declaration
2// Up to 3 parameters can be indexed.
3// Indexed parameters helps you filter the logs efficiently
4sol! {
5 event Log(address indexed sender, string message);
6 event AnotherLog();
7}
8
9#[entrypoint]
10fn user_main(_input: Vec<u8>) -> ArbResult {
11 // emits a 'Log' event, defined above in the sol! macro
12 evm::log(Log {
13 sender: Address::from([0x11; 20]),
14 message: "Hello world!".to_string(),
15 });
16
17 // no data, but 'AnotherLog' event will still emit to the chain
18 evm::log(AnotherLog {});
19
20 Ok(vec![])
21}
1// sol! macro event declaration
2// Up to 3 parameters can be indexed.
3// Indexed parameters helps you filter the logs efficiently
4sol! {
5 event Log(address indexed sender, string message);
6 event AnotherLog();
7}
8
9#[entrypoint]
10fn user_main(_input: Vec<u8>) -> ArbResult {
11 // emits a 'Log' event, defined above in the sol! macro
12 evm::log(Log {
13 sender: Address::from([0x11; 20]),
14 message: "Hello world!".to_string(),
15 });
16
17 // no data, but 'AnotherLog' event will still emit to the chain
18 evm::log(AnotherLog {});
19
20 Ok(vec![])
21}
The evm::raw_log
affordance offers the ability to send anonymous events that do not necessarily conform to the Solidity ABI. Instead, up to four raw 32-byte indexed topics are published along with any arbitrary bytes appended as data.
NOTE: It's still possible to achieve Solidity ABI compatibility using this construct. To do so you'll have to manually compute the ABI signature for the event, following the equation set in the Solidity docs. The result of that should be assigned to TOPIC_0
, the first topic in the slice passed to raw_log
.
1// set up local variables
2let user = Address::from([0x22; 20]);
3let balance = U256::from(10_000_000);
4
5// declare up to 4 topics
6// topics must be of type FixedBytes<32>
7let topics = &[user.into_word()];
8
9// store non-indexed data in a byte Vec
10let mut data: Vec<u8> = vec![];
11// to_be_bytes means 'to big endian bytes'
12data.extend_from_slice(balance.to_be_bytes::<32>().to_vec().as_slice());
13
14// unwrap() here 'consumes' the Result
15evm::raw_log(topics.as_slice(), data.as_ref()).unwrap();
1// set up local variables
2let user = Address::from([0x22; 20]);
3let balance = U256::from(10_000_000);
4
5// declare up to 4 topics
6// topics must be of type FixedBytes<32>
7let topics = &[user.into_word()];
8
9// store non-indexed data in a byte Vec
10let mut data: Vec<u8> = vec![];
11// to_be_bytes means 'to big endian bytes'
12data.extend_from_slice(balance.to_be_bytes::<32>().to_vec().as_slice());
13
14// unwrap() here 'consumes' the Result
15evm::raw_log(topics.as_slice(), data.as_ref()).unwrap();
Combining the above examples into the boiler plate provided below this section, deploying to a Stylus chain and then invoking the deployed contract will result in the following three events logged to the chain:
1[
2 {
3 "address": "0x6cf4a18ac8efd6b0b99d3200c4fb9609dd60d4b3",
4 "topics": [
5 "0x0738f4da267a110d810e6e89fc59e46be6de0c37b1d5cd559b267dc3688e74e0",
6 "0x0000000000000000000000001111111111111111111111111111111111111111"
7 ],
8 "data": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000c48656c6c6f20776f726c64210000000000000000000000000000000000000000",
9 "blockHash": "0xfef880025dc87b5ab4695a0e1a6955dd7603166ecba79ce0f503a568b2ec8940",
10 "blockNumber": "0x94",
11 "transactionHash": "0xc7318dae2164eb441fb80f5b869f844e3e97ae83c24a4639d46ec4d915a30818",
12 "transactionIndex": "0x1",
13 "logIndex": "0x0",
14 "removed": false
15 },
16 {
17 "address": "0x6cf4a18ac8efd6b0b99d3200c4fb9609dd60d4b3",
18 "topics": [
19 "0xfe1a3ad11e425db4b8e6af35d11c50118826a496df73006fc724cb27f2b99946"
20 ],
21 "data": "0x",
22 "blockHash": "0xfef880025dc87b5ab4695a0e1a6955dd7603166ecba79ce0f503a568b2ec8940",
23 "blockNumber": "0x94",
24 "transactionHash": "0xc7318dae2164eb441fb80f5b869f844e3e97ae83c24a4639d46ec4d915a30818",
25 "transactionIndex": "0x1",
26 "logIndex": "0x1",
27 "removed": false
28 },
29 {
30 "address": "0x6cf4a18ac8efd6b0b99d3200c4fb9609dd60d4b3",
31 "topics": [
32 "0x0000000000000000000000002222222222222222222222222222222222222222"
33 ],
34 "data": "0x0000000000000000000000000000000000000000000000000000000000989680",
35 "blockHash": "0xfef880025dc87b5ab4695a0e1a6955dd7603166ecba79ce0f503a568b2ec8940",
36 "blockNumber": "0x94",
37 "transactionHash": "0xc7318dae2164eb441fb80f5b869f844e3e97ae83c24a4639d46ec4d915a30818",
38 "transactionIndex": "0x1",
39 "logIndex": "0x2",
40 "removed": false
41 }
42]
1[
2 {
3 "address": "0x6cf4a18ac8efd6b0b99d3200c4fb9609dd60d4b3",
4 "topics": [
5 "0x0738f4da267a110d810e6e89fc59e46be6de0c37b1d5cd559b267dc3688e74e0",
6 "0x0000000000000000000000001111111111111111111111111111111111111111"
7 ],
8 "data": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000c48656c6c6f20776f726c64210000000000000000000000000000000000000000",
9 "blockHash": "0xfef880025dc87b5ab4695a0e1a6955dd7603166ecba79ce0f503a568b2ec8940",
10 "blockNumber": "0x94",
11 "transactionHash": "0xc7318dae2164eb441fb80f5b869f844e3e97ae83c24a4639d46ec4d915a30818",
12 "transactionIndex": "0x1",
13 "logIndex": "0x0",
14 "removed": false
15 },
16 {
17 "address": "0x6cf4a18ac8efd6b0b99d3200c4fb9609dd60d4b3",
18 "topics": [
19 "0xfe1a3ad11e425db4b8e6af35d11c50118826a496df73006fc724cb27f2b99946"
20 ],
21 "data": "0x",
22 "blockHash": "0xfef880025dc87b5ab4695a0e1a6955dd7603166ecba79ce0f503a568b2ec8940",
23 "blockNumber": "0x94",
24 "transactionHash": "0xc7318dae2164eb441fb80f5b869f844e3e97ae83c24a4639d46ec4d915a30818",
25 "transactionIndex": "0x1",
26 "logIndex": "0x1",
27 "removed": false
28 },
29 {
30 "address": "0x6cf4a18ac8efd6b0b99d3200c4fb9609dd60d4b3",
31 "topics": [
32 "0x0000000000000000000000002222222222222222222222222222222222222222"
33 ],
34 "data": "0x0000000000000000000000000000000000000000000000000000000000989680",
35 "blockHash": "0xfef880025dc87b5ab4695a0e1a6955dd7603166ecba79ce0f503a568b2ec8940",
36 "blockNumber": "0x94",
37 "transactionHash": "0xc7318dae2164eb441fb80f5b869f844e3e97ae83c24a4639d46ec4d915a30818",
38 "transactionIndex": "0x1",
39 "logIndex": "0x2",
40 "removed": false
41 }
42]
1#![no_main]
2#![no_std]
3extern crate alloc;
4
5#[global_allocator]
6static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
7use alloc::vec::Vec;
8use alloc::{string::ToString, vec};
9
10use stylus_sdk::alloy_primitives::{U256, Address};
11use stylus_sdk::alloy_sol_types::sol;
12use stylus_sdk::{evm, prelude::*, ArbResult};
13
14
15#[entrypoint]
16fn user_main(_input: Vec<u8>) -> ArbResult {
17 // Insert logic from above usages here
18
19 Ok(Vec::new())
20}
1#![no_main]
2#![no_std]
3extern crate alloc;
4
5#[global_allocator]
6static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
7use alloc::vec::Vec;
8use alloc::{string::ToString, vec};
9
10use stylus_sdk::alloy_primitives::{U256, Address};
11use stylus_sdk::alloy_sol_types::sol;
12use stylus_sdk::{evm, prelude::*, ArbResult};
13
14
15#[entrypoint]
16fn user_main(_input: Vec<u8>) -> ArbResult {
17 // Insert logic from above usages here
18
19 Ok(Vec::new())
20}
1[package]
2name = "events"
3version = "0.1.0"
4edition = "2021"
5
6[dependencies]
7# Note: Do not ship to prod with 'debug' flag set
8stylus-sdk = { version = "0.4.2", features = ["debug"] }
9wee_alloc = "0.4.5"
10alloy-sol-types = "0.3.1"
11
12[features]
13export-abi = ["stylus-sdk/export-abi"]
14
15[profile.release]
16codegen-units = 1
17strip = true
18lto = true
19panic = "abort"
20opt-level = "s"
21
22[workspace]
1[package]
2name = "events"
3version = "0.1.0"
4edition = "2021"
5
6[dependencies]
7# Note: Do not ship to prod with 'debug' flag set
8stylus-sdk = { version = "0.4.2", features = ["debug"] }
9wee_alloc = "0.4.5"
10alloy-sol-types = "0.3.1"
11
12[features]
13export-abi = ["stylus-sdk/export-abi"]
14
15[profile.release]
16codegen-units = 1
17strip = true
18lto = true
19panic = "abort"
20opt-level = "s"
21
22[workspace]