On-chain events let off-chain indexers, clients, and other programs observe what happened inside a transaction. Quasar provides two emission strategies with different cost and trust tradeoffs: a fast log-based path viaDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/blueshift-gg/quasar/llms.txt
Use this file to discover all available pages before exploring further.
emit! and a spoofing-resistant self-CPI path via emit_cpi!.
Defining Event Types with #[event]
Annotate a struct with #[event(discriminator = N)] to declare an event type. The macro generates an Event trait impl with a discriminator, a fixed data size, and the serialization logic for both emission paths:
#[account] fields: every type must be a Pod type with alignment 1 (Address, u64, u32, u8, bool, etc.).
The Event Trait
The generated impl satisfies the Event trait from quasar_lang::traits:
emit! — Log-Based Emission (~100 CU)
emit!(MyEvent { ... }) serializes the event into a stack buffer and calls sol_log_data. This is the fastest emission path (~100 CU) and produces a Program data: ... log entry that off-chain indexers can parse.
sol_log_data logs are not linked to a specific program in the transaction trace. Any program in the same transaction can call sol_log_data with the same bytes, making emit! events spoofable by a malicious program that runs in the same transaction.
emit_cpi! — Self-CPI Emission (~1,000 CU)
emit_cpi!(MyEvent { ... }) performs a self-CPI to the program’s own __event_authority PDA. Because the Solana runtime records which program made each CPI call, the emitting program’s address appears in the transaction trace alongside the event — making the event unforgeable.
emit!.
- emit! (~100 CU)
- emit_cpi! (~1,000 CU)
Use when:
- Off-chain indexers are the only consumers
- You trust the transaction context (e.g. your own frontends)
- Compute budget is tight
- Spoofability is acceptable for your use case
The __event_authority PDA
The #[program] macro generates a constant EventAuthority type. Its BUMP field is the canonical bump for the __event_authority PDA derived from b"__event_authority" and the program ID:
emit_cpi! runs, it signs the self-CPI with seeds [b"__event_authority", &[BUMP]]. The __handle_event dispatch arm validates:
- At least one account was passed
- The first account is a signer
- Its address matches the
__event_authorityPDA - The instruction data is more than 1 byte (the
0xFFCPI marker plus payload)
sol_log_data with the remaining bytes (discriminator + event data).
Event Serialization Format
Both emission paths serialize events the same way on the wire:0xFF prefix distinguishes self-CPI invocations from normal instruction calls in the dispatch router.
Reading Events Off-Chain
Events emitted viaemit! appear in the transaction logs as Program data: <base64>. Parse them by:
- Filtering
Program data:log entries for your program’s logs - Base64-decoding the payload
- Matching the first byte(s) against known discriminators
- Deserializing the remaining bytes according to the event layout
quasar build --client) handles this automatically. For manual parsing, see the escrow client’s event decoder:
MAKE_EVENT_DISCRIMINATOR is the constant &[u8] matching the #[event(discriminator = 0)] value.
The event discriminator namespace is separate from the account and instruction discriminator namespaces. You may safely use
discriminator = 0 on an event type even if discriminator = 0 is already used on an instruction in the same program.