use algonaut_abi::{
abi_interactions::AbiReturnType,
abi_type::{AbiType, AbiValue},
};
use algonaut_core::TransactionId;
use algonaut_model::algod::PendingTransactionResponse;
use crate::{Error, simulate::SimulateResponse};
const ABI_RETURN_HASH: [u8; 4] = [0x15, 0x1f, 0x7c, 0x75];
#[derive(Debug, Clone)]
pub struct AbiMethodResult {
pub transaction_id: TransactionId,
pub transaction_info: PendingTransactionResponse,
pub return_value: Result<AbiMethodReturnValue, AbiReturnDecodeError>,
}
#[derive(Debug, Clone)]
pub struct AbiReturnDecodeError(pub String);
#[derive(Debug, Clone)]
pub enum AbiMethodReturnValue {
Some(AbiValue),
Void,
}
#[derive(Debug, Clone)]
pub struct ExecuteOutcome {
pub confirmed_round: Option<u64>,
pub transaction_ids: Vec<TransactionId>,
pub method_results: Vec<AbiMethodResult>,
}
#[derive(Debug, Clone)]
pub struct SimulateOutcome {
pub transaction_ids: Vec<TransactionId>,
pub method_results: Vec<AbiMethodResult>,
pub simulate_response: SimulateResponse,
}
pub(super) fn get_return_value_with_return_type(
pending_tx: &PendingTransactionResponse,
transaction_id: &TransactionId, return_type: AbiReturnType,
) -> Result<AbiMethodResult, Error> {
let return_value = match return_type {
AbiReturnType::Some(return_type) => {
get_return_value_with_abi_type(pending_tx, &return_type)?
}
AbiReturnType::Void => Ok(AbiMethodReturnValue::Void),
};
Ok(AbiMethodResult {
transaction_id: transaction_id.to_owned(),
transaction_info: pending_tx.clone(),
return_value,
})
}
fn get_return_value_with_abi_type(
pending_tx: &PendingTransactionResponse,
abi_type: &AbiType,
) -> Result<Result<AbiMethodReturnValue, AbiReturnDecodeError>, Error> {
let logs = pending_tx.logs.as_deref().ok_or(Error::MissingReturnLog)?;
let ret_line = logs.last().ok_or(Error::MissingReturnLog)?;
let decoded_ret_line = &ret_line.0;
if !decoded_ret_line.starts_with(&ABI_RETURN_HASH) {
return Err(Error::MissingReturnLog);
}
let abi_encoded = &decoded_ret_line[ABI_RETURN_HASH.len()..];
Ok(match abi_type.decode(abi_encoded) {
Ok(decoded) => Ok(AbiMethodReturnValue::Some(decoded)),
Err(e) => Err(AbiReturnDecodeError(format!("{e:?}"))),
})
}