use std::fmt;
use std::fmt::{
Debug,
Formatter,
};
use time::Duration;
use crate::execute::execute;
use crate::signer::AnySigner;
use crate::{
AccountId,
Client,
Hbar,
PrivateKey,
PublicKey,
Signer,
TransactionId,
TransactionResponse,
};
mod any;
mod execute;
mod protobuf;
#[cfg(feature = "ffi")]
pub use any::AnyTransaction;
#[cfg(feature = "ffi")]
pub(crate) use any::AnyTransactionBody;
pub(crate) use any::AnyTransactionData;
pub(crate) use execute::TransactionExecute;
pub(crate) use protobuf::ToTransactionDataProtobuf;
const DEFAULT_TRANSACTION_VALID_DURATION: Duration = Duration::seconds(120);
#[cfg_attr(feature = "ffi", derive(serde::Serialize))]
pub struct Transaction<D>
where
D: TransactionExecute,
{
#[cfg_attr(feature = "ffi", serde(flatten))]
pub(crate) body: TransactionBody<D>,
#[cfg_attr(feature = "ffi", serde(skip))]
pub(crate) signers: Vec<AnySigner>,
}
#[cfg_attr(feature = "ffi", serde_with::skip_serializing_none)]
#[derive(Debug, Default, Clone)]
#[cfg_attr(feature = "ffi", derive(serde::Serialize))]
#[cfg_attr(feature = "ffi", serde(rename_all = "camelCase"))]
#[allow(clippy::type_repetition_in_bounds)]
pub(crate) struct TransactionBody<D>
where
D: TransactionExecute,
{
#[cfg_attr(feature = "ffi", serde(flatten))]
#[cfg_attr(
feature = "ffi",
serde(with = "serde_with::As::<serde_with::FromInto<AnyTransactionData>>")
)]
pub(crate) data: D,
pub(crate) node_account_ids: Option<Vec<AccountId>>,
#[cfg_attr(
feature = "ffi",
serde(with = "serde_with::As::<Option<serde_with::DurationSeconds<i64>>>")
)]
pub(crate) transaction_valid_duration: Option<Duration>,
pub(crate) max_transaction_fee: Option<Hbar>,
#[cfg_attr(feature = "ffi", serde(skip_serializing_if = "String::is_empty"))]
pub(crate) transaction_memo: String,
pub(crate) payer_account_id: Option<AccountId>,
pub(crate) transaction_id: Option<TransactionId>,
}
impl<D> Default for Transaction<D>
where
D: Default + TransactionExecute,
{
fn default() -> Self {
Self {
body: TransactionBody {
data: D::default(),
node_account_ids: None,
transaction_valid_duration: None,
transaction_memo: String::new(),
max_transaction_fee: None,
payer_account_id: None,
transaction_id: None,
},
signers: Vec::new(),
}
}
}
impl<D> Debug for Transaction<D>
where
D: Debug + TransactionExecute,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("Transaction").field("body", &self.body).finish()
}
}
impl<D> Transaction<D>
where
D: Default + TransactionExecute,
{
#[inline]
#[must_use]
pub fn new() -> Self {
Self::default()
}
}
impl<D> Transaction<D>
where
D: TransactionExecute,
{
pub fn node_account_ids(&mut self, ids: impl IntoIterator<Item = AccountId>) -> &mut Self {
self.body.node_account_ids = Some(ids.into_iter().collect());
self
}
pub fn transaction_valid_duration(&mut self, duration: Duration) -> &mut Self {
self.body.transaction_valid_duration = Some(duration);
self
}
pub fn max_transaction_fee(&mut self, fee: Hbar) -> &mut Self {
self.body.max_transaction_fee = Some(fee);
self
}
pub fn transaction_memo(&mut self, memo: impl AsRef<str>) -> &mut Self {
self.body.transaction_memo = memo.as_ref().to_owned();
self
}
pub fn transaction_id(&mut self, id: TransactionId) -> &mut Self {
self.body.transaction_id = Some(id);
self
}
pub fn sign(&mut self, private_key: PrivateKey) -> &mut Self {
self.sign_signer(AnySigner::PrivateKey(private_key))
}
pub fn sign_with<F>(&mut self, public_key: PublicKey, signer: Signer) -> &mut Self {
self.sign_signer(AnySigner::Arbitrary(Box::new(public_key), signer))
}
pub(crate) fn sign_signer(&mut self, signer: AnySigner) -> &mut Self {
self.signers.push(signer);
self
}
}
impl<D> Transaction<D>
where
D: TransactionExecute,
{
#[allow(clippy::missing_errors_doc)]
pub async fn execute(&mut self, client: &Client) -> crate::Result<TransactionResponse> {
execute(client, self, None).await
}
#[cfg(feature = "ffi")]
pub(crate) async fn execute_with_optional_timeout(
&mut self,
client: &Client,
timeout: Option<std::time::Duration>,
) -> crate::Result<TransactionResponse> {
execute(client, self, timeout).await
}
#[allow(clippy::missing_errors_doc)]
pub async fn execute_with_timeout(
&mut self,
client: &Client,
timeout: std::time::Duration,
) -> crate::Result<TransactionResponse> {
execute(client, self, timeout).await
}
}