use crate::{
assembled::simulate_and_assemble_transaction,
commands::tx::fetch,
config::{self, data, network},
print, resources,
signer::{self, Signer},
utils::transaction_env_hash,
xdr::{
self, FeeBumpTransaction, FeeBumpTransactionExt, FeeBumpTransactionInnerTx, Hash,
Transaction, TransactionEnvelope,
},
};
use soroban_rpc::GetTransactionResponse;
pub mod builder;
pub const ONE_XLM: i64 = 10_000_000;
#[allow(clippy::too_many_arguments)]
pub async fn sim_sign_and_send_tx<E>(
client: &soroban_rpc::Client,
tx: &Transaction,
config: &config::Args,
resources: &resources::Args,
auth_signers: &[Signer],
auth_mode: Option<soroban_rpc::AuthMode>,
quiet: bool,
no_cache: bool,
) -> Result<GetTransactionResponse, E>
where
E: From<soroban_rpc::Error>
+ From<config::Error>
+ From<fetch::Error>
+ From<data::Error>
+ From<network::Error>
+ From<xdr::Error>,
{
let print = print::Print::new(quiet);
let network = config.get_network()?;
print.infoln("Simulating transaction…");
let txn = simulate_and_assemble_transaction(
client,
tx,
resources.resource_config(),
resources.resource_fee,
auth_mode,
)
.await?;
let assembled = resources.apply_to_assembled_txn(txn);
let mut txn = Box::new(assembled.transaction().clone());
let sim_res = assembled.sim_response();
if !no_cache {
data::write(sim_res.clone().into(), &network.rpc_uri()?)?;
}
if let Some(tx) = config
.sign_soroban_authorizations(&txn, auth_signers, &print)
.await?
{
*txn = tx;
}
let mut signed_tx = config.sign(*txn, quiet).await?;
if let Some(fee_bump_fee) = assembled.fee_bump_fee() {
print.warnln(format!(
"Wrapping transaction with a fee bump transaction due to a fee of {} XLM.",
print::format_number(fee_bump_fee, 7)
));
let fee_bump_inner = match signed_tx {
TransactionEnvelope::Tx(tx_env) => FeeBumpTransactionInnerTx::Tx(tx_env),
_ => {
return Err(config::Error::Signer(
signer::Error::UnsupportedTransactionEnvelopeType,
)
.into())
}
};
let fee_bump = FeeBumpTransaction {
fee_source: tx.source_account.clone(),
fee: fee_bump_fee,
inner_tx: fee_bump_inner,
ext: FeeBumpTransactionExt::V0,
};
signed_tx = config.sign_fee_bump(fee_bump, quiet).await?;
}
print.globeln("Sending transaction…");
let res = send_transaction_polling_with_events(
client,
&signed_tx,
&network.network_passphrase,
&print,
)
.await?;
print.checkln("Transaction submitted successfully!");
let tx_hash_bytes = transaction_env_hash(&signed_tx, &network.network_passphrase)?;
let tx_hash = hex::encode(tx_hash_bytes);
print.log_explorer_url(&network, &tx_hash);
resources.print_cost_info(&res)?;
if !no_cache {
data::write(res.clone().try_into()?, &network.rpc_uri()?)?;
}
Ok(res)
}
pub async fn send_transaction_polling_with_events(
client: &soroban_rpc::Client,
signed_tx: &TransactionEnvelope,
network_passphrase: &str,
print: &print::Print,
) -> Result<GetTransactionResponse, soroban_rpc::Error> {
match client.send_transaction_polling(signed_tx).await {
Ok(res) => Ok(res),
Err(e) => {
if let Ok(hash) = transaction_env_hash(signed_tx, network_passphrase) {
if let Ok(resp) = client.get_transaction(&Hash(hash)).await {
let events = &resp.events.diagnostic_events;
crate::log::event::all(events);
crate::log::event::failure(events, print);
}
}
Err(e)
}
}
}