use hedera_proto::services;
use hedera_proto::services::schedule_service_client::ScheduleServiceClient;
use time::OffsetDateTime;
use tonic::transport::Channel;
use super::schedulable_transaction_body::SchedulableTransactionBody;
use crate::protobuf::{
FromProtobuf,
ToProtobuf,
};
use crate::transaction::{
AnyTransactionData,
ChunkInfo,
ToSchedulableTransactionDataProtobuf,
ToTransactionDataProtobuf,
TransactionData,
TransactionExecute,
};
use crate::{
AccountId,
BoxGrpcFuture,
Error,
Key,
LedgerId,
Transaction,
ValidateChecksums,
};
pub type ScheduleCreateTransaction = Transaction<ScheduleCreateTransactionData>;
#[derive(Default, Debug, Clone)]
#[cfg_attr(feature = "ffi", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "ffi", serde(rename_all = "camelCase", default))]
pub struct ScheduleCreateTransactionData {
scheduled_transaction: Option<SchedulableTransactionBody>,
schedule_memo: Option<String>,
admin_key: Option<Key>,
payer_account_id: Option<AccountId>,
#[cfg_attr(
feature = "ffi",
serde(with = "serde_with::As::<Option<serde_with::TimestampNanoSeconds>>")
)]
expiration_time: Option<OffsetDateTime>,
wait_for_expiry: bool,
}
impl ScheduleCreateTransaction {
pub fn scheduled_transaction<D>(&mut self, transaction: Transaction<D>) -> &mut Self
where
D: TransactionExecute,
{
let body = transaction.into_body();
let data: AnyTransactionData = body.data.into();
self.data_mut().scheduled_transaction = Some(SchedulableTransactionBody {
max_transaction_fee: body.max_transaction_fee,
transaction_memo: body.transaction_memo,
data: Box::new(data.try_into().unwrap()),
});
self
}
#[must_use]
pub fn get_expiration_time(&self) -> Option<OffsetDateTime> {
self.data().expiration_time
}
pub fn expiration_time(&mut self, time: OffsetDateTime) -> &mut Self {
self.data_mut().expiration_time = Some(time);
self
}
#[must_use]
pub fn get_wait_for_expiry(&self) -> bool {
self.data().wait_for_expiry
}
pub fn wait_for_expiry(&mut self, wait: bool) -> &mut Self {
self.data_mut().wait_for_expiry = wait;
self
}
#[must_use]
pub fn get_payer_account_id(&self) -> Option<AccountId> {
self.data().payer_account_id
}
pub fn payer_account_id(&mut self, id: AccountId) -> &mut Self {
self.data_mut().payer_account_id = Some(id);
self
}
#[must_use]
pub fn get_schedule_memo(&self) -> Option<&str> {
self.data().schedule_memo.as_deref()
}
pub fn schedule_memo(&mut self, memo: impl Into<String>) -> &mut Self {
self.data_mut().schedule_memo = Some(memo.into());
self
}
#[must_use]
pub fn get_admin_key(&self) -> Option<&Key> {
self.data().admin_key.as_ref()
}
pub fn admin_key(&mut self, key: impl Into<Key>) -> &mut Self {
self.data_mut().admin_key = Some(key.into());
self
}
}
impl TransactionData for ScheduleCreateTransactionData {}
impl TransactionExecute for ScheduleCreateTransactionData {
fn execute(
&self,
channel: Channel,
request: services::Transaction,
) -> BoxGrpcFuture<'_, services::TransactionResponse> {
Box::pin(async { ScheduleServiceClient::new(channel).create_schedule(request).await })
}
}
impl ValidateChecksums for ScheduleCreateTransactionData {
fn validate_checksums(&self, ledger_id: &LedgerId) -> Result<(), Error> {
self.payer_account_id.validate_checksums(ledger_id)
}
}
impl ToTransactionDataProtobuf for ScheduleCreateTransactionData {
#[allow(clippy::too_many_lines)]
fn to_transaction_data_protobuf(
&self,
chunk_info: &ChunkInfo,
) -> services::transaction_body::Data {
let _ = chunk_info.assert_single_transaction();
let body = self.scheduled_transaction.as_ref().map(|scheduled| {
let data = scheduled.data.to_schedulable_transaction_data_protobuf();
services::SchedulableTransactionBody {
data: Some(data),
memo: scheduled.transaction_memo.clone(),
transaction_fee: scheduled
.max_transaction_fee
.unwrap_or_else(|| scheduled.data.default_max_transaction_fee())
.to_tinybars() as u64,
}
});
let payer_account_id = self.payer_account_id.to_protobuf();
let admin_key = self.admin_key.to_protobuf();
let expiration_time = self.expiration_time.map(Into::into);
services::transaction_body::Data::ScheduleCreate(services::ScheduleCreateTransactionBody {
scheduled_transaction_body: body,
memo: self.schedule_memo.clone().unwrap_or_default(),
admin_key,
payer_account_id,
expiration_time,
wait_for_expiry: self.wait_for_expiry,
})
}
}
impl From<ScheduleCreateTransactionData> for AnyTransactionData {
fn from(transaction: ScheduleCreateTransactionData) -> Self {
Self::ScheduleCreate(transaction)
}
}
impl FromProtobuf<services::ScheduleCreateTransactionBody> for ScheduleCreateTransactionData {
fn from_protobuf(pb: services::ScheduleCreateTransactionBody) -> crate::Result<Self> {
Ok(Self {
scheduled_transaction: Option::from_protobuf(pb.scheduled_transaction_body)?,
schedule_memo: Some(pb.memo),
admin_key: Option::from_protobuf(pb.admin_key)?,
payer_account_id: Option::from_protobuf(pb.payer_account_id)?,
expiration_time: pb.expiration_time.map(Into::into),
wait_for_expiry: pb.wait_for_expiry,
})
}
}