soroban_cli/commands/tx/
args.rs1use crate::{
2 commands::{global, txn_result::TxnEnvelopeResult},
3 config::{
4 self,
5 address::{self, UnresolvedMuxedAccount},
6 data, network, secret,
7 },
8 fee,
9 rpc::{self, Client, GetTransactionResponse},
10 tx::builder::{self, asset, TxExt},
11 xdr::{self, Limits, WriteXdr},
12};
13
14#[derive(Debug, clap::Args, Clone)]
15#[group(skip)]
16pub struct Args {
17 #[clap(flatten)]
18 pub fee: fee::Args,
19 #[clap(flatten)]
20 pub config: config::Args,
21}
22
23#[derive(thiserror::Error, Debug)]
24pub enum Error {
25 #[error(transparent)]
26 Rpc(#[from] rpc::Error),
27 #[error(transparent)]
28 Config(#[from] config::Error),
29 #[error(transparent)]
30 Network(#[from] network::Error),
31 #[error(transparent)]
32 Secret(#[from] secret::Error),
33 #[error(transparent)]
34 Tx(#[from] builder::Error),
35 #[error(transparent)]
36 Data(#[from] data::Error),
37 #[error(transparent)]
38 Xdr(#[from] xdr::Error),
39 #[error(transparent)]
40 Address(#[from] address::Error),
41 #[error(transparent)]
42 Asset(#[from] asset::Error),
43 #[error(transparent)]
44 TxXdr(#[from] super::xdr::Error),
45}
46
47impl Args {
48 pub async fn tx(&self, body: impl Into<xdr::OperationBody>) -> Result<xdr::Transaction, Error> {
49 let source_account = self.source_account().await?;
50 let seq_num = self
51 .config
52 .next_sequence_number(source_account.clone().account_id())
53 .await?;
54 let operation = xdr::Operation {
56 source_account: None,
57 body: body.into(),
58 };
59 Ok(xdr::Transaction::new_tx(
60 source_account,
61 self.fee.fee,
62 seq_num,
63 operation,
64 ))
65 }
66
67 pub fn client(&self) -> Result<Client, Error> {
68 let network = self.config.get_network()?;
69 Ok(Client::new(&network.rpc_url)?)
70 }
71
72 pub async fn handle(
73 &self,
74 op: impl Into<xdr::OperationBody>,
75 global_args: &global::Args,
76 ) -> Result<TxnEnvelopeResult<GetTransactionResponse>, Error> {
77 let tx = self.tx(op).await?;
78 self.handle_tx(tx, global_args).await
79 }
80
81 pub async fn handle_and_print(
82 &self,
83 op: impl Into<xdr::OperationBody>,
84 global_args: &global::Args,
85 ) -> Result<(), Error> {
86 let res = self.handle(op, global_args).await?;
87 if let TxnEnvelopeResult::TxnEnvelope(tx) = res {
88 println!("{}", tx.to_xdr_base64(Limits::none())?);
89 }
90 Ok(())
91 }
92
93 pub async fn handle_tx(
94 &self,
95 tx: xdr::Transaction,
96 args: &global::Args,
97 ) -> Result<TxnEnvelopeResult<GetTransactionResponse>, Error> {
98 let network = self.config.get_network()?;
99 let client = Client::new(&network.rpc_url)?;
100 if self.fee.build_only {
101 return Ok(TxnEnvelopeResult::TxnEnvelope(Box::new(tx.into())));
102 }
103
104 let txn_resp = client
105 .send_transaction_polling(&self.config.sign_with_local_key(tx).await?)
106 .await?;
107
108 if !args.no_cache {
109 data::write(txn_resp.clone().try_into().unwrap(), &network.rpc_uri()?)?;
110 }
111
112 Ok(TxnEnvelopeResult::Res(txn_resp))
113 }
114
115 pub async fn source_account(&self) -> Result<xdr::MuxedAccount, Error> {
116 Ok(self.config.source_account().await?)
117 }
118
119 pub fn resolve_muxed_address(
120 &self,
121 address: &UnresolvedMuxedAccount,
122 ) -> Result<xdr::MuxedAccount, Error> {
123 Ok(address.resolve_muxed_account_sync(&self.config.locator, self.config.hd_path)?)
124 }
125
126 pub fn resolve_account_id(
127 &self,
128 address: &UnresolvedMuxedAccount,
129 ) -> Result<xdr::AccountId, Error> {
130 Ok(address
131 .resolve_muxed_account_sync(&self.config.locator, self.config.hd_path)?
132 .account_id())
133 }
134
135 pub async fn add_op(
136 &self,
137 op_body: impl Into<xdr::OperationBody>,
138 tx_env: xdr::TransactionEnvelope,
139 op_source: Option<&address::UnresolvedMuxedAccount>,
140 ) -> Result<xdr::TransactionEnvelope, Error> {
141 let mut source_account = None;
142 if let Some(account) = op_source {
143 source_account = Some(
144 account
145 .resolve_muxed_account(&self.config.locator, self.config.hd_path)
146 .await?,
147 );
148 }
149 let op = xdr::Operation {
150 source_account,
151 body: op_body.into(),
152 };
153 Ok(super::xdr::add_op(tx_env, op)?)
154 }
155
156 pub fn resolve_asset(&self, asset: &builder::Asset) -> Result<xdr::Asset, Error> {
157 Ok(asset.resolve(&self.config.locator)?)
158 }
159}