pub const CPI_EVENT_MARKER: [u8; 2] = [0xE0, 0x1E];
pub const EVENT_AUTHORITY_SEED: &[u8] = b"__hopper_event_authority";
#[inline]
pub fn encode_event_cpi(
event_tag: u8,
event_payload: &[u8],
out: &mut [u8],
) -> Option<usize> {
let total = 2 + 1 + event_payload.len();
if out.len() < total {
return None;
}
out[0..2].copy_from_slice(&CPI_EVENT_MARKER);
out[2] = event_tag;
out[3..total].copy_from_slice(event_payload);
Some(total)
}
#[inline]
pub fn invoke_event_cpi(
program_id: &crate::address::Address,
event_authority: &crate::account::AccountView,
data: &[u8],
authority_seeds: &[&[u8]],
) -> crate::result::ProgramResult {
#[cfg(all(target_os = "solana", feature = "hopper-native-backend"))]
{
use crate::instruction::{InstructionAccount, InstructionView};
let account_meta = InstructionAccount {
pubkey: event_authority.address(),
is_signer: true,
is_writable: false,
};
let ix = InstructionView {
program_id,
accounts: ::core::slice::from_ref(&account_meta),
data,
};
let signer_list = [authority_seeds];
let account_views = [event_authority];
crate::cpi::invoke_signed::<1>(&ix, &account_views, &signer_list[..])
}
#[cfg(any(
not(target_os = "solana"),
feature = "legacy-pinocchio-compat",
feature = "solana-program-backend",
))]
{
let _ = (program_id, event_authority, data, authority_seeds);
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn encodes_marker_tag_and_payload_in_order() {
let mut buf = [0u8; 16];
let len = encode_event_cpi(0x42, &[1, 2, 3, 4], &mut buf).unwrap();
assert_eq!(len, 7);
assert_eq!(&buf[..len], &[0xE0, 0x1E, 0x42, 1, 2, 3, 4]);
}
#[test]
fn rejects_short_buffer() {
let mut buf = [0u8; 3];
let len = encode_event_cpi(0, &[1, 2, 3, 4], &mut buf);
assert!(len.is_none());
}
#[test]
fn zero_payload_is_valid() {
let mut buf = [0u8; 3];
let len = encode_event_cpi(0x7F, &[], &mut buf).unwrap();
assert_eq!(len, 3);
assert_eq!(&buf[..len], &[0xE0, 0x1E, 0x7F]);
}
#[test]
fn reserved_marker_is_stable() {
assert_eq!(CPI_EVENT_MARKER, [0xE0, 0x1E]);
}
}