From 6fc3c517f8c5a9c62ac2decaea045d8ea5533143 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Fri, 22 Jul 2022 17:05:51 -0600 Subject: [PATCH] cosmrs: add `tx::BodyBuilder` Adds a builder type for constructing `tx::Body`. --- cosmrs/src/error.rs | 2 +- cosmrs/src/tx.rs | 2 + cosmrs/src/tx/body.rs | 9 ++++- cosmrs/src/tx/builder.rs | 73 +++++++++++++++++++++++++++++++++++++ cosmrs/tests/integration.rs | 3 +- 5 files changed, 84 insertions(+), 5 deletions(-) create mode 100644 cosmrs/src/tx/builder.rs diff --git a/cosmrs/src/error.rs b/cosmrs/src/error.rs index c455c25c..0958625b 100644 --- a/cosmrs/src/error.rs +++ b/cosmrs/src/error.rs @@ -46,7 +46,7 @@ pub enum Error { /// Expected type URL. expected: &'static str, - /// Actual type URL found in the [`prost_types::Any`] message. + /// Actual type URL found in the [`crate::Any`] message. found: String, }, diff --git a/cosmrs/src/tx.rs b/cosmrs/src/tx.rs index 3dd2f538..d038298b 100644 --- a/cosmrs/src/tx.rs +++ b/cosmrs/src/tx.rs @@ -106,6 +106,7 @@ pub mod mode_info; mod auth_info; mod body; +mod builder; mod fee; mod msg; mod raw; @@ -115,6 +116,7 @@ mod signer_info; pub use self::{ auth_info::AuthInfo, body::Body, + builder::BodyBuilder, fee::Fee, mode_info::ModeInfo, msg::Msg, diff --git a/cosmrs/src/tx/body.rs b/cosmrs/src/tx/body.rs index d7cf7047..e1fee462 100644 --- a/cosmrs/src/tx/body.rs +++ b/cosmrs/src/tx/body.rs @@ -2,9 +2,8 @@ use crate::{ proto::{self, traits::MessageExt}, - ErrorReport, Result, + Any, ErrorReport, Result, }; -use prost_types::Any; use tendermint::block; /// [`Body`] of a transaction that all signers sign over. @@ -70,6 +69,12 @@ impl Body { } } +impl Default for Body { + fn default() -> Body { + Self::new([], "", 0u8) + } +} + impl From for proto::cosmos::tx::v1beta1::TxBody { fn from(body: Body) -> proto::cosmos::tx::v1beta1::TxBody { proto::cosmos::tx::v1beta1::TxBody { diff --git a/cosmrs/src/tx/builder.rs b/cosmrs/src/tx/builder.rs new file mode 100644 index 00000000..6921c657 --- /dev/null +++ b/cosmrs/src/tx/builder.rs @@ -0,0 +1,73 @@ +//! Transaction builder. + +use super::Body; +use crate::Any; +use tendermint::block; + +/// Transaction [`Body`] builder which simplifies incrementally assembling and +/// signing a transaction. +#[derive(Clone, Debug, Default)] +pub struct BodyBuilder { + /// Transaction body in-progress. + body: Body, +} + +impl BodyBuilder { + /// Create a new transaction builder in the default state. + pub fn new() -> Self { + Self::default() + } + + /// Add a message to the transaction. + pub fn msg(&mut self, msg: impl Into) -> &mut Self { + self.body.messages.push(msg.into()); + self + } + + /// Add multiple messages to the transaction. + pub fn msgs(&mut self, msgs: impl IntoIterator) -> &mut Self { + self.body.messages.extend(msgs); + self + } + + /// Set the transaction memo. + pub fn memo(&mut self, memo: impl Into) -> &mut Self { + self.body.memo = memo.into(); + self + } + + /// Set the timeout height. + pub fn timeout_height(&mut self, height: impl Into) -> &mut Self { + self.body.timeout_height = height.into(); + self + } + + /// Add an extension option. + pub fn extension_option(&mut self, option: impl Into) -> &mut Self { + self.body.extension_options.push(option.into()); + self + } + + /// Add a non-critical extension option. + pub fn non_critical_extension_option(&mut self, option: impl Into) -> &mut Self { + self.body.extension_options.push(option.into()); + self + } + + /// Return the finished [`Body`]. + pub fn finish(&self) -> Body { + self.into() + } +} + +impl From for Body { + fn from(builder: BodyBuilder) -> Body { + builder.body + } +} + +impl From<&BodyBuilder> for Body { + fn from(builder: &BodyBuilder) -> Body { + builder.body.clone() + } +} diff --git a/cosmrs/tests/integration.rs b/cosmrs/tests/integration.rs index ce3b608d..71247762 100644 --- a/cosmrs/tests/integration.rs +++ b/cosmrs/tests/integration.rs @@ -60,9 +60,8 @@ fn msg_send() { let sequence_number = 0; let gas = 100_000; let fee = Fee::from_amount_and_gas(amount, gas); - let timeout_height = 9001u16; - let tx_body = tx::Body::new(vec![msg_send], MEMO, timeout_height); + let tx_body = tx::BodyBuilder::new().msg(msg_send).memo(MEMO).finish(); let auth_info = SignerInfo::single_direct(Some(sender_public_key), sequence_number).auth_info(fee); let sign_doc = SignDoc::new(&tx_body, &auth_info, &chain_id, ACCOUNT_NUMBER).unwrap();