From 97d9a4dbec41038e3b11da6e37d2c8ea47be046a Mon Sep 17 00:00:00 2001 From: Matthias <48327140+Matthias1590@users.noreply.github.com> Date: Wed, 22 Apr 2026 23:51:11 +0200 Subject: [PATCH 1/6] Fix inner instruction events not being detected --- ts/packages/anchor/src/program/event.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ts/packages/anchor/src/program/event.ts b/ts/packages/anchor/src/program/event.ts index 07ae3c05fa..e0dc50f1d4 100644 --- a/ts/packages/anchor/src/program/event.ts +++ b/ts/packages/anchor/src/program/event.ts @@ -274,7 +274,7 @@ export class EventParser { // Handles logs when the current program being executing is *not* this. private handleSystemLog(log: string): [string | null, boolean] { - if (log.startsWith(`Program ${this.programId.toString()} log:`)) { + if (log.startsWith(`Program ${this.programId.toString()} log:`) || log.startsWith(`Program ${this.programId.toString()} invoke`)) { return [this.programId.toString(), false]; } else if (log.includes("invoke") && !log.endsWith("[1]")) { return ["cpi", false]; From 184a4cfce8f21f237e20f6b02823eb13970bca19 Mon Sep 17 00:00:00 2001 From: Matthias <48327140+Matthias1590@users.noreply.github.com> Date: Thu, 23 Apr 2026 00:02:49 +0200 Subject: [PATCH 2/6] simplify check --- ts/packages/anchor/src/program/event.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ts/packages/anchor/src/program/event.ts b/ts/packages/anchor/src/program/event.ts index e0dc50f1d4..c0fab9e3f2 100644 --- a/ts/packages/anchor/src/program/event.ts +++ b/ts/packages/anchor/src/program/event.ts @@ -274,7 +274,7 @@ export class EventParser { // Handles logs when the current program being executing is *not* this. private handleSystemLog(log: string): [string | null, boolean] { - if (log.startsWith(`Program ${this.programId.toString()} log:`) || log.startsWith(`Program ${this.programId.toString()} invoke`)) { + if (log.startsWith(`Program ${this.programId.toString()} `)) { return [this.programId.toString(), false]; } else if (log.includes("invoke") && !log.endsWith("[1]")) { return ["cpi", false]; From 40fe9e70ef34410db3d52d4f20a936788a807d0a Mon Sep 17 00:00:00 2001 From: Matthias Wijnsma Date: Thu, 23 Apr 2026 12:52:07 +0200 Subject: [PATCH 3/6] Use regex for invoke parsing in logs --- ts/packages/anchor/src/program/event.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ts/packages/anchor/src/program/event.ts b/ts/packages/anchor/src/program/event.ts index c0fab9e3f2..56c58f2d84 100644 --- a/ts/packages/anchor/src/program/event.ts +++ b/ts/packages/anchor/src/program/event.ts @@ -274,9 +274,12 @@ export class EventParser { // Handles logs when the current program being executing is *not* this. private handleSystemLog(log: string): [string | null, boolean] { - if (log.startsWith(`Program ${this.programId.toString()} `)) { + const invokeMatch = EventParser.INVOKE_RE.exec(log); + if (invokeMatch && invokeMatch[1] === this.programId.toString()) { return [this.programId.toString(), false]; - } else if (log.includes("invoke") && !log.endsWith("[1]")) { + } else if (log.startsWith(`Program ${this.programId.toString()} log: `)) { + return [this.programId.toString(), false]; + } else if (invokeMatch && invokeMatch[2] !== EventParser.ROOT_DEPTH) { return ["cpi", false]; } else { let regex = /^Program ([1-9A-HJ-NP-Za-km-z]+) success$/; From eedcbacd77bb503d7bc49d467f96f933d04e7b53 Mon Sep 17 00:00:00 2001 From: Matthias Wijnsma Date: Thu, 23 Apr 2026 13:56:16 +0200 Subject: [PATCH 4/6] Add test for events coming from inner instructions --- client/src/lib.rs | 70 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index 3d470363c9..ec63761af8 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -858,7 +858,7 @@ mod tests { // Creating a mock struct that implements `anchor_lang::events` // for type inference in `test_logs` use { - anchor_lang::prelude::*, + anchor_lang::{Event, prelude::*}, futures::{SinkExt, StreamExt}, solana_rpc_client_api::response::RpcResponseContext, std::sync::atomic::{AtomicU64, Ordering}, @@ -1047,6 +1047,74 @@ mod tests { Ok(()) } + #[test] + fn test_parse_log_response_inner_events() -> Result<()> { + use { + anchor_lang::__private::base64, + base64::{engine::general_purpose::STANDARD, Engine}, + }; + + let mock_event = MockEvent {}; + let program_data_log = format!("Program data: {}", STANDARD.encode(mock_event.data())); + + let logs = vec![ + "Program ComputeBudget111111111111111111111111111111 invoke [1]", + "Program ComputeBudget111111111111111111111111111111 success", + "Program ComputeBudget111111111111111111111111111111 invoke [1]", + "Program ComputeBudget111111111111111111111111111111 success", + "Program term9YPb9mzAsABaqN71A4xdbxHmpBNZavpBiQKZzN3 invoke [1]", + "Program log: Instruction: ValidateNonce", + "Program term9YPb9mzAsABaqN71A4xdbxHmpBNZavpBiQKZzN3 consumed 4839 of 239700 compute units", + "Program term9YPb9mzAsABaqN71A4xdbxHmpBNZavpBiQKZzN3 success", + "Program term9YPb9mzAsABaqN71A4xdbxHmpBNZavpBiQKZzN3 invoke [1]", + "Program log: Instruction: SellExactInPumpFunV3", + "Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [2]", + "Program log: Instruction: Sell", + "Program pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ invoke [3]", + "Program log: Instruction: GetFees", + "Program pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ consumed 3136 of 187774 compute units", + "Program return: pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ AAAAAAAAAABfAAAAAAAAAB4AAAAAAAAA", + "Program pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ success", + "Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [3]", + "Program log: Instruction: TransferChecked", + "Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 2475 of 180928 compute units", + "Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success", + &program_data_log, + "Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [3]", + "Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 2060 of 166037 compute units", + "Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success", + "Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 60634 of 223605 compute units", + "Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success", + "Program term9YPb9mzAsABaqN71A4xdbxHmpBNZavpBiQKZzN3 consumed 72662 of 234861 compute units", + "Program term9YPb9mzAsABaqN71A4xdbxHmpBNZavpBiQKZzN3 success", + "Program 11111111111111111111111111111111 invoke [1]", + "Program 11111111111111111111111111111111 success", + "Program 11111111111111111111111111111111 invoke [1]", + "Program 11111111111111111111111111111111 success", + ]; + + // Converting to Vec as expected in `RpcLogsResponse` + let logs: Vec = logs.iter().map(|&l| l.to_string()).collect(); + + let program_id_str = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"; + + let events = parse_logs_response::( + RpcResponse { + context: RpcResponseContext::new(0), + value: RpcLogsResponse { + signature: "".to_string(), + err: None, + logs: logs.to_vec(), + }, + }, + program_id_str, + ).unwrap(); + + assert_eq!(events.len(), 1); + + Ok(()) + } + /// Regression test that registering multiple event listeners does not deadlock. #[test] fn multiple_listeners_no_deadlock() { From f3a293794f1a31dfaf0276447f9676ce62dc88ee Mon Sep 17 00:00:00 2001 From: Matthias Wijnsma Date: Thu, 23 Apr 2026 13:57:20 +0200 Subject: [PATCH 5/6] Detect inner events to pass test_parse_log_response_inner_events --- client/src/lib.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index ec63761af8..a358e02f0b 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -423,13 +423,20 @@ pub fn handle_program_log (Option, bool) { + let invoke_re = Regex::new(r"^Program ([1-9A-HJ-NP-Za-km-z]+) invoke \[([\d]+)\]$").unwrap(); + if let Some(invoke_match) = invoke_re.captures(log) { + if invoke_match.get(1).unwrap().as_str() == this_program_str { + return (Some(this_program_str.to_string()), false); + + // `Invoke [1]` instructions are pushed to the stack in `parse_logs_response`, + // so this ensures we only push CPIs to the stack at this stage + } else if invoke_match.get(2).unwrap().as_str() != "1" { + return (Some("cpi".to_string()), false); // Any string will do. + } + } + if log.starts_with(&format!("Program {this_program_str} log:")) { (Some(this_program_str.to_string()), false) - - // `Invoke [1]` instructions are pushed to the stack in `parse_logs_response`, - // so this ensures we only push CPIs to the stack at this stage - } else if log.contains("invoke") && !log.ends_with("[1]") { - (Some("cpi".to_string()), false) // Any string will do. } else { let re = Regex::new(r"^Program ([1-9A-HJ-NP-Za-km-z]+) success$").unwrap(); if re.is_match(log) { From 42a1dc1add3e63968f1adfcebd0ae3d258acb04a Mon Sep 17 00:00:00 2001 From: Matthias Wijnsma Date: Thu, 23 Apr 2026 16:19:49 +0200 Subject: [PATCH 6/6] formatting --- client/src/lib.rs | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index a358e02f0b..1bf71cf4ba 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -865,7 +865,7 @@ mod tests { // Creating a mock struct that implements `anchor_lang::events` // for type inference in `test_logs` use { - anchor_lang::{Event, prelude::*}, + anchor_lang::{prelude::*, Event}, futures::{SinkExt, StreamExt}, solana_rpc_client_api::response::RpcResponseContext, std::sync::atomic::{AtomicU64, Ordering}, @@ -1060,7 +1060,7 @@ mod tests { anchor_lang::__private::base64, base64::{engine::general_purpose::STANDARD, Engine}, }; - + let mock_event = MockEvent {}; let program_data_log = format!("Program data: {}", STANDARD.encode(mock_event.data())); @@ -1071,7 +1071,8 @@ mod tests { "Program ComputeBudget111111111111111111111111111111 success", "Program term9YPb9mzAsABaqN71A4xdbxHmpBNZavpBiQKZzN3 invoke [1]", "Program log: Instruction: ValidateNonce", - "Program term9YPb9mzAsABaqN71A4xdbxHmpBNZavpBiQKZzN3 consumed 4839 of 239700 compute units", + "Program term9YPb9mzAsABaqN71A4xdbxHmpBNZavpBiQKZzN3 consumed 4839 of 239700 compute \ + units", "Program term9YPb9mzAsABaqN71A4xdbxHmpBNZavpBiQKZzN3 success", "Program term9YPb9mzAsABaqN71A4xdbxHmpBNZavpBiQKZzN3 invoke [1]", "Program log: Instruction: SellExactInPumpFunV3", @@ -1079,20 +1080,26 @@ mod tests { "Program log: Instruction: Sell", "Program pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ invoke [3]", "Program log: Instruction: GetFees", - "Program pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ consumed 3136 of 187774 compute units", - "Program return: pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ AAAAAAAAAABfAAAAAAAAAB4AAAAAAAAA", + "Program pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ consumed 3136 of 187774 compute \ + units", + "Program return: pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ \ + AAAAAAAAAABfAAAAAAAAAB4AAAAAAAAA", "Program pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ success", "Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke [3]", "Program log: Instruction: TransferChecked", - "Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 2475 of 180928 compute units", + "Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 2475 of 180928 compute \ + units", "Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success", &program_data_log, "Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P invoke [3]", - "Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 2060 of 166037 compute units", + "Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 2060 of 166037 compute \ + units", "Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success", - "Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 60634 of 223605 compute units", + "Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P consumed 60634 of 223605 compute \ + units", "Program 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P success", - "Program term9YPb9mzAsABaqN71A4xdbxHmpBNZavpBiQKZzN3 consumed 72662 of 234861 compute units", + "Program term9YPb9mzAsABaqN71A4xdbxHmpBNZavpBiQKZzN3 consumed 72662 of 234861 compute \ + units", "Program term9YPb9mzAsABaqN71A4xdbxHmpBNZavpBiQKZzN3 success", "Program 11111111111111111111111111111111 invoke [1]", "Program 11111111111111111111111111111111 success", @@ -1115,7 +1122,8 @@ mod tests { }, }, program_id_str, - ).unwrap(); + ) + .unwrap(); assert_eq!(events.len(), 1);