@@ -6,6 +6,7 @@ use katana_primitives::contract::StorageKey;
66use katana_primitives:: execution:: { EntryPointSelector , FunctionCall } ;
77use katana_primitives:: transaction:: TxHash ;
88use katana_primitives:: { ContractAddress , Felt } ;
9+ use katana_rpc_types:: event:: { EventFilter , EventFilterWithPage , ResultPageRequest } ;
910
1011use super :: client:: Client ;
1112
@@ -79,6 +80,10 @@ pub enum StarknetCommands {
7980 #[ command( name = "nonce" ) ]
8081 GetNonce ( GetNonceArgs ) ,
8182
83+ /// Get events matching filter criteria
84+ #[ command( name = "events" ) ]
85+ GetEvents ( GetEventsArgs ) ,
86+
8287 /// Get transaction execution trace
8388 #[ command( name = "trace" ) ]
8489 TraceTransaction ( TxHashArgs ) ,
@@ -220,8 +225,30 @@ pub struct CallArgs {
220225#[ derive( Debug , Args ) ]
221226#[ cfg_attr( test, derive( PartialEq , Eq ) ) ]
222227pub struct GetEventsArgs {
223- /// Event filter JSON
224- filter : String ,
228+ /// From block (number, hash, 'latest', or 'pending')
229+ #[ arg( long) ]
230+ from : Option < BlockIdArg > ,
231+
232+ /// To block (number, hash, 'latest', or 'pending')
233+ #[ arg( long) ]
234+ to : Option < BlockIdArg > ,
235+
236+ /// Contract address to filter events from
237+ #[ arg( long) ]
238+ address : Option < ContractAddress > ,
239+
240+ /// Event keys filter. Each key group is comma-separated, groups are space-separated.
241+ /// Example: --keys 0x1 0x2,0x3 represents [[0x1], [0x2, 0x3]]
242+ #[ arg( long, num_args = 0 ..) ]
243+ keys : Vec < String > ,
244+
245+ /// Continuation token from previous query for pagination
246+ #[ arg( long) ]
247+ continuation_token : Option < String > ,
248+
249+ /// Number of events to return per page
250+ #[ arg( long, default_value = "10" ) ]
251+ chunk_size : u64 ,
225252}
226253
227254#[ derive( Debug , Args ) ]
@@ -395,6 +422,29 @@ impl StarknetCommands {
395422 println ! ( "{}" , colored_json:: to_colored_json_auto( & result) ?) ;
396423 }
397424
425+ StarknetCommands :: GetEvents ( args) => {
426+ // Parse keys if provided
427+ let keys: Option < Vec < Vec < Felt > > > =
428+ if !args. keys . is_empty ( ) { Some ( parse_event_keys ( & args. keys ) ?) } else { None } ;
429+
430+ let event_filter = EventFilter {
431+ keys,
432+ address : args. address ,
433+ to_block : args. to . map ( |b| b. 0 ) ,
434+ from_block : args. from . map ( |b| b. 0 ) ,
435+ } ;
436+
437+ let result_page_request = ResultPageRequest {
438+ chunk_size : args. chunk_size ,
439+ continuation_token : args. continuation_token ,
440+ } ;
441+
442+ let filter = EventFilterWithPage { event_filter, result_page_request } ;
443+
444+ let result = client. get_events ( filter) . await ?;
445+ println ! ( "{}" , colored_json:: to_colored_json_auto( & result) ?) ;
446+ }
447+
398448 StarknetCommands :: TraceTransaction ( args) => {
399449 let tx_hash = args. tx_hash ;
400450 let result = client. trace_transaction ( tx_hash) . await ?;
@@ -475,6 +525,26 @@ impl Default for ConfirmedBlockIdArg {
475525 }
476526}
477527
528+ /// Parses event keys from CLI arguments.
529+ ///
530+ /// Format: Each argument is a comma-separated list of felts.
531+ /// Example: ["0x1", "0x2,0x3", "0x4"] => [[0x1], [0x2, 0x3], [0x4]]
532+ fn parse_event_keys ( keys : & [ String ] ) -> Result < Vec < Vec < Felt > > > {
533+ keys. iter ( )
534+ . enumerate ( )
535+ . map ( |( i, group) | {
536+ group
537+ . split ( ',' )
538+ . map ( |s| {
539+ s. trim ( )
540+ . parse :: < Felt > ( )
541+ . with_context ( || format ! ( "invalid felt in key group {}: '{}'" , i, s) )
542+ } )
543+ . collect :: < Result < Vec < Felt > > > ( )
544+ } )
545+ . collect ( )
546+ }
547+
478548#[ cfg( test) ]
479549mod tests {
480550 use std:: str:: FromStr ;
@@ -551,4 +621,64 @@ mod tests {
551621 let default = ConfirmedBlockIdArg :: default ( ) ;
552622 assert_matches ! ( default . 0 , ConfirmedBlockIdOrTag :: Latest ) ;
553623 }
624+
625+ use clap:: Parser ;
626+
627+ use super :: { parse_event_keys, GetEventsArgs } ;
628+
629+ #[ derive( Debug , Parser ) ]
630+ struct TestCli {
631+ #[ command( flatten) ]
632+ args : GetEventsArgs ,
633+ }
634+
635+ #[ test]
636+ fn get_events_args_single_keys ( ) {
637+ let args = TestCli :: try_parse_from ( [ "test" , "--keys" , "0x1" , "0x2" , "0x3" ] ) . unwrap ( ) ;
638+
639+ let keys = parse_event_keys ( & args. args . keys ) . unwrap ( ) ;
640+ assert_eq ! ( keys. len( ) , 3 ) ;
641+ assert_eq ! ( keys[ 0 ] , vec![ felt!( "0x1" ) ] ) ;
642+ assert_eq ! ( keys[ 1 ] , vec![ felt!( "0x2" ) ] ) ;
643+ assert_eq ! ( keys[ 2 ] , vec![ felt!( "0x3" ) ] ) ;
644+ }
645+
646+ #[ test]
647+ fn get_events_args_multiple_keys ( ) {
648+ let args =
649+ TestCli :: try_parse_from ( [ "test" , "--keys" , "0x9" , "0x1,0x2,0x3" , "0x4,0x5" ] ) . unwrap ( ) ;
650+
651+ let keys = parse_event_keys ( & args. args . keys ) . unwrap ( ) ;
652+ assert_eq ! ( keys. len( ) , 3 ) ;
653+ assert_eq ! ( keys[ 0 ] , vec![ felt!( "0x9" ) ] ) ;
654+ assert_eq ! ( keys[ 1 ] , vec![ felt!( "0x1" ) , felt!( "0x2" ) , felt!( "0x3" ) ] ) ;
655+ assert_eq ! ( keys[ 2 ] , vec![ felt!( "0x4" ) , felt!( "0x5" ) ] ) ;
656+ }
657+
658+ #[ test]
659+ fn get_events_args_keys_with_whitespace ( ) {
660+ let args = TestCli :: try_parse_from ( [ "test" , "--keys" , "0x1, 0x2 , 0x3" ] ) . unwrap ( ) ;
661+
662+ let keys = parse_event_keys ( & args. args . keys ) . unwrap ( ) ;
663+ assert_eq ! ( keys. len( ) , 1 ) ;
664+ assert_eq ! ( keys[ 0 ] , vec![ felt!( "0x1" ) , felt!( "0x2" ) , felt!( "0x3" ) ] ) ;
665+ }
666+
667+ #[ test]
668+ fn get_events_args_invalid_felt ( ) {
669+ let args = TestCli :: try_parse_from ( [ "test" , "--keys" , "0x1" , "invalid" ] ) . unwrap ( ) ;
670+
671+ let result = parse_event_keys ( & args. args . keys ) ;
672+ assert ! ( result. is_err( ) ) ;
673+ assert ! ( result. unwrap_err( ) . to_string( ) . contains( "invalid felt in key group" ) ) ;
674+ }
675+
676+ #[ test]
677+ fn get_events_args_invalid_hex ( ) {
678+ let args = TestCli :: try_parse_from ( [ "test" , "--keys" , "0x1,0xGGG" ] ) . unwrap ( ) ;
679+
680+ let result = parse_event_keys ( & args. args . keys ) ;
681+ assert ! ( result. is_err( ) ) ;
682+ assert ! ( result. unwrap_err( ) . to_string( ) . contains( "invalid felt in key group 0" ) ) ;
683+ }
554684}
0 commit comments