-
Events in Anchor provide a mechanism for notifying and communicating between different components of a Solana dApp.
-
Events are structured pieces of data holding information about a specific occurrence in a program.
-
Since there is no native support for events in Solana, Anchor events depend on logging to emit events.
- Programs log
base64
encoded event data and clients parse the logs of the transaction to interpret the events.
- Programs log
- Events are defined using
#[event]
attribute macro, which allows the specification of fields that an event should contain:
#[event]
pub struct TransferEvent {
from: Pubkey,
to: Pubkey,
amount: u64,
}
- To emit an event, you can use the
emit!
macro:
emit!(TransferEvent {
from: *ctx.accounts.from.key,
to: *ctx.accounts.to.key,
amount,
});
- Anyone can subscribe to events emitted by your program, through the @coral-xyz/anchor library:
const subscriptionId = program.addEventListener("TransferEvent", (event) => {
// Handle event...
});
- The event listener should be removed once it's no longer needed:
program.removeEventListener(subscriptionId);
-
Solana nodes truncate logs larger than 10KB, which makes regular events emitted via
emit!
unreliable. -
Unlike logs, RPC providers store instruction data without truncation.
- CPI events make use of this by executing a self-invoke with the event data to store the event(s) in the instruction.
-
To use CPI events, you can enable
event-cpi
:
anchor-lang = { version = "0.29.0", features = ["event-cpi"] }
- Then, add
#[event_cpi]
to accountsstruct
:
#[event_cpi]
#[derive(Accounts)]
pub struct TransferContext {}
- And the instruction handler:
#![allow(unused)]
fn main() {
#[program]
pub mod my_program {
use super::*;
pub fn transfer(ctx: Context<TransferContext>, amount: u64) -> Result<()> {
// Perform transfer logic
// Emit the TransferEvent
emit_cpi!(TransferEvent {
from: *ctx.accounts.from.key,
to: *ctx.accounts.to.key,
amount,
});
Ok(())
}
}
}