use async_trait::async_trait;
use hedera_proto::services;
use hedera_proto::services::crypto_service_client::CryptoServiceClient;
use tonic::transport::Channel;
use crate::entity_id::AutoValidateChecksum;
use crate::protobuf::ToProtobuf;
use crate::transaction::{
AnyTransactionData,
ToTransactionDataProtobuf,
TransactionExecute,
};
use crate::{
AccountId,
Error,
LedgerId,
NftId,
TokenId,
Transaction,
};
pub type AccountAllowanceDeleteTransaction = Transaction<AccountAllowanceDeleteTransactionData>;
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "ffi", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "ffi", serde(rename_all = "camelCase"))]
pub struct AccountAllowanceDeleteTransactionData {
pub nft_allowances: Vec<NftRemoveAllowance>,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "ffi", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "ffi", serde(rename_all = "camelCase"))]
pub struct NftRemoveAllowance {
pub token_id: TokenId,
pub owner_account_id: AccountId,
pub serials: Vec<i64>,
}
impl AccountAllowanceDeleteTransaction {
pub fn delete_all_token_nft_allowances(
&mut self,
nft_id: NftId,
owner_account_id: AccountId,
) -> &mut Self {
let owner_account_id = owner_account_id;
if let Some(allowance) = self.body.data.nft_allowances.iter_mut().find(|allowance| {
allowance.token_id == nft_id.token_id && allowance.owner_account_id == owner_account_id
}) {
allowance.serials.push(nft_id.serial as i64);
} else {
self.body.data.nft_allowances.push(NftRemoveAllowance {
token_id: nft_id.token_id,
serials: vec![nft_id.serial as i64],
owner_account_id,
});
}
self
}
}
#[async_trait]
impl TransactionExecute for AccountAllowanceDeleteTransactionData {
fn validate_checksums_for_ledger_id(&self, ledger_id: &LedgerId) -> Result<(), Error> {
for allowance in &self.nft_allowances {
allowance.token_id.validate_checksum_for_ledger_id(ledger_id)?;
allowance.owner_account_id.validate_checksum_for_ledger_id(ledger_id)?;
}
Ok(())
}
async fn execute(
&self,
channel: Channel,
request: services::Transaction,
) -> Result<tonic::Response<services::TransactionResponse>, tonic::Status> {
CryptoServiceClient::new(channel).delete_allowances(request).await
}
}
impl ToTransactionDataProtobuf for AccountAllowanceDeleteTransactionData {
fn to_transaction_data_protobuf(
&self,
_node_account_id: AccountId,
_transaction_id: &crate::TransactionId,
) -> services::transaction_body::Data {
let nft_allowances = self.nft_allowances.to_protobuf();
services::transaction_body::Data::CryptoDeleteAllowance(
services::CryptoDeleteAllowanceTransactionBody { nft_allowances },
)
}
}
impl From<AccountAllowanceDeleteTransactionData> for AnyTransactionData {
fn from(transaction: AccountAllowanceDeleteTransactionData) -> Self {
Self::AccountAllowanceDelete(transaction)
}
}
impl ToProtobuf for NftRemoveAllowance {
type Protobuf = services::NftRemoveAllowance;
fn to_protobuf(&self) -> Self::Protobuf {
Self::Protobuf {
token_id: Some(self.token_id.to_protobuf()),
owner: Some(self.owner_account_id.to_protobuf()),
serial_numbers: self.serials.clone(),
}
}
}