cosm_tome/modules/tx/
api.rs1use cosmrs::proto::cosmos::tx::v1beta1::TxRaw;
2use cosmrs::tx::Body;
3use cosmrs::tx::SignerInfo;
4use serde::Serialize;
5
6use crate::chain::coin::{Coin, Denom};
7use crate::chain::error::ChainError;
8use crate::chain::msg::Msg;
9use crate::chain::response::AsyncChainTxResponse;
10use crate::modules::auth::model::{Account, Address};
11use crate::{
12 chain::{fee::Fee, request::TxOptions, response::ChainTxResponse, Any},
13 clients::client::{CosmTome, CosmosClient},
14 signing_key::key::SigningKey,
15};
16
17use super::error::TxError;
18use super::model::{BroadcastMode, RawTx};
19
20impl<T: CosmosClient> CosmTome<T> {
26 pub async fn tx_sign(
27 &self,
28 msgs: Vec<impl Msg + Serialize>,
29 sender_addr: Option<Address>,
30 key: &SigningKey,
31 tx_options: &TxOptions,
32 ) -> Result<RawTx, TxError> {
33 let sender_addr = if let Some(sender_addr) = sender_addr {
34 sender_addr
35 } else {
36 key.to_addr(&self.cfg.prefix).await?
37 };
38
39 let timeout_height = tx_options.timeout_height.unwrap_or_default();
40 let account = self.auth_query_account(sender_addr).await?.account;
41
42 let sim_fee = self
44 .tx_simulate(
45 msgs.iter()
46 .map(|m| m.to_any())
47 .collect::<Result<Vec<_>, _>>()
48 .map_err(|e| ChainError::ProtoEncoding {
49 message: e.to_string(),
50 })?,
51 &account,
52 )
53 .await?;
54
55 let fee = if let Some(fee) = &tx_options.fee {
56 fee.clone()
57 } else {
58 sim_fee
59 };
60
61 let raw = key
62 .sign(
63 msgs,
64 timeout_height,
65 &tx_options.memo,
66 account,
67 fee,
68 &self.cfg,
69 )
70 .await?;
71 Ok(raw)
72 }
73
74 pub async fn tx_simulate<I>(&self, msgs: I, account: &Account) -> Result<Fee, TxError>
77 where
78 I: IntoIterator<Item = Any>,
79 {
80 let tx = Body::new(msgs, "cosm-client memo", 0u16);
81
82 let denom: Denom = self.cfg.denom.parse()?;
83
84 let fee = Fee::new(
85 Coin {
86 denom: denom.clone(),
87 amount: 0u128,
88 },
89 0u64,
90 None,
91 None,
92 );
93
94 let auth_info =
95 SignerInfo::single_direct(None, account.sequence).auth_info(fee.try_into()?);
96
97 let tx_raw = TxRaw {
98 body_bytes: tx.into_bytes().map_err(ChainError::proto_encoding)?,
99 auth_info_bytes: auth_info.into_bytes().map_err(ChainError::proto_encoding)?,
100 signatures: vec![vec![]],
101 };
102
103 let gas_info = self.client.simulate_tx(&tx_raw.into()).await?;
104
105 let gas_limit = (gas_info.gas_used.value() as f64 * self.cfg.gas_adjustment).ceil();
107 let amount = Coin {
108 denom,
109 amount: ((gas_limit * self.cfg.gas_price).ceil() as u64).into(),
110 };
111
112 let fee = Fee::new(amount, gas_limit as u64, None, None);
113
114 Ok(fee)
115 }
116
117 pub async fn tx_broadcast(
119 &self,
120 tx: &RawTx,
121 mode: BroadcastMode,
122 ) -> Result<AsyncChainTxResponse, TxError> {
123 Ok(self.client.broadcast_tx(tx, mode).await?)
124 }
125
126 pub async fn tx_broadcast_block(&self, tx: &RawTx) -> Result<ChainTxResponse, TxError> {
128 Ok(self.client.broadcast_tx_block(tx).await?)
129 }
130}