use std::error::Error;
use std::fmt::Display;
use colored::Colorize;
use litesvm::types::{FailedTransactionMetadata, TransactionMetadata};
use solana_sdk::transaction::Transaction;
use solana_address_book::AddressBook;
#[derive(Debug)]
pub struct TXError {
pub transaction: Transaction,
pub metadata: FailedTransactionMetadata,
pub address_book: AddressBook,
}
impl Error for TXError {}
impl Display for TXError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Transaction failed: {}", self.metadata.err)
}
}
impl TXError {
pub fn print_error(&self) {
println!(
"\n{} {}",
"❌".red(),
"Transaction failed with error:".red().bold()
);
println!(" {}", format!("{:?}", self.metadata.err).bright_red());
println!(
"\n{} {}",
"📜".yellow(),
"Transaction Logs:".yellow().bold()
);
println!(
"{}",
self.address_book
.replace_addresses_in_text(&self.metadata.meta.pretty_logs())
);
println!(
"\n{} {}",
"📋".blue(),
"Instructions in failed transaction:".blue().bold()
);
for (i, ix) in self.transaction.message.instructions.iter().enumerate() {
let program_id = self.transaction.message.account_keys[ix.program_id_index as usize];
println!(
" {} {}: {}",
"Instruction".dimmed(),
i.to_string().bold(),
self.address_book.format_address(&program_id)
);
println!(
" {} {}",
"Accounts:".dimmed(),
format!("{} total", ix.accounts.len()).cyan()
);
for (j, account_index) in ix.accounts.iter().enumerate() {
let account_key = self.transaction.message.account_keys[*account_index as usize];
let is_signer = self.transaction.message.is_signer(*account_index as usize);
let is_writable = self
.transaction
.message
.is_maybe_writable(*account_index as usize, None);
let mut flags = Vec::new();
if is_signer {
flags.push("signer".green().to_string());
}
if is_writable {
flags.push("writable".yellow().to_string());
}
let flags_str = if !flags.is_empty() {
format!(" [{}]", flags.join(", "))
} else {
String::new()
};
println!(
" {} {}: {}{}",
"Account".dimmed(),
j.to_string().bold(),
self.address_book.format_address(&account_key),
flags_str
);
}
}
}
}
pub type TXResult = Result<TransactionMetadata, Box<TXError>>;