evt_store_srv/
lib.rs

1use anchor_lang::prelude::*;
2use anchor_lang::solana_program::log::sol_log_data;
3use anchor_lang::system_program::{self, System};
4 use base64::engine::general_purpose::STANDARD as B64;
5use base64::Engine as _;
6
7declare_id!("Htor6YTegN8f8R6hzKmCc8mGzrWuEEMSGnzff574uypY");
8
9#[program]
10pub mod evt_store_srv {
11    use super::*;
12
13    // Unique entrypoint to accept a base64 string and push it to tx logs like an event
14    // event_type is a UTF-8 string describing the struct/type name of the payload
15    pub fn emit(ctx: Context<Emit>, data_b64: String, event_type: String) -> Result<()> {
16        // Decode the provided base64 string into raw bytes
17        let decoded = B64
18            .decode(data_b64.as_bytes())
19            .map_err(|_| error!(EvtError::InvalidBase64))?;
20
21        // Optionally ensure the provided caller_program is actually executable
22        require!(
23            ctx.accounts
24                .caller_program
25                .to_account_info()
26                .executable,
27            EvtError::InvalidCallerProgram
28        );
29
30        // Log as Program data using three slices in stable order:
31        // [event_type_utf8] [caller_program_pubkey(32)] [decoded_bytes]
32        let caller_key = ctx.accounts.caller_program.key();
33        sol_log_data(&[
34            event_type.as_bytes(),
35            caller_key.as_ref(),
36            decoded.as_slice(),
37        ]);
38        Ok(())
39    }
40}
41
42#[derive(Accounts)]
43pub struct Emit<'info> {
44    /// CHECK: The caller program account is only used for its Pubkey and to check `executable`.
45    /// We do not read or mutate its data; runtime check enforces it's an executable program.
46    /// The account is provided by the CPI caller (evt-store-cli) and is used to prefix logs.
47    pub caller_program: UncheckedAccount<'info>,
48    #[account(address = system_program::ID)]
49    pub system_program: Program<'info, System>,
50}
51
52#[error_code]
53pub enum EvtError {
54    #[msg("Invalid base64 input")]
55    InvalidBase64,
56    #[msg("Invalid caller program account")]
57    InvalidCallerProgram,
58}