LogoAnchor Docs

Emit Events

Learn how to emit events in Anchor programs using emit! and emit_cpi! macros.

Examples

Anchor provides two macros for emitting events in your programs:

  1. emit!() - Emits events directly to program logs. This is the simpler, though program logs may be truncated by data providers in some cases
  2. emit_cpi!() - Emits events through a Cross Program Invocation (CPI) by including the event data in the instruction data.

The emit_cpi() approach was introduced an alternative to program logs, which can sometimes be truncated by data providers. While CPI instruction data is less likely to be truncated, this approach does incur additional compute costs from the Cross Program Invocation.

For more robust solutions for events, consider geyser gRPC services by Triton or Helius.

emit

The emit!() macro provides a way to emit events through program logs. When called, it:

  1. Uses the sol_log_data() syscall to write the data to program logs
  2. Encodes the event data as a base64 string prefixed with Program Data:

To receive emitted events in your client application, use the addEventListener() method. This method automatically parses and decodes event data from the program logs.

Example usage:

lib.rs
use anchor_lang::prelude::*;
 
declare_id!("8T7MsCZyzxboviPJg5Rc7d8iqEcDReYR2pkQKrmbg7dy");
 
#[program]
pub mod event {
    use super::*;
 
    pub fn emit_event(_ctx: Context<EmitEvent>, input: String) -> Result<()> {


        emit!(CustomEvent { message: input });
        Ok(())
    }
}
 
#[derive(Accounts)]
pub struct EmitEvent {}
 

#[event]
pub struct CustomEvent {
    pub message: String,
}

The following is the output of the program logs. The event data is base64 encoded as Zb1eU3aiYdwOAAAASGVsbG8sIFNvbGFuYSE=.

Program Logs
Log Messages:
  Program 8T7MsCZyzxboviPJg5Rc7d8iqEcDReYR2pkQKrmbg7dy invoke [1]
  Program log: Instruction: EmitEvent
  Program data: Zb1eU3aiYdwOAAAASGVsbG8sIFNvbGFuYSE=
  Program 8T7MsCZyzxboviPJg5Rc7d8iqEcDReYR2pkQKrmbg7dy consumed 1012 of 200000 compute units
  Program 8T7MsCZyzxboviPJg5Rc7d8iqEcDReYR2pkQKrmbg7dy success

Ensure the RPC provider you use does not truncate the program logs from the transaction data.

emit_cpi

The emit_cpi!() macro emits events through Cross Program Invocations (CPIs) to the program itself. The event data is encoded and included in the CPI's instruction data (instead of program logs).

To emit events through CPIs, you need to enable the event-cpi feature in your program's Cargo.toml:

Cargo.toml
[dependencies]
anchor-lang = { version = "0.30.1", features = ["event-cpi"] }

Example usage:

lib.rs
use anchor_lang::prelude::*;
 
declare_id!("2cDQ2LxKwQ8fnFUz4LLrZ157QzBnhPNeQrTSmWcpVin1");
 
#[program]
pub mod event_cpi {
    use super::*;
 
    pub fn emit_event(ctx: Context<EmitEvent>, input: String) -> Result<()> {


        emit_cpi!(CustomEvent { message: input });
        Ok(())
    }
}
 

#[event_cpi]
#[derive(Accounts)]
pub struct EmitEvent {}
 

#[event]
pub struct CustomEvent {
    pub message: String,
}

The event_cpi attribute must be added to the #[derive(Accounts)] struct for the instruction instruction that emits events using the emit_cpi!() macro. This attribute automatically includes additional accounts that are required for the self CPI.

lib.rs

#[event_cpi]
#[derive(Accounts)]
pub struct RequiredAccounts {
  // --snip--
}

To get the emitted event data in your client application, you need to fetch the transaction using the transaction signature and parse the event data from the CPI instruction data.

test.ts
// 1. Fetch the full transaction data using the transaction signature
const transactionData = await program.provider.connection.getTransaction(
  transactionSignature,
  { commitment: "confirmed" },
);
 
// 2. Extract the CPI (inner instruction) that contains the event data
const eventIx = transactionData.meta.innerInstructions[0].instructions[0];
 
// 3. Decode the event data
const rawData = anchor.utils.bytes.bs58.decode(eventIx.data);
const base64Data = anchor.utils.bytes.base64.encode(rawData.subarray(8));
const event = program.coder.events.decode(base64Data);
console.log(event);

Below is an example transaction showing how event data appears in the transaction details. When using emit_cpi!(), the event data is encoded and included in the data field of an inner instruction (CPI).

In the example transaction below, the encoded event data is "data": "6AJcBqZP8afBKheoif1oA6UAiLAcqYr2RaR33pFnEY1taQp" in the innerInstructions array.

Transaction Data
{
  "blockTime": 1735854530,
  "meta": {
    "computeUnitsConsumed": 13018,
    "err": null,
    "fee": 5000,
    "innerInstructions": [
      {
        "index": 0,
        "instructions": [
          {
            "accounts": [
              1
            ],
            "data": "6AJcBqZP8afBKheoif1oA6UAiLAcqYr2RaR33pFnEY1taQp",
            "programIdIndex": 2,
            "stackHeight": 2
          }
        ]
      }
    ],
    "loadedAddresses": {
      "readonly": [],
      "writable": []
    },
    "logMessages": [
      "Program 2cDQ2LxKwQ8fnFUz4LLrZ157QzBnhPNeQrTSmWcpVin1 invoke [1]",
      "Program log: Instruction: EmitEvent",
      "Program 2cDQ2LxKwQ8fnFUz4LLrZ157QzBnhPNeQrTSmWcpVin1 invoke [2]",
      "Program 2cDQ2LxKwQ8fnFUz4LLrZ157QzBnhPNeQrTSmWcpVin1 consumed 5000 of 192103 compute units",
      "Program 2cDQ2LxKwQ8fnFUz4LLrZ157QzBnhPNeQrTSmWcpVin1 success",
      "Program 2cDQ2LxKwQ8fnFUz4LLrZ157QzBnhPNeQrTSmWcpVin1 consumed 13018 of 200000 compute units",
      "Program 2cDQ2LxKwQ8fnFUz4LLrZ157QzBnhPNeQrTSmWcpVin1 success"
    ],
    "postBalances": [
      499999999999995000,
      0,
      1141440
    ],
    "postTokenBalances": [],
    "preBalances": [
      500000000000000000,
      0,
      1141440
    ],
    "preTokenBalances": [],
    "rewards": [],
    "status": {
      "Ok": null
    }
  },
  "slot": 3,
  "transaction": {
    "message": {
      "header": {
        "numReadonlySignedAccounts": 0,
        "numReadonlyUnsignedAccounts": 2,
        "numRequiredSignatures": 1
      },
      "accountKeys": [
        "4kh6HxYZiAebF8HWLsUWod2EaQQ6iWHpHYCz8UcmFbM1",
        "2brZf9PQqEvv17xtbj5WNhZJULgVZuLZT6FgH1Cqpro2",
        "2cDQ2LxKwQ8fnFUz4LLrZ157QzBnhPNeQrTSmWcpVin1"
      ],
      "recentBlockhash": "2QtnU35RXTo7uuQEVARYJgWYRYtbqUxWQkK8WywUnVdY",
      "instructions": [
        {
          "accounts": [
            1,
            2
          ],
          "data": "3XZZ984toC4WXCLkxBsLimpEGgH75TKXRJnk",
          "programIdIndex": 2,
          "stackHeight": null
        }
      ],
      "indexToProgramIds": {}
    },
    "signatures": [
      "3gFbKahSSbitRSos4MH3cqeVv2FiTNaLCuWaLPo6R98FEbHnTshoYxopGcx74nFLqt1pbZK9i8dnr4NFXayrMndZ"
    ]
  }
}

Currently, event data emitted through CPIs cannot be directly subscribed to. To access this data, you must fetch the complete transaction data and manually decode the event information from the instruction data of the CPI.

On this page

Edit on GitHub