> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/solana-foundation/anchor/llms.txt
> Use this file to discover all available pages before exploring further.

# Events

> Learn how to emit events in Anchor programs using emit! and emit_cpi! macros with real examples

Events allow your program to emit structured data that clients can subscribe to and monitor. Anchor provides two ways to emit events: through program logs with `emit!` or through Cross Program Invocations with `emit_cpi!`.

## Defining Events

Define events using the `#[event]` attribute on a struct:

```rust theme={null}
#[event]
pub struct TransferEvent {
    pub from: Pubkey,
    pub to: Pubkey,
    pub amount: u64,
    pub timestamp: i64,
}
```

Events can contain any data types that implement `AnchorSerialize` and `AnchorDeserialize`.

## Emitting Events with emit!

The `emit!` macro is the simpler approach, writing events to program logs using the `sol_log_data()` syscall:

```rust theme={null}
use anchor_lang::prelude::*;

declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");

#[program]
pub mod events {
    use super::*;

    pub fn transfer(
        ctx: Context<Transfer>,
        amount: u64,
    ) -> Result<()> {
        // Transfer logic here
        
        emit!(TransferEvent {
            from: ctx.accounts.from.key(),
            to: ctx.accounts.to.key(),
            amount,
            timestamp: Clock::get()?.unix_timestamp,
        });
        
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Transfer<'info> {
    pub from: Signer<'info>,
    /// CHECK: This is safe because we don't read or write
    pub to: AccountInfo<'info>,
}

#[event]
pub struct TransferEvent {
    pub from: Pubkey,
    pub to: Pubkey,
    pub amount: u64,
    pub timestamp: i64,
}
```

### How emit! Works

1. Serializes the event data
2. Calls `sol_log_data()` to write to program logs
3. Encodes data as base64 with the prefix `Program data:`

### Program Logs Output

When an event is emitted, it appears in the logs:

```
Program log: Instruction: Transfer
Program data: Zb1eU3aiYdwOAAAASGVsbG8sIFNvbGFuYSE=
Program consumed 1012 of 200000 compute units
Program success
```

## Emitting Events with emit\_cpi!

The `emit_cpi!` macro emits events through a Cross Program Invocation, including the data in the instruction data instead of logs. This approach is more reliable when working with data providers that might truncate logs.

### Setup

Enable the `event-cpi` feature in `Cargo.toml`:

```toml theme={null}
[dependencies]
anchor-lang = { version = "0.32.1", features = ["event-cpi"] }
```

### Usage

```rust theme={null}
use anchor_lang::prelude::*;

declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");

#[program]
pub mod events_cpi {
    use super::*;

    pub fn transfer(
        ctx: Context<Transfer>,
        amount: u64,
    ) -> Result<()> {
        // Transfer logic here
        
        emit_cpi!(TransferEvent {
            from: ctx.accounts.from.key(),
            to: ctx.accounts.to.key(),
            amount,
            timestamp: Clock::get()?.unix_timestamp,
        });
        
        Ok(())
    }
}

// Add #[event_cpi] to the Accounts struct
#[event_cpi]
#[derive(Accounts)]
pub struct Transfer<'info> {
    pub from: Signer<'info>,
    /// CHECK: This is safe because we don't read or write
    pub to: AccountInfo<'info>,
}

#[event]
pub struct TransferEvent {
    pub from: Pubkey,
    pub to: Pubkey,
    pub amount: u64,
    pub timestamp: i64,
}
```

The `#[event_cpi]` attribute must be added to the accounts struct. It automatically includes additional accounts required for the self-CPI.

## Subscribing to Events in TypeScript

### Using emit! Events

Listen to events with `addEventListener()`:

```typescript theme={null}
import * as anchor from "@anchor-lang/anchor";
import { Program } from "@anchor-lang/anchor";
import { Events } from "../target/types/events";

const program = anchor.workspace.Events as Program<Events>;

// Set up event listener
const listenerId = program.addEventListener(
  "transferEvent",
  (event, slot) => {
    console.log(`Event in slot ${slot}:`);
    console.log(`  From: ${event.from.toString()}`);
    console.log(`  To: ${event.to.toString()}`);
    console.log(`  Amount: ${event.amount.toString()}`);
    console.log(`  Timestamp: ${event.timestamp.toString()}`);
  }
);

// Send transaction
await program.methods
  .transfer(new anchor.BN(1000))
  .accounts({ from, to })
  .rpc();

// Remove listener when done
await program.removeEventListener(listenerId);
```

### Using emit\_cpi! Events

For CPI events, fetch the transaction and decode manually:

```typescript theme={null}
import * as anchor from "@anchor-lang/anchor";

const txSignature = await program.methods
  .transfer(new anchor.BN(1000))
  .accounts({ from, to })
  .rpc();

// Wait for confirmation
await program.provider.connection.confirmTransaction(
  txSignature,
  "confirmed"
);

// Fetch transaction data
const txData = await program.provider.connection.getTransaction(
  txSignature,
  { commitment: "confirmed" }
);

// Decode event from CPI instruction data
const eventIx = txData.meta.innerInstructions[0].instructions[0];
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:", event);
```

## Complete Example

Here's a real-world example from a token staking program:

```rust theme={null}
use anchor_lang::prelude::*;

declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");

#[program]
pub mod staking {
    use super::*;

    pub fn stake(
        ctx: Context<Stake>,
        amount: u64,
    ) -> Result<()> {
        let stake_account = &mut ctx.accounts.stake_account;
        let clock = Clock::get()?;
        
        stake_account.staked_amount = stake_account.staked_amount
            .checked_add(amount)
            .ok_or(ErrorCode::Overflow)?;
        stake_account.last_stake_time = clock.unix_timestamp;
        
        emit!(StakeEvent {
            user: ctx.accounts.user.key(),
            amount,
            total_staked: stake_account.staked_amount,
            timestamp: clock.unix_timestamp,
        });
        
        msg!("Staked {} tokens", amount);
        Ok(())
    }

    pub fn unstake(
        ctx: Context<Unstake>,
        amount: u64,
    ) -> Result<()> {
        let stake_account = &mut ctx.accounts.stake_account;
        let clock = Clock::get()?;
        
        require!(
            stake_account.staked_amount >= amount,
            ErrorCode::InsufficientStake
        );
        
        stake_account.staked_amount = stake_account.staked_amount
            .checked_sub(amount)
            .ok_or(ErrorCode::Underflow)?;
        
        emit!(UnstakeEvent {
            user: ctx.accounts.user.key(),
            amount,
            remaining_staked: stake_account.staked_amount,
            timestamp: clock.unix_timestamp,
        });
        
        msg!("Unstaked {} tokens", amount);
        Ok(())
    }

    pub fn claim_rewards(ctx: Context<ClaimRewards>) -> Result<()> {
        let stake_account = &ctx.accounts.stake_account;
        let clock = Clock::get()?;
        
        let time_elapsed = clock.unix_timestamp - stake_account.last_stake_time;
        let rewards = calculate_rewards(stake_account.staked_amount, time_elapsed);
        
        emit!(RewardsClaimedEvent {
            user: ctx.accounts.user.key(),
            rewards,
            timestamp: clock.unix_timestamp,
        });
        
        msg!("Claimed {} reward tokens", rewards);
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Stake<'info> {
    #[account(mut)]
    pub stake_account: Account<'info, StakeAccount>,
    pub user: Signer<'info>,
}

#[derive(Accounts)]
pub struct Unstake<'info> {
    #[account(mut, has_one = user)]
    pub stake_account: Account<'info, StakeAccount>,
    pub user: Signer<'info>,
}

#[derive(Accounts)]
pub struct ClaimRewards<'info> {
    #[account(has_one = user)]
    pub stake_account: Account<'info, StakeAccount>,
    pub user: Signer<'info>,
}

#[account]
#[derive(InitSpace)]
pub struct StakeAccount {
    pub user: Pubkey,
    pub staked_amount: u64,
    pub last_stake_time: i64,
}

// Events
#[event]
pub struct StakeEvent {
    pub user: Pubkey,
    pub amount: u64,
    pub total_staked: u64,
    pub timestamp: i64,
}

#[event]
pub struct UnstakeEvent {
    pub user: Pubkey,
    pub amount: u64,
    pub remaining_staked: u64,
    pub timestamp: i64,
}

#[event]
pub struct RewardsClaimedEvent {
    pub user: Pubkey,
    pub rewards: u64,
    pub timestamp: i64,
}

#[error_code]
pub enum ErrorCode {
    #[msg("Insufficient staked tokens")]
    InsufficientStake,
    #[msg("Arithmetic overflow")]
    Overflow,
    #[msg("Arithmetic underflow")]
    Underflow,
}

fn calculate_rewards(staked_amount: u64, time_elapsed: i64) -> u64 {
    // Simple reward calculation: 10% APY
    let annual_rate = 10; // 10%
    let seconds_per_year = 365 * 24 * 60 * 60;
    
    (staked_amount as u128 * time_elapsed as u128 * annual_rate as u128 
        / (100 * seconds_per_year) as u128) as u64
}
```

## emit! vs emit\_cpi!

| Feature          | emit!                | emit\_cpi!                     |
| ---------------- | -------------------- | ------------------------------ |
| **Complexity**   | Simple               | Requires feature flag          |
| **Performance**  | Low compute cost     | Higher compute cost (CPI)      |
| **Reliability**  | May be truncated     | More reliable                  |
| **Setup**        | No special setup     | Needs `#[event_cpi]` attribute |
| **Subscription** | `addEventListener()` | Manual decoding                |
| **Best for**     | Most use cases       | High-value events              |

## Best Practices

1. **Keep events small**: Only include necessary data to minimize compute costs
2. **Add timestamps**: Always include a timestamp for event ordering
3. **Use descriptive names**: Name events clearly (e.g., `TokensMinted`, `UserRegistered`)
4. **Version events**: Consider adding a version field for future compatibility
5. **Test event emission**: Write tests to verify events are emitted correctly
6. **Document events**: Explain when each event is emitted and what data it contains

## Limitations

* **Log truncation**: RPC providers may truncate program logs (use `emit_cpi!` for critical events)
* **No event history**: Events are only available in transaction logs, not stored on-chain
* **Size limits**: Very large events may hit transaction size limits

<Callout type="info">
  For production applications requiring reliable event indexing, consider using Geyser gRPC services from providers like [Triton](https://docs.triton.one/project-yellowstone/dragons-mouth-grpc-subscriptions) or [Helius](https://docs.helius.dev/data-streaming/geyser-yellowstone).
</Callout>

## Related Resources

* [Events Test Example](https://github.com/coral-xyz/anchor/blob/master/tests/events/programs/events/src/lib.rs)
* [emit! Macro Source](https://github.com/coral-xyz/anchor/blob/master/lang/attribute/event/src/lib.rs)
* [Program Structure](/concepts/program-structure)
