use crate::{cmd, util::node_url::get_node_url};
use anyhow::Context;
use fuel_core_client::client::{types::TransactionStatus, FuelClient};
use fuel_crypto::fuel_types::canonical::Deserialize;
pub async fn submit(cmd: cmd::Submit) -> anyhow::Result<()> {
let tx = read_tx(&cmd.tx_path)?;
let node_url = get_node_url(&cmd.network.node, &None)?;
let client = FuelClient::new(node_url)?;
if cmd.network.await_ {
let status = client
.submit_and_await_commit(&tx)
.await
.context("Submission of tx or awaiting commit failed")?;
if cmd.tx_status.json {
print_status_json(&status)?;
} else {
print_status(&status);
}
} else {
let id = client.submit(&tx).await.context("Failed to submit tx")?;
println!("{id}");
}
Ok(())
}
pub fn read_tx(path: &std::path::Path) -> anyhow::Result<fuel_tx::Transaction> {
let file = std::fs::File::open(path)?;
let reader = std::io::BufReader::new(file);
fn has_extension(path: &std::path::Path, ext: &str) -> bool {
path.extension().and_then(|ex| ex.to_str()) == Some(ext)
}
let tx: fuel_tx::Transaction = if has_extension(path, "json") {
serde_json::from_reader(reader)?
} else if has_extension(path, "bin") {
let tx_bytes = std::fs::read(path)?;
fuel_tx::Transaction::from_bytes(&tx_bytes).map_err(anyhow::Error::msg)?
} else {
anyhow::bail!(r#"Unsupported transaction file extension, expected ".json" or ".bin""#);
};
Ok(tx)
}
pub fn fmt_status(status: &TransactionStatus, s: &mut String) -> anyhow::Result<()> {
use chrono::TimeZone;
use std::fmt::Write;
match status {
TransactionStatus::Submitted { submitted_at } => {
writeln!(s, "Transaction Submitted at {:?}", submitted_at.0)?;
}
TransactionStatus::Success {
block_height,
time,
program_state,
..
} => {
let utc = chrono::Utc.timestamp_nanos(time.to_unix());
writeln!(s, "Transaction Succeeded")?;
writeln!(s, " Block ID: {block_height}")?;
writeln!(s, " Time: {utc}",)?;
writeln!(s, " Program State: {program_state:?}")?;
}
TransactionStatus::SqueezedOut { reason } => {
writeln!(s, "Transaction Squeezed Out: {reason}")?;
}
TransactionStatus::Failure {
block_height,
time,
reason,
program_state,
..
} => {
let utc = chrono::Utc.timestamp_nanos(time.to_unix());
writeln!(s, "Transaction Failed")?;
writeln!(s, " Reason: {reason}")?;
writeln!(s, " Block ID: {block_height}")?;
writeln!(s, " Time: {utc}")?;
writeln!(s, " Program State: {program_state:?}")?;
}
}
Ok(())
}
pub fn print_status(status: &TransactionStatus) {
let mut string = String::new();
fmt_status(status, &mut string).expect("formatting to `String` is infallible");
println!("{string}");
}
pub fn print_status_json(status: &TransactionStatus) -> anyhow::Result<()> {
let json = serde_json::to_string_pretty(status)?;
println!("{json}");
Ok(())
}