Skip to main content

hopper_emit_cpi

Macro hopper_emit_cpi 

Source
macro_rules! hopper_emit_cpi {
    ( $program_id:expr, $event_authority:expr, $bump:expr, $event:expr ) => { ... };
}
Expand description

Emit a Hopper event via self-CPI for reliable indexing, the manual-wiring form.

Most programs should not call this directly: #[hopper::context(event_cpi)] plus ctx.emit_event_cpi(&event) wires the same emission (accounts, bump, sink) with zero hand-written plumbing. Reach for this macro only when the context macro is out of the picture (raw handlers, hand-rolled account handling, a custom sink).

Wraps cpi_event::encode_event_cpi and a call into the active backend’s invoke_signed so indexers see the event as an inner instruction in the transaction metadata. Log output is size-capped; inner instructions are retained. Anchor’s emit_cpi! solves the same problem with the same trick; Hopper’s lives in pure Rust so it works under no_std and any of the three backends, and its wire format is 3 bytes of overhead (2-byte marker + 1-byte tag) against Anchor’s 16 (8-byte instruction tag + 8-byte event discriminator).

§Required program plumbing (manual form only)

The caller must declare a sentinel handler so the dispatcher routes the self-CPI somewhere, and should authenticate it rather than no-op, or forged events become possible:

ⓘ
#[instruction(discriminator = [0xE0, 0x1E])]
fn __hopper_event_sink(ctx: &mut Context<'_>) -> ProgramResult {
    hopper_runtime::cpi_event::handle_event_sink(ctx, ctx.instruction_data())
}

And a PDA account seeded with cpi_event::EVENT_AUTHORITY_SEED (b"__hopper_event_authority") so the CPI has a signer, plus the program’s own account in the instruction so the runtime can resolve the self-CPI target.

§Usage

ⓘ
hopper_emit_cpi!(
    ctx.program_id(),
    event_authority: &AccountView,
    event_authority_bump: u8,
    Deposited { amount, depositor }
);

$event must be a #[hopper::event] type (anything implementing cpi_event::CpiEvent). Expands to: build instruction bytes, invoke_signed with the event_authority PDA as the signer. One CPI, bounded stack allocation, zero heap.