Skip to content

Commit caad694

Browse files
committed
refactor: adding separate logicerror context for reuse in app factory
1 parent 41605ec commit caad694

File tree

4 files changed

+46
-108
lines changed

4 files changed

+46
-108
lines changed

crates/algokit_utils/src/applications/app_client/error_transformation.rs

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use super::types::LogicError;
22
use super::{AppClient, AppSourceMaps};
3+
use crate::AlgorandClient;
34
use crate::transactions::TransactionResultError;
4-
use algokit_abi::arc56_contract::PcOffsetMethod;
5+
use algokit_abi::{Arc56Contract, arc56_contract::PcOffsetMethod};
56
use lazy_static::lazy_static;
67
use regex::Regex;
78
use 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+
4250
impl 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+
}

crates/algokit_utils/src/applications/app_client/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub struct BoxValue {
2525
}
2626
mod compilation;
2727
mod error;
28-
mod error_transformation;
28+
pub(crate) mod error_transformation;
2929
mod params_builder;
3030
mod state_accessor;
3131
mod transaction_builder;

crates/algokit_utils/src/applications/app_factory/mod.rs

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::sync::{Arc, Mutex};
55
use algokit_abi::arc56_contract::CallOnApplicationComplete;
66
use algokit_abi::{ABIReturn, ABIValue, Arc56Contract};
77

8+
use crate::applications::app_client::error_transformation::LogicErrorContext;
89
use crate::applications::app_client::{AppClientMethodCallParams, CompilationParams};
910
use crate::applications::app_deployer::{AppLookup, OnSchemaBreak, OnUpdate};
1011
use crate::applications::app_factory;
@@ -498,22 +499,16 @@ impl AppFactory {
498499
message: error_str.to_string(),
499500
};
500501

501-
let client = AppClient::new(AppClientParams {
502+
let source_maps = self.current_source_maps();
503+
let context = LogicErrorContext {
502504
app_id: 0,
503-
app_spec: self.app_spec.clone(),
504-
algorand: self.algorand.clone(),
505-
app_name: Some(self.app_name.clone()),
506-
default_sender: self.default_sender.clone(),
507-
default_signer: self.default_signer.clone(),
508-
source_maps: self.current_source_maps(),
509-
transaction_composer_config: self.transaction_composer_config.clone(),
510-
});
505+
app_spec: &self.app_spec,
506+
algorand: self.algorand.as_ref(),
507+
source_maps: source_maps.as_ref(),
508+
};
511509

512-
Some(
513-
client
514-
.expose_logic_error(&tx_err, is_clear_state_program)
515-
.message,
516-
)
510+
let logic = context.expose_logic_error(&tx_err, is_clear_state_program);
511+
Some(logic.message)
517512
}
518513

519514
/// Idempotently deploys (create, update, or replace) an application using

crates/algokit_utils/tests/applications/app_client/create_transaction.rs

Lines changed: 0 additions & 80 deletions
This file was deleted.

0 commit comments

Comments
 (0)