diff --git a/spel-client-gen/src/tests.rs b/spel-client-gen/src/tests.rs index 5e0ecb3..f9ed94b 100644 --- a/spel-client-gen/src/tests.rs +++ b/spel-client-gen/src/tests.rs @@ -269,6 +269,7 @@ fn test_pda_helpers_single_arg_seed() { spec: None, metadata: None, instruction_type: None, + events: vec![], }; let output = generate_pda_helpers(&idl); @@ -352,6 +353,7 @@ fn test_pda_helpers_multi_seed() { spec: None, metadata: None, instruction_type: None, + events: vec![], }; let output = generate_pda_helpers(&idl); @@ -433,6 +435,7 @@ fn test_pda_helpers_deduplication() { spec: None, metadata: None, instruction_type: None, + events: vec![], }; let output = generate_pda_helpers(&idl); @@ -507,6 +510,7 @@ fn test_pda_helpers_u64_single_seed() { spec: None, metadata: None, instruction_type: None, + events: vec![], }; let output = generate_pda_helpers(&idl); @@ -595,6 +599,7 @@ fn test_pda_helpers_u64_multi_seed() { spec: None, metadata: None, instruction_type: None, + events: vec![], }; let output = generate_pda_helpers(&idl); diff --git a/spel-framework-core/src/idl.rs b/spel-framework-core/src/idl.rs index dd57c46..51c14c2 100644 --- a/spel-framework-core/src/idl.rs +++ b/spel-framework-core/src/idl.rs @@ -36,6 +36,9 @@ pub struct SpelIdl { /// Example: "multisig_core::Instruction" #[serde(default, skip_serializing_if = "Option::is_none")] pub instruction_type: Option, + /// Events emitted by this program. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub events: Vec, } /// Program metadata (lssa-lang compat). @@ -191,6 +194,17 @@ pub struct IdlError { pub msg: Option, } +/// An event type emitted by a program. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct IdlEvent { + /// Event name (matches the struct name). + pub name: String, + /// Program-defined discriminant identifying this event type. + pub discriminant: u32, + /// Fields of the event payload (Borsh-encoded). + pub fields: Vec, +} + /// Compute the lssa-lang discriminator for an instruction name. /// /// This is SHA256("global:{name}")[..8], matching lssa-lang's convention. @@ -215,6 +229,7 @@ impl SpelIdl { spec: None, metadata: None, instruction_type: None, + events: vec![], } } diff --git a/spel-framework-core/src/idl_gen.rs b/spel-framework-core/src/idl_gen.rs index eb0592e..1bdf2bd 100644 --- a/spel-framework-core/src/idl_gen.rs +++ b/spel-framework-core/src/idl_gen.rs @@ -229,6 +229,7 @@ fn generate_idl_inner( spec: None, metadata: None, instruction_type: external_instruction, + events: vec![], }) } diff --git a/spel-framework-macros/src/lib.rs b/spel-framework-macros/src/lib.rs index 39c0bb0..972e559 100644 --- a/spel-framework-macros/src/lib.rs +++ b/spel-framework-macros/src/lib.rs @@ -135,6 +135,27 @@ pub fn account_type(_attr: TokenStream, item: TokenStream) -> TokenStream { item } +/// Mark a struct as an event payload for IDL generation. +/// +/// The `discriminant` argument must match the value passed to `emit_event()`. +/// +/// # Example +/// ```rust,ignore +/// #[event(discriminant = 1)] +/// pub struct InsufficientFunds { +/// pub requested: u128, +/// pub available: u128, +/// } +/// ``` +/// +/// This attribute is a no-op at compile time; it is consumed solely by the +/// IDL generator alongside `#[account_type]`. +#[proc_macro_attribute] +pub fn event(_attr: TokenStream, item: TokenStream) -> TokenStream { + // Marker only — detected by generate_idl! and #[lez_program] at compile time. + item +} + /// Generate IDL from a program source file. /// /// Parses the given Rust source file, finds the `#[lez_program]` module, diff --git a/spel-framework/src/lib.rs b/spel-framework/src/lib.rs index 8b167db..53ba2b3 100644 --- a/spel-framework/src/lib.rs +++ b/spel-framework/src/lib.rs @@ -4,7 +4,7 @@ //! similar to Anchor for Solana. // Re-export the proc macros -pub use spel_framework_macros::{account_type, generate_idl, instruction, lez_program}; +pub use spel_framework_macros::{lez_program, instruction, account_type, generate_idl, event}; // Re-export core types pub use spel_framework_core::types::{SpelOutput, SpelOutputParts}; @@ -15,6 +15,7 @@ pub use serde_json; pub mod prelude { pub use crate::account_type; + pub use crate::event; pub use crate::instruction; pub use crate::lez_program; pub use borsh::{BorshDeserialize, BorshSerialize};