Skip to main content

solana_tools_lite_cli/flows/
analyze.rs

1use serde_json;
2use solana_tools_lite::adapters::io_adapter::{
3    read_input_transaction, read_lookup_tables,
4};
5use solana_tools_lite::handlers::analysis::{analyze_transaction, build_signing_summary};
6use solana_tools_lite::models::{InputTransaction, PubkeyBase58, Transaction};
7use std::convert::TryFrom;
8
9use crate::flows::presenter::{Presentable, AnalysisPresenter};
10use crate::shell::error::CliError;
11
12/// Analyze-transaction flow: thin orchestrator around the analysis handler.
13///
14/// Parameters
15/// - `input`: optional path to input file (when `None`, handler may read from stdin)
16/// - `pubkey`: optional public key to analyze as (Base58); if not provided, uses first signer
17/// - `lookup_tables_path`: optional path to lookup tables file
18/// - `summary_json`: emit analysis summary as JSON to stdout
19pub fn execute(
20    input: Option<&str>,
21    pubkey: Option<&str>,
22    lookup_tables_path: Option<&str>,
23    summary_json: bool,
24) -> Result<(), CliError> {
25    // 1) Read input transaction (file/stdin) via adapter
26    let input_tx: InputTransaction = read_input_transaction(input)?;
27
28    // 2) Convert to Transaction
29    let tx: Transaction = Transaction::try_from(input_tx)
30        .map_err(|e| CliError::Core(solana_tools_lite::ToolError::TransactionParse(e)))?;
31
32    let message = &tx.message;
33
34    // 3) Determine the public key to analyze as
35    let analyze_pubkey = if let Some(pk_str) = pubkey {
36        PubkeyBase58::try_from(pk_str)
37            .map_err(|e| CliError::Core(solana_tools_lite::ToolError::InvalidInput(
38                format!("Invalid pubkey: {}", e)
39            )))?
40    } else {
41        // Use first signer from message header
42        let account_keys = message.account_keys();
43
44        account_keys
45            .get(0)
46            .cloned()
47            .ok_or_else(|| CliError::Core(solana_tools_lite::ToolError::InvalidInput(
48                "No accounts in message".to_string()
49            )))?
50    };
51
52    // 4) Read lookup tables if provided
53    let tables = lookup_tables_path.map(read_lookup_tables).transpose()?;
54
55    // 5) Analyze the transaction
56    let analysis = analyze_transaction(message, &analyze_pubkey, tables.as_ref());
57
58    // 6) Present analysis summary to stderr
59    let analysis_presenter = AnalysisPresenter {
60        analysis: Some(&analysis),
61        summary_payload: None,
62    };
63
64    analysis_presenter.present(false, false, true)?;
65
66    // 7) Optionally emit JSON summary to stdout
67    if summary_json {
68        let summary = build_signing_summary(&tx, &analysis)?;
69
70        let payload = serde_json::to_string_pretty(&summary)
71            .map_err(|e| CliError::SummaryEncode(e.to_string()))?;
72
73        println!("{}", payload);
74    }
75
76    Ok(())
77}