11use super :: types:: LogicError ;
22use super :: { AppClient , AppSourceMaps } ;
3+ use crate :: AlgorandClient ;
34use crate :: transactions:: TransactionResultError ;
4- use algokit_abi:: arc56_contract:: PcOffsetMethod ;
5+ use algokit_abi:: { Arc56Contract , arc56_contract:: PcOffsetMethod } ;
56use lazy_static:: lazy_static;
67use regex:: Regex ;
78use serde_json:: Value as JsonValue ;
@@ -39,6 +40,13 @@ pub(crate) fn extract_logic_error_data(error_str: &str) -> Option<LogicErrorData
3940 } )
4041}
4142
43+ pub ( crate ) struct LogicErrorContext < ' logic_error_ctx > {
44+ pub app_id : u64 ,
45+ pub app_spec : & ' logic_error_ctx Arc56Contract ,
46+ pub algorand : & ' logic_error_ctx AlgorandClient ,
47+ pub source_maps : Option < & ' logic_error_ctx AppSourceMaps > ,
48+ }
49+
4250impl AppClient {
4351 /// Import compiled source maps for approval and clear programs.
4452 pub fn import_source_maps ( & mut self , source_maps : AppSourceMaps ) {
@@ -51,9 +59,9 @@ impl AppClient {
5159 }
5260}
5361
54- impl AppClient {
62+ impl LogicErrorContext < ' _ > {
5563 /// Create an enhanced LogicError from a transaction error, applying source maps if available.
56- pub fn expose_logic_error (
64+ pub ( crate ) fn expose_logic_error (
5765 & self ,
5866 error : & TransactionResultError ,
5967 is_clear_state_program : bool ,
@@ -96,7 +104,7 @@ impl AppClient {
96104 let mut arc56_line_no: Option < u64 > = None ;
97105 let mut arc56_listing: Vec < String > = Vec :: new ( ) ;
98106
99- if let Some ( si_model) = self . app_spec ( ) . source_info . as_ref ( ) {
107+ if let Some ( si_model) = self . app_spec . source_info . as_ref ( ) {
100108 let program_source_info = if is_clear_state_program {
101109 & si_model. clear
102110 } else {
@@ -134,7 +142,7 @@ impl AppClient {
134142 }
135143
136144 if arc56_line_no. is_some ( )
137- && self . app_spec ( ) . source . is_some ( )
145+ && self . app_spec . source . is_some ( )
138146 && self . get_source_map ( is_clear_state_program) . is_none ( )
139147 {
140148 if let Some ( teal_src) = self . decode_teal ( is_clear_state_program) {
@@ -156,15 +164,12 @@ impl AppClient {
156164 if let Some ( emsg) = arc56_error_message. or ( msg_msg) {
157165 let app_id_from_msg = Self :: extract_app_id ( & err_str) ;
158166 let app_id = app_id_from_msg
159- . or_else ( || Some ( self . app_id ( ) . to_string ( ) ) )
167+ . or_else ( || Some ( self . app_id . to_string ( ) ) )
160168 . unwrap_or_else ( || "N/A" . to_string ( ) ) ;
161169 let txid_str = tx_id. unwrap_or_else ( || "N/A" . to_string ( ) ) ;
162170 let runtime_msg = format ! (
163171 "Runtime error when executing {} (appId: {}) in transaction {}: {}" ,
164- self . app_spec( ) . name,
165- app_id,
166- txid_str,
167- emsg
172+ self . app_spec. name, app_id, txid_str, emsg
168173 ) ;
169174 logic. message = runtime_msg. clone ( ) ;
170175 }
@@ -224,7 +229,7 @@ impl AppClient {
224229
225230 /// Get the selected program's source map.
226231 fn get_source_map ( & self , is_clear_state_program : bool ) -> Option < & JsonValue > {
227- let maps = self . source_maps . as_ref ( ) ?;
232+ let maps = self . source_maps ?;
228233 if is_clear_state_program {
229234 maps. clear_source_map . as_ref ( )
230235 } else {
@@ -365,15 +370,15 @@ impl AppClient {
365370 /// This avoids async calls; returns None if not available.
366371 fn get_program_bytes ( & self , is_clear_state_program : bool ) -> Option < Vec < u8 > > {
367372 let teal_src = self . decode_teal ( is_clear_state_program) ?;
368- self . algorand ( )
373+ self . algorand
369374 . app ( )
370375 . get_compilation_result ( & teal_src)
371376 . map ( |c| c. compiled_base64_to_bytes )
372377 }
373378
374379 /// Decode base64 TEAL source from the app spec.
375380 fn decode_teal ( & self , is_clear_state_program : bool ) -> Option < String > {
376- let src = self . app_spec ( ) . source . as_ref ( ) ?;
381+ let src = self . app_spec . source . as_ref ( ) ?;
377382 if is_clear_state_program {
378383 src. get_decoded_clear ( ) . ok ( )
379384 } else {
@@ -389,3 +394,21 @@ impl AppClient {
389394 . map ( |m| m. as_str ( ) . to_string ( ) )
390395 }
391396}
397+
398+ impl AppClient {
399+ /// Create an enhanced LogicError from a transaction error, applying source maps if available.
400+ pub fn expose_logic_error (
401+ & self ,
402+ error : & TransactionResultError ,
403+ is_clear_state_program : bool ,
404+ ) -> LogicError {
405+ let context = LogicErrorContext {
406+ app_id : self . app_id ( ) ,
407+ app_spec : self . app_spec ( ) ,
408+ algorand : self . algorand ( ) ,
409+ source_maps : self . source_maps . as_ref ( ) ,
410+ } ;
411+
412+ context. expose_logic_error ( error, is_clear_state_program)
413+ }
414+ }
0 commit comments