Skip to main content

hiero_sdk/transaction/
any.rs

1// SPDX-License-Identifier: Apache-2.0
2
3use hiero_sdk_proto::services;
4use tonic::transport::Channel;
5
6use super::chunked::ChunkInfo;
7use super::{
8    TransactionData,
9    TransactionExecuteChunked,
10};
11use crate::custom_fee_limit::CustomFeeLimit;
12use crate::downcast::DowncastOwned;
13use crate::entity_id::ValidateChecksums;
14use crate::ledger_id::RefLedgerId;
15use crate::protobuf::FromProtobuf;
16use crate::transaction::{
17    ToTransactionDataProtobuf,
18    TransactionBody,
19    TransactionExecute,
20};
21use crate::{
22    AccountId,
23    BoxGrpcFuture,
24    Error,
25    Hbar,
26    Transaction,
27    TransactionId,
28};
29
30mod data {
31    pub(super) use crate::account::{
32        AccountAllowanceApproveTransactionData as AccountAllowanceApprove,
33        AccountAllowanceDeleteTransactionData as AccountAllowanceDelete,
34        AccountCreateTransactionData as AccountCreate,
35        AccountDeleteTransactionData as AccountDelete,
36        AccountUpdateTransactionData as AccountUpdate,
37    };
38    pub(super) use crate::address_book::{
39        NodeCreateTransactionData as NodeCreate,
40        NodeDeleteTransactionData as NodeDelete,
41        NodeUpdateTransactionData as NodeUpdate,
42    };
43    pub(super) use crate::batch_transaction::BatchTransactionData as Batch;
44    pub(super) use crate::contract::{
45        ContractCreateTransactionData as ContractCreate,
46        ContractDeleteTransactionData as ContractDelete,
47        ContractExecuteTransactionData as ContractExecute,
48        ContractUpdateTransactionData as ContractUpdate,
49    };
50    pub(super) use crate::ethereum::EthereumTransactionData as Ethereum;
51    pub(super) use crate::file::{
52        FileAppendTransactionData as FileAppend,
53        FileCreateTransactionData as FileCreate,
54        FileDeleteTransactionData as FileDelete,
55        FileUpdateTransactionData as FileUpdate,
56    };
57    pub(super) use crate::hooks::HookStoreTransactionData as HookStore;
58    pub(super) use crate::prng_transaction::PrngTransactionData as Prng;
59    pub(super) use crate::schedule::{
60        ScheduleCreateTransactionData as ScheduleCreate,
61        ScheduleDeleteTransactionData as ScheduleDelete,
62        ScheduleSignTransactionData as ScheduleSign,
63    };
64    pub(super) use crate::system::{
65        FreezeTransactionData as Freeze,
66        SystemDeleteTransactionData as SystemDelete,
67        SystemUndeleteTransactionData as SystemUndelete,
68    };
69    pub(super) use crate::token::{
70        TokenAirdropTransactionData as TokenAirdrop,
71        TokenAssociateTransactionData as TokenAssociate,
72        TokenBurnTransactionData as TokenBurn,
73        TokenCancelAirdropTransactionData as TokenCancelAirdrop,
74        TokenClaimAirdropTransactionData as TokenClaimAirdrop,
75        TokenCreateTransactionData as TokenCreate,
76        TokenDeleteTransactionData as TokenDelete,
77        TokenDissociateTransactionData as TokenDissociate,
78        TokenFeeScheduleUpdateTransactionData as TokenFeeScheduleUpdate,
79        TokenFreezeTransactionData as TokenFreeze,
80        TokenGrantKycTransactionData as TokenGrantKyc,
81        TokenMintTransactionData as TokenMint,
82        TokenPauseTransactionData as TokenPause,
83        TokenRejectTransactionData as TokenReject,
84        TokenRevokeKycTransactionData as TokenRevokeKyc,
85        TokenUnfreezeTransactionData as TokenUnfreeze,
86        TokenUnpauseTransactionData as TokenUnpause,
87        TokenUpdateNftsTransactionData as TokenUpdateNfts,
88        TokenUpdateTransactionData as TokenUpdate,
89        TokenWipeTransactionData as TokenWipe,
90    };
91    pub(super) use crate::topic::{
92        TopicCreateTransactionData as TopicCreate,
93        TopicDeleteTransactionData as TopicDelete,
94        TopicMessageSubmitTransactionData as TopicMessageSubmit,
95        TopicUpdateTransactionData as TopicUpdate,
96    };
97    pub(super) use crate::transfer_transaction::TransferTransactionData as Transfer;
98}
99
100/// Any possible transaction that may be executed on the Hiero network.
101pub type AnyTransaction = Transaction<AnyTransactionData>;
102
103#[derive(Debug, Clone)]
104#[non_exhaustive]
105pub enum AnyTransactionData {
106    AccountCreate(data::AccountCreate),
107    AccountUpdate(data::AccountUpdate),
108    AccountDelete(data::AccountDelete),
109    AccountAllowanceApprove(data::AccountAllowanceApprove),
110    AccountAllowanceDelete(data::AccountAllowanceDelete),
111    ContractCreate(data::ContractCreate),
112    ContractUpdate(data::ContractUpdate),
113    ContractDelete(data::ContractDelete),
114    ContractExecute(data::ContractExecute),
115    Transfer(data::Transfer),
116    TopicCreate(data::TopicCreate),
117    TopicUpdate(data::TopicUpdate),
118    TopicDelete(data::TopicDelete),
119    TopicMessageSubmit(data::TopicMessageSubmit),
120    FileAppend(data::FileAppend),
121    FileCreate(data::FileCreate),
122    FileUpdate(data::FileUpdate),
123    FileDelete(data::FileDelete),
124    Prng(data::Prng),
125    ScheduleCreate(data::ScheduleCreate),
126    ScheduleSign(data::ScheduleSign),
127    ScheduleDelete(data::ScheduleDelete),
128    TokenAssociate(data::TokenAssociate),
129    TokenBurn(data::TokenBurn),
130    TokenCreate(data::TokenCreate),
131    TokenDelete(data::TokenDelete),
132    TokenDissociate(data::TokenDissociate),
133    TokenFeeScheduleUpdate(data::TokenFeeScheduleUpdate),
134    TokenFreeze(data::TokenFreeze),
135    TokenGrantKyc(data::TokenGrantKyc),
136    TokenMint(data::TokenMint),
137    TokenPause(data::TokenPause),
138    TokenRevokeKyc(data::TokenRevokeKyc),
139    TokenUnfreeze(data::TokenUnfreeze),
140    TokenUnpause(data::TokenUnpause),
141    TokenUpdate(data::TokenUpdate),
142    TokenWipe(data::TokenWipe),
143    SystemDelete(data::SystemDelete),
144    SystemUndelete(data::SystemUndelete),
145    Freeze(data::Freeze),
146    Ethereum(data::Ethereum),
147    TokenUpdateNfts(data::TokenUpdateNfts),
148    NodeCreate(data::NodeCreate),
149    NodeUpdate(data::NodeUpdate),
150    NodeDelete(data::NodeDelete),
151    TokenReject(data::TokenReject),
152    TokenAirdrop(data::TokenAirdrop),
153    TokenClaimAirdrop(data::TokenClaimAirdrop),
154    TokenCancelAirdrop(data::TokenCancelAirdrop),
155    Batch(data::Batch),
156    HookStore(data::HookStore),
157}
158
159impl ToTransactionDataProtobuf for AnyTransactionData {
160    // not really anything I can do about this
161    #[allow(clippy::too_many_lines)]
162    fn to_transaction_data_protobuf(
163        &self,
164        chunk_info: &ChunkInfo,
165    ) -> services::transaction_body::Data {
166        match self {
167            Self::Transfer(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
168
169            Self::AccountCreate(transaction) => {
170                transaction.to_transaction_data_protobuf(chunk_info)
171            }
172
173            Self::AccountUpdate(transaction) => {
174                transaction.to_transaction_data_protobuf(chunk_info)
175            }
176
177            Self::AccountDelete(transaction) => {
178                transaction.to_transaction_data_protobuf(chunk_info)
179            }
180
181            Self::AccountAllowanceApprove(transaction) => {
182                transaction.to_transaction_data_protobuf(chunk_info)
183            }
184
185            Self::AccountAllowanceDelete(transaction) => {
186                transaction.to_transaction_data_protobuf(chunk_info)
187            }
188
189            Self::ContractCreate(transaction) => {
190                transaction.to_transaction_data_protobuf(chunk_info)
191            }
192
193            Self::ContractUpdate(transaction) => {
194                transaction.to_transaction_data_protobuf(chunk_info)
195            }
196
197            Self::ContractDelete(transaction) => {
198                transaction.to_transaction_data_protobuf(chunk_info)
199            }
200
201            Self::ContractExecute(transaction) => {
202                transaction.to_transaction_data_protobuf(chunk_info)
203            }
204
205            Self::FileAppend(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
206
207            Self::FileCreate(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
208
209            Self::FileUpdate(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
210
211            Self::FileDelete(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
212
213            Self::Prng(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
214
215            Self::TokenAssociate(transaction) => {
216                transaction.to_transaction_data_protobuf(chunk_info)
217            }
218
219            Self::TokenBurn(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
220
221            Self::TokenCreate(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
222
223            Self::TokenDelete(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
224
225            Self::TokenDissociate(transaction) => {
226                transaction.to_transaction_data_protobuf(chunk_info)
227            }
228
229            Self::TokenFeeScheduleUpdate(transaction) => {
230                transaction.to_transaction_data_protobuf(chunk_info)
231            }
232
233            Self::TokenFreeze(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
234
235            Self::TokenGrantKyc(transaction) => {
236                transaction.to_transaction_data_protobuf(chunk_info)
237            }
238
239            Self::TokenMint(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
240
241            Self::TokenPause(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
242
243            Self::TokenRevokeKyc(transaction) => {
244                transaction.to_transaction_data_protobuf(chunk_info)
245            }
246
247            Self::TokenUnfreeze(transaction) => {
248                transaction.to_transaction_data_protobuf(chunk_info)
249            }
250
251            Self::TokenUnpause(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
252
253            Self::TokenUpdate(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
254
255            Self::TokenWipe(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
256
257            Self::TopicCreate(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
258
259            Self::TopicUpdate(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
260
261            Self::TopicDelete(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
262
263            Self::TokenReject(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
264
265            Self::TopicMessageSubmit(transaction) => {
266                transaction.to_transaction_data_protobuf(chunk_info)
267            }
268
269            Self::SystemDelete(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
270
271            Self::SystemUndelete(transaction) => {
272                transaction.to_transaction_data_protobuf(chunk_info)
273            }
274
275            Self::Freeze(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
276
277            Self::ScheduleCreate(transaction) => {
278                transaction.to_transaction_data_protobuf(chunk_info)
279            }
280
281            Self::ScheduleSign(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
282
283            Self::ScheduleDelete(transaction) => {
284                transaction.to_transaction_data_protobuf(chunk_info)
285            }
286
287            Self::Ethereum(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
288
289            Self::TokenUpdateNfts(transaction) => {
290                transaction.to_transaction_data_protobuf(chunk_info)
291            }
292
293            Self::NodeCreate(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
294
295            Self::NodeUpdate(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
296
297            Self::NodeDelete(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
298
299            Self::TokenAirdrop(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
300
301            Self::TokenClaimAirdrop(transaction) => {
302                transaction.to_transaction_data_protobuf(chunk_info)
303            }
304            Self::TokenCancelAirdrop(transaction) => {
305                transaction.to_transaction_data_protobuf(chunk_info)
306            }
307            Self::Batch(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
308            Self::HookStore(transaction) => transaction.to_transaction_data_protobuf(chunk_info),
309        }
310    }
311}
312
313impl TransactionData for AnyTransactionData {
314    fn default_max_transaction_fee(&self) -> Hbar {
315        match self {
316            Self::Transfer(transaction) => transaction.default_max_transaction_fee(),
317            Self::AccountCreate(transaction) => transaction.default_max_transaction_fee(),
318            Self::AccountUpdate(transaction) => transaction.default_max_transaction_fee(),
319            Self::AccountDelete(transaction) => transaction.default_max_transaction_fee(),
320            Self::AccountAllowanceApprove(transaction) => transaction.default_max_transaction_fee(),
321            Self::AccountAllowanceDelete(transaction) => transaction.default_max_transaction_fee(),
322            Self::ContractCreate(transaction) => transaction.default_max_transaction_fee(),
323            Self::ContractUpdate(transaction) => transaction.default_max_transaction_fee(),
324            Self::ContractDelete(transaction) => transaction.default_max_transaction_fee(),
325            Self::ContractExecute(transaction) => transaction.default_max_transaction_fee(),
326            Self::FileAppend(transaction) => transaction.default_max_transaction_fee(),
327            Self::FileCreate(transaction) => transaction.default_max_transaction_fee(),
328            Self::FileUpdate(transaction) => transaction.default_max_transaction_fee(),
329            Self::FileDelete(transaction) => transaction.default_max_transaction_fee(),
330            Self::Prng(transaction) => transaction.default_max_transaction_fee(),
331            Self::TokenAssociate(transaction) => transaction.default_max_transaction_fee(),
332            Self::TokenBurn(transaction) => transaction.default_max_transaction_fee(),
333            Self::TokenCreate(transaction) => transaction.default_max_transaction_fee(),
334            Self::TokenDelete(transaction) => transaction.default_max_transaction_fee(),
335            Self::TokenDissociate(transaction) => transaction.default_max_transaction_fee(),
336            Self::TokenFeeScheduleUpdate(transaction) => transaction.default_max_transaction_fee(),
337            Self::TokenFreeze(transaction) => transaction.default_max_transaction_fee(),
338            Self::TokenGrantKyc(transaction) => transaction.default_max_transaction_fee(),
339            Self::TokenMint(transaction) => transaction.default_max_transaction_fee(),
340            Self::TokenPause(transaction) => transaction.default_max_transaction_fee(),
341            Self::TokenRevokeKyc(transaction) => transaction.default_max_transaction_fee(),
342            Self::TokenUnfreeze(transaction) => transaction.default_max_transaction_fee(),
343            Self::TokenUnpause(transaction) => transaction.default_max_transaction_fee(),
344            Self::TokenUpdate(transaction) => transaction.default_max_transaction_fee(),
345            Self::TokenWipe(transaction) => transaction.default_max_transaction_fee(),
346            Self::TopicCreate(transaction) => transaction.default_max_transaction_fee(),
347            Self::TopicUpdate(transaction) => transaction.default_max_transaction_fee(),
348            Self::TopicDelete(transaction) => transaction.default_max_transaction_fee(),
349            Self::TopicMessageSubmit(transaction) => transaction.default_max_transaction_fee(),
350            Self::SystemDelete(transaction) => transaction.default_max_transaction_fee(),
351            Self::SystemUndelete(transaction) => transaction.default_max_transaction_fee(),
352            Self::Freeze(transaction) => transaction.default_max_transaction_fee(),
353            Self::ScheduleCreate(transaction) => transaction.default_max_transaction_fee(),
354            Self::ScheduleSign(transaction) => transaction.default_max_transaction_fee(),
355            Self::ScheduleDelete(transaction) => transaction.default_max_transaction_fee(),
356            Self::Ethereum(transaction) => transaction.default_max_transaction_fee(),
357            Self::TokenUpdateNfts(transaction) => transaction.default_max_transaction_fee(),
358            Self::NodeCreate(transaction) => transaction.default_max_transaction_fee(),
359            Self::NodeUpdate(transaction) => transaction.default_max_transaction_fee(),
360            Self::NodeDelete(transaction) => transaction.default_max_transaction_fee(),
361            Self::TokenReject(transaction) => transaction.default_max_transaction_fee(),
362            Self::TokenAirdrop(transaction) => transaction.default_max_transaction_fee(),
363            Self::TokenClaimAirdrop(transaction) => transaction.default_max_transaction_fee(),
364            Self::TokenCancelAirdrop(transaction) => transaction.default_max_transaction_fee(),
365            Self::Batch(transaction) => transaction.default_max_transaction_fee(),
366            Self::HookStore(transaction) => transaction.default_max_transaction_fee(),
367        }
368    }
369
370    fn maybe_chunk_data(&self) -> Option<&super::ChunkData> {
371        match self {
372            Self::AccountCreate(it) => it.maybe_chunk_data(),
373            Self::AccountUpdate(it) => it.maybe_chunk_data(),
374            Self::AccountDelete(it) => it.maybe_chunk_data(),
375            Self::AccountAllowanceApprove(it) => it.maybe_chunk_data(),
376            Self::AccountAllowanceDelete(it) => it.maybe_chunk_data(),
377            Self::ContractCreate(it) => it.maybe_chunk_data(),
378            Self::ContractUpdate(it) => it.maybe_chunk_data(),
379            Self::ContractDelete(it) => it.maybe_chunk_data(),
380            Self::ContractExecute(it) => it.maybe_chunk_data(),
381            Self::Transfer(it) => it.maybe_chunk_data(),
382            Self::TopicCreate(it) => it.maybe_chunk_data(),
383            Self::TopicUpdate(it) => it.maybe_chunk_data(),
384            Self::TopicDelete(it) => it.maybe_chunk_data(),
385            Self::TopicMessageSubmit(it) => it.maybe_chunk_data(),
386            Self::FileAppend(it) => it.maybe_chunk_data(),
387            Self::FileCreate(it) => it.maybe_chunk_data(),
388            Self::FileUpdate(it) => it.maybe_chunk_data(),
389            Self::FileDelete(it) => it.maybe_chunk_data(),
390            Self::Prng(it) => it.maybe_chunk_data(),
391            Self::TokenAssociate(it) => it.maybe_chunk_data(),
392            Self::TokenBurn(it) => it.maybe_chunk_data(),
393            Self::TokenCreate(it) => it.maybe_chunk_data(),
394            Self::TokenDelete(it) => it.maybe_chunk_data(),
395            Self::TokenDissociate(it) => it.maybe_chunk_data(),
396            Self::TokenFeeScheduleUpdate(it) => it.maybe_chunk_data(),
397            Self::TokenFreeze(it) => it.maybe_chunk_data(),
398            Self::TokenGrantKyc(it) => it.maybe_chunk_data(),
399            Self::TokenMint(it) => it.maybe_chunk_data(),
400            Self::TokenPause(it) => it.maybe_chunk_data(),
401            Self::TokenRevokeKyc(it) => it.maybe_chunk_data(),
402            Self::TokenUnfreeze(it) => it.maybe_chunk_data(),
403            Self::TokenUnpause(it) => it.maybe_chunk_data(),
404            Self::TokenUpdate(it) => it.maybe_chunk_data(),
405            Self::TokenWipe(it) => it.maybe_chunk_data(),
406            Self::SystemDelete(it) => it.maybe_chunk_data(),
407            Self::SystemUndelete(it) => it.maybe_chunk_data(),
408            Self::Freeze(it) => it.maybe_chunk_data(),
409            Self::ScheduleCreate(it) => it.maybe_chunk_data(),
410            Self::ScheduleSign(it) => it.maybe_chunk_data(),
411            Self::ScheduleDelete(it) => it.maybe_chunk_data(),
412            Self::Ethereum(it) => it.maybe_chunk_data(),
413            Self::TokenUpdateNfts(it) => it.maybe_chunk_data(),
414            Self::NodeCreate(it) => it.maybe_chunk_data(),
415            Self::NodeUpdate(it) => it.maybe_chunk_data(),
416            Self::NodeDelete(it) => it.maybe_chunk_data(),
417            Self::TokenReject(it) => it.maybe_chunk_data(),
418            Self::TokenAirdrop(it) => it.maybe_chunk_data(),
419            Self::TokenClaimAirdrop(it) => it.maybe_chunk_data(),
420            Self::TokenCancelAirdrop(it) => it.maybe_chunk_data(),
421            Self::Batch(it) => it.maybe_chunk_data(),
422            Self::HookStore(it) => it.maybe_chunk_data(),
423        }
424    }
425
426    fn wait_for_receipt(&self) -> bool {
427        match self {
428            Self::AccountCreate(it) => it.wait_for_receipt(),
429            Self::AccountUpdate(it) => it.wait_for_receipt(),
430            Self::AccountDelete(it) => it.wait_for_receipt(),
431            Self::AccountAllowanceApprove(it) => it.wait_for_receipt(),
432            Self::AccountAllowanceDelete(it) => it.wait_for_receipt(),
433            Self::ContractCreate(it) => it.wait_for_receipt(),
434            Self::ContractUpdate(it) => it.wait_for_receipt(),
435            Self::ContractDelete(it) => it.wait_for_receipt(),
436            Self::ContractExecute(it) => it.wait_for_receipt(),
437            Self::Transfer(it) => it.wait_for_receipt(),
438            Self::TopicCreate(it) => it.wait_for_receipt(),
439            Self::TopicUpdate(it) => it.wait_for_receipt(),
440            Self::TopicDelete(it) => it.wait_for_receipt(),
441            Self::TopicMessageSubmit(it) => it.wait_for_receipt(),
442            Self::FileAppend(it) => it.wait_for_receipt(),
443            Self::FileCreate(it) => it.wait_for_receipt(),
444            Self::FileUpdate(it) => it.wait_for_receipt(),
445            Self::FileDelete(it) => it.wait_for_receipt(),
446            Self::Prng(it) => it.wait_for_receipt(),
447            Self::TokenAssociate(it) => it.wait_for_receipt(),
448            Self::TokenBurn(it) => it.wait_for_receipt(),
449            Self::TokenCreate(it) => it.wait_for_receipt(),
450            Self::TokenDelete(it) => it.wait_for_receipt(),
451            Self::TokenDissociate(it) => it.wait_for_receipt(),
452            Self::TokenFeeScheduleUpdate(it) => it.wait_for_receipt(),
453            Self::TokenFreeze(it) => it.wait_for_receipt(),
454            Self::TokenGrantKyc(it) => it.wait_for_receipt(),
455            Self::TokenMint(it) => it.wait_for_receipt(),
456            Self::TokenPause(it) => it.wait_for_receipt(),
457            Self::TokenRevokeKyc(it) => it.wait_for_receipt(),
458            Self::TokenUnfreeze(it) => it.wait_for_receipt(),
459            Self::TokenUnpause(it) => it.wait_for_receipt(),
460            Self::TokenUpdate(it) => it.wait_for_receipt(),
461            Self::TokenWipe(it) => it.wait_for_receipt(),
462            Self::SystemDelete(it) => it.wait_for_receipt(),
463            Self::SystemUndelete(it) => it.wait_for_receipt(),
464            Self::Freeze(it) => it.wait_for_receipt(),
465            Self::ScheduleCreate(it) => it.wait_for_receipt(),
466            Self::ScheduleSign(it) => it.wait_for_receipt(),
467            Self::ScheduleDelete(it) => it.wait_for_receipt(),
468            Self::Ethereum(it) => it.wait_for_receipt(),
469            Self::TokenUpdateNfts(it) => it.wait_for_receipt(),
470            Self::NodeCreate(it) => it.wait_for_receipt(),
471            Self::NodeUpdate(it) => it.wait_for_receipt(),
472            Self::NodeDelete(it) => it.wait_for_receipt(),
473            Self::TokenReject(it) => it.wait_for_receipt(),
474            Self::TokenAirdrop(it) => it.wait_for_receipt(),
475            Self::TokenClaimAirdrop(it) => it.wait_for_receipt(),
476            Self::TokenCancelAirdrop(it) => it.wait_for_receipt(),
477            Self::Batch(it) => it.wait_for_receipt(),
478            Self::HookStore(it) => it.wait_for_receipt(),
479        }
480    }
481}
482
483impl TransactionExecute for AnyTransactionData {
484    fn execute(
485        &self,
486        channel: Channel,
487        request: services::Transaction,
488    ) -> BoxGrpcFuture<'_, services::TransactionResponse> {
489        match self {
490            Self::Transfer(transaction) => transaction.execute(channel, request),
491            Self::AccountCreate(transaction) => transaction.execute(channel, request),
492            Self::AccountUpdate(transaction) => transaction.execute(channel, request),
493            Self::AccountDelete(transaction) => transaction.execute(channel, request),
494            Self::AccountAllowanceApprove(transaction) => transaction.execute(channel, request),
495            Self::AccountAllowanceDelete(transaction) => transaction.execute(channel, request),
496            Self::ContractCreate(transaction) => transaction.execute(channel, request),
497            Self::ContractUpdate(transaction) => transaction.execute(channel, request),
498            Self::ContractDelete(transaction) => transaction.execute(channel, request),
499            Self::ContractExecute(transaction) => transaction.execute(channel, request),
500            Self::FileAppend(transaction) => transaction.execute(channel, request),
501            Self::FileCreate(transaction) => transaction.execute(channel, request),
502            Self::FileUpdate(transaction) => transaction.execute(channel, request),
503            Self::FileDelete(transaction) => transaction.execute(channel, request),
504            Self::Prng(transaction) => transaction.execute(channel, request),
505            Self::TokenAssociate(transaction) => transaction.execute(channel, request),
506            Self::TokenBurn(transaction) => transaction.execute(channel, request),
507            Self::TokenCreate(transaction) => transaction.execute(channel, request),
508            Self::TokenDelete(transaction) => transaction.execute(channel, request),
509            Self::TokenDissociate(transaction) => transaction.execute(channel, request),
510            Self::TokenFeeScheduleUpdate(transaction) => transaction.execute(channel, request),
511            Self::TokenFreeze(transaction) => transaction.execute(channel, request),
512            Self::TokenGrantKyc(transaction) => transaction.execute(channel, request),
513            Self::TokenMint(transaction) => transaction.execute(channel, request),
514            Self::TokenPause(transaction) => transaction.execute(channel, request),
515            Self::TokenRevokeKyc(transaction) => transaction.execute(channel, request),
516            Self::TokenUnfreeze(transaction) => transaction.execute(channel, request),
517            Self::TokenUnpause(transaction) => transaction.execute(channel, request),
518            Self::TokenUpdate(transaction) => transaction.execute(channel, request),
519            Self::TokenWipe(transaction) => transaction.execute(channel, request),
520            Self::TopicCreate(transaction) => transaction.execute(channel, request),
521            Self::TopicUpdate(transaction) => transaction.execute(channel, request),
522            Self::TopicDelete(transaction) => transaction.execute(channel, request),
523            Self::TopicMessageSubmit(transaction) => transaction.execute(channel, request),
524            Self::SystemDelete(transaction) => transaction.execute(channel, request),
525            Self::SystemUndelete(transaction) => transaction.execute(channel, request),
526            Self::Freeze(transaction) => transaction.execute(channel, request),
527            Self::ScheduleCreate(transaction) => transaction.execute(channel, request),
528            Self::ScheduleSign(transaction) => transaction.execute(channel, request),
529            Self::ScheduleDelete(transaction) => transaction.execute(channel, request),
530            Self::Ethereum(transaction) => transaction.execute(channel, request),
531            Self::TokenUpdateNfts(transaction) => transaction.execute(channel, request),
532            Self::NodeCreate(transaction) => transaction.execute(channel, request),
533            Self::NodeUpdate(transaction) => transaction.execute(channel, request),
534            Self::NodeDelete(transaction) => transaction.execute(channel, request),
535            Self::TokenReject(transaction) => transaction.execute(channel, request),
536            Self::TokenAirdrop(transaction) => transaction.execute(channel, request),
537            Self::TokenClaimAirdrop(transaction) => transaction.execute(channel, request),
538            Self::TokenCancelAirdrop(transaction) => transaction.execute(channel, request),
539            Self::Batch(transaction) => transaction.execute(channel, request),
540            Self::HookStore(transaction) => transaction.execute(channel, request),
541        }
542    }
543}
544
545impl TransactionExecuteChunked for AnyTransactionData {}
546
547impl ValidateChecksums for AnyTransactionData {
548    fn validate_checksums(&self, ledger_id: &RefLedgerId) -> Result<(), Error> {
549        match self {
550            Self::AccountCreate(transaction) => transaction.validate_checksums(ledger_id),
551            Self::AccountUpdate(transaction) => transaction.validate_checksums(ledger_id),
552            Self::AccountDelete(transaction) => transaction.validate_checksums(ledger_id),
553            Self::AccountAllowanceApprove(transaction) => transaction.validate_checksums(ledger_id),
554            Self::AccountAllowanceDelete(transaction) => transaction.validate_checksums(ledger_id),
555            Self::ContractCreate(transaction) => transaction.validate_checksums(ledger_id),
556            Self::ContractUpdate(transaction) => transaction.validate_checksums(ledger_id),
557            Self::ContractDelete(transaction) => transaction.validate_checksums(ledger_id),
558            Self::ContractExecute(transaction) => transaction.validate_checksums(ledger_id),
559            Self::Transfer(transaction) => transaction.validate_checksums(ledger_id),
560            Self::TopicCreate(transaction) => transaction.validate_checksums(ledger_id),
561            Self::TopicUpdate(transaction) => transaction.validate_checksums(ledger_id),
562            Self::TopicDelete(transaction) => transaction.validate_checksums(ledger_id),
563            Self::TopicMessageSubmit(transaction) => transaction.validate_checksums(ledger_id),
564            Self::FileAppend(transaction) => transaction.validate_checksums(ledger_id),
565            Self::FileCreate(transaction) => transaction.validate_checksums(ledger_id),
566            Self::FileUpdate(transaction) => transaction.validate_checksums(ledger_id),
567            Self::FileDelete(transaction) => transaction.validate_checksums(ledger_id),
568            Self::Prng(transaction) => transaction.validate_checksums(ledger_id),
569            Self::ScheduleCreate(transaction) => transaction.validate_checksums(ledger_id),
570            Self::ScheduleSign(transaction) => transaction.validate_checksums(ledger_id),
571            Self::ScheduleDelete(transaction) => transaction.validate_checksums(ledger_id),
572            Self::TokenAssociate(transaction) => transaction.validate_checksums(ledger_id),
573            Self::TokenBurn(transaction) => transaction.validate_checksums(ledger_id),
574            Self::TokenCreate(transaction) => transaction.validate_checksums(ledger_id),
575            Self::TokenDelete(transaction) => transaction.validate_checksums(ledger_id),
576            Self::TokenDissociate(transaction) => transaction.validate_checksums(ledger_id),
577            Self::TokenFeeScheduleUpdate(transaction) => transaction.validate_checksums(ledger_id),
578            Self::TokenFreeze(transaction) => transaction.validate_checksums(ledger_id),
579            Self::TokenGrantKyc(transaction) => transaction.validate_checksums(ledger_id),
580            Self::TokenMint(transaction) => transaction.validate_checksums(ledger_id),
581            Self::TokenPause(transaction) => transaction.validate_checksums(ledger_id),
582            Self::TokenRevokeKyc(transaction) => transaction.validate_checksums(ledger_id),
583            Self::TokenUnfreeze(transaction) => transaction.validate_checksums(ledger_id),
584            Self::TokenUnpause(transaction) => transaction.validate_checksums(ledger_id),
585            Self::TokenUpdate(transaction) => transaction.validate_checksums(ledger_id),
586            Self::TokenWipe(transaction) => transaction.validate_checksums(ledger_id),
587            Self::SystemDelete(transaction) => transaction.validate_checksums(ledger_id),
588            Self::SystemUndelete(transaction) => transaction.validate_checksums(ledger_id),
589            Self::Freeze(transaction) => transaction.validate_checksums(ledger_id),
590            Self::Ethereum(transaction) => transaction.validate_checksums(ledger_id),
591            Self::TokenUpdateNfts(transaction) => transaction.validate_checksums(ledger_id),
592            Self::NodeCreate(transaction) => transaction.validate_checksums(ledger_id),
593            Self::NodeUpdate(transaction) => transaction.validate_checksums(ledger_id),
594            Self::NodeDelete(transaction) => transaction.validate_checksums(ledger_id),
595            Self::TokenReject(transaction) => transaction.validate_checksums(ledger_id),
596            Self::TokenAirdrop(transaction) => transaction.validate_checksums(ledger_id),
597            Self::TokenClaimAirdrop(transaction) => transaction.validate_checksums(ledger_id),
598            Self::TokenCancelAirdrop(transaction) => transaction.validate_checksums(ledger_id),
599            Self::Batch(transaction) => transaction.validate_checksums(ledger_id),
600            Self::HookStore(transaction) => transaction.validate_checksums(ledger_id),
601        }
602    }
603}
604
605impl FromProtobuf<services::transaction_body::Data> for AnyTransactionData {
606    fn from_protobuf(pb: services::transaction_body::Data) -> crate::Result<Self>
607    where
608        Self: Sized,
609    {
610        use services::transaction_body::Data;
611        let data = match pb {
612            Data::ContractCall(pb) => data::ContractExecute::from_protobuf(pb)?.into(),
613            Data::ContractCreateInstance(pb) => data::ContractCreate::from_protobuf(pb)?.into(),
614            Data::ContractUpdateInstance(pb) => data::ContractUpdate::from_protobuf(pb)?.into(),
615            Data::ContractDeleteInstance(pb) => data::ContractDelete::from_protobuf(pb)?.into(),
616            Data::EthereumTransaction(pb) => data::Ethereum::from_protobuf(pb)?.into(),
617            Data::CryptoApproveAllowance(pb) => {
618                data::AccountAllowanceApprove::from_protobuf(pb)?.into()
619            }
620            Data::CryptoDeleteAllowance(pb) => {
621                data::AccountAllowanceDelete::from_protobuf(pb)?.into()
622            }
623            Data::CryptoCreateAccount(pb) => data::AccountCreate::from_protobuf(pb)?.into(),
624            Data::CryptoDelete(pb) => data::AccountDelete::from_protobuf(pb)?.into(),
625            Data::CryptoTransfer(pb) => data::Transfer::from_protobuf(pb)?.into(),
626            Data::CryptoUpdateAccount(pb) => data::AccountUpdate::from_protobuf(pb)?.into(),
627            Data::FileAppend(pb) => data::FileAppend::from_protobuf(pb)?.into(),
628            Data::FileCreate(pb) => data::FileCreate::from_protobuf(pb)?.into(),
629            Data::FileDelete(pb) => data::FileDelete::from_protobuf(pb)?.into(),
630            Data::FileUpdate(pb) => data::FileUpdate::from_protobuf(pb)?.into(),
631            Data::UtilPrng(pb) => data::Prng::from_protobuf(pb)?.into(),
632            Data::SystemDelete(pb) => data::SystemDelete::from_protobuf(pb)?.into(),
633            Data::SystemUndelete(pb) => data::SystemUndelete::from_protobuf(pb)?.into(),
634            Data::Freeze(pb) => data::Freeze::from_protobuf(pb)?.into(),
635            Data::ConsensusCreateTopic(pb) => data::TopicCreate::from_protobuf(pb)?.into(),
636            Data::ConsensusUpdateTopic(pb) => data::TopicUpdate::from_protobuf(pb)?.into(),
637            Data::ConsensusDeleteTopic(pb) => data::TopicDelete::from_protobuf(pb)?.into(),
638            Data::ConsensusSubmitMessage(pb) => data::TopicMessageSubmit::from_protobuf(pb)?.into(),
639            Data::TokenCreation(pb) => data::TokenCreate::from_protobuf(pb)?.into(),
640            Data::TokenFreeze(pb) => data::TokenFreeze::from_protobuf(pb)?.into(),
641            Data::TokenUnfreeze(pb) => data::TokenUnfreeze::from_protobuf(pb)?.into(),
642            Data::TokenGrantKyc(pb) => data::TokenGrantKyc::from_protobuf(pb)?.into(),
643            Data::TokenRevokeKyc(pb) => data::TokenRevokeKyc::from_protobuf(pb)?.into(),
644            Data::TokenDeletion(pb) => data::TokenDelete::from_protobuf(pb)?.into(),
645            Data::TokenUpdate(pb) => data::TokenUpdate::from_protobuf(pb)?.into(),
646            Data::TokenMint(pb) => data::TokenMint::from_protobuf(pb)?.into(),
647            Data::TokenBurn(pb) => data::TokenBurn::from_protobuf(pb)?.into(),
648            Data::TokenWipe(pb) => data::TokenWipe::from_protobuf(pb)?.into(),
649            Data::TokenAssociate(pb) => data::TokenAssociate::from_protobuf(pb)?.into(),
650            Data::TokenDissociate(pb) => data::TokenDissociate::from_protobuf(pb)?.into(),
651            Data::TokenFeeScheduleUpdate(pb) => {
652                data::TokenFeeScheduleUpdate::from_protobuf(pb)?.into()
653            }
654            Data::TokenPause(pb) => data::TokenPause::from_protobuf(pb)?.into(),
655            Data::TokenUnpause(pb) => data::TokenUnpause::from_protobuf(pb)?.into(),
656            Data::TokenReject(pb) => data::TokenReject::from_protobuf(pb)?.into(),
657            Data::ScheduleCreate(pb) => data::ScheduleCreate::from_protobuf(pb)?.into(),
658            Data::ScheduleDelete(pb) => data::ScheduleDelete::from_protobuf(pb)?.into(),
659            Data::ScheduleSign(pb) => data::ScheduleSign::from_protobuf(pb)?.into(),
660            Data::TokenUpdateNfts(pb) => data::TokenUpdateNfts::from_protobuf(pb)?.into(),
661            Data::NodeCreate(pb) => data::NodeCreate::from_protobuf(pb)?.into(),
662            Data::NodeUpdate(pb) => data::NodeUpdate::from_protobuf(pb)?.into(),
663            Data::NodeDelete(pb) => data::NodeDelete::from_protobuf(pb)?.into(),
664            Data::TokenAirdrop(pb) => data::TokenAirdrop::from_protobuf(pb)?.into(),
665            Data::TokenClaimAirdrop(pb) => data::TokenClaimAirdrop::from_protobuf(pb)?.into(),
666            Data::TokenCancelAirdrop(pb) => data::TokenCancelAirdrop::from_protobuf(pb)?.into(),
667            Data::CryptoAddLiveHash(_) => {
668                return Err(Error::from_protobuf(
669                    "unsupported transaction `AddLiveHashTransaction`",
670                ))
671            }
672            Data::CryptoDeleteLiveHash(_) => {
673                return Err(Error::from_protobuf(
674                    "unsupported transaction `DeleteLiveHashTransaction`",
675                ))
676            }
677            Data::UncheckedSubmit(_) => {
678                return Err(Error::from_protobuf(
679                    "unsupported transaction `UncheckedSubmitTransaction`",
680                ))
681            }
682            Data::NodeStakeUpdate(_) => {
683                return Err(Error::from_protobuf(
684                    "unsupported transaction `NodeStakeUpdateTransaction`",
685                ))
686            }
687            Data::HookStore(pb) => data::HookStore::from_protobuf(pb)?.into(),
688            Data::HookDispatch(_) => {
689                return Err(Error::from_protobuf(
690                    "unsupported transaction `HookDispatchTransaction`",
691                ))
692            }
693            Data::AtomicBatch(_) => {
694                return Err(Error::from_protobuf(
695                    "unsupported transaction `AtomicBatchTransaction`",
696                ))
697            }
698            Data::LedgerIdPublication(_) => {
699                return Err(Error::from_protobuf(
700                    "unsupported transaction `LedgerIdPublicationTransaction`",
701                ))
702            }
703            Data::RegisteredNodeCreate(_) => {
704                return Err(Error::from_protobuf(
705                    "unsupported transaction `RegisteredNodeCreateTransaction`",
706                ))
707            }
708            Data::RegisteredNodeUpdate(_) => {
709                return Err(Error::from_protobuf(
710                    "unsupported transaction `RegisteredNodeUpdateTransaction`",
711                ))
712            }
713            Data::RegisteredNodeDelete(_) => {
714                return Err(Error::from_protobuf(
715                    "unsupported transaction `RegisteredNodeDeleteTransaction`",
716                ))
717            }
718        };
719
720        Ok(data)
721    }
722}
723
724impl AnyTransactionData {
725    // can't do anything about the # of lines, since this function just delegates to `data::_::from_protobuf`.
726    #[allow(clippy::too_many_lines)]
727    fn from_protobuf(data_chunks: ServicesTransactionDataList) -> crate::Result<Self> {
728        fn try_into_only_element<T>(v: Vec<T>) -> crate::Result<T> {
729            match <[T; 1]>::try_from(v) {
730                Ok([element]) => Ok(element),
731                _ => Err(Error::from_protobuf("chunks in non chunkable transaction")),
732            }
733        }
734
735        let data = match data_chunks {
736            ServicesTransactionDataList::AccountCreate(v) => {
737                data::AccountCreate::from_protobuf(try_into_only_element(v)?)?.into()
738            }
739            ServicesTransactionDataList::AccountUpdate(v) => {
740                data::AccountUpdate::from_protobuf(try_into_only_element(v)?)?.into()
741            }
742            ServicesTransactionDataList::AccountDelete(v) => {
743                data::AccountDelete::from_protobuf(try_into_only_element(v)?)?.into()
744            }
745            ServicesTransactionDataList::AccountAllowanceApprove(v) => {
746                data::AccountAllowanceApprove::from_protobuf(try_into_only_element(v)?)?.into()
747            }
748            ServicesTransactionDataList::AccountAllowanceDelete(v) => {
749                data::AccountAllowanceDelete::from_protobuf(try_into_only_element(v)?)?.into()
750            }
751            ServicesTransactionDataList::ContractCreate(v) => {
752                data::ContractCreate::from_protobuf(try_into_only_element(v)?)?.into()
753            }
754            ServicesTransactionDataList::ContractUpdate(v) => {
755                data::ContractUpdate::from_protobuf(try_into_only_element(v)?)?.into()
756            }
757            ServicesTransactionDataList::ContractDelete(v) => {
758                data::ContractDelete::from_protobuf(try_into_only_element(v)?)?.into()
759            }
760            ServicesTransactionDataList::ContractExecute(v) => {
761                data::ContractExecute::from_protobuf(try_into_only_element(v)?)?.into()
762            }
763            ServicesTransactionDataList::Transfer(v) => {
764                data::Transfer::from_protobuf(try_into_only_element(v)?)?.into()
765            }
766            ServicesTransactionDataList::TopicCreate(v) => {
767                data::TopicCreate::from_protobuf(try_into_only_element(v)?)?.into()
768            }
769            ServicesTransactionDataList::TopicUpdate(v) => {
770                data::TopicUpdate::from_protobuf(try_into_only_element(v)?)?.into()
771            }
772            ServicesTransactionDataList::TopicDelete(v) => {
773                data::TopicDelete::from_protobuf(try_into_only_element(v)?)?.into()
774            }
775            ServicesTransactionDataList::TopicMessageSubmit(v) => {
776                data::TopicMessageSubmit::from_protobuf(v)?.into()
777            }
778            ServicesTransactionDataList::FileAppend(v) => {
779                data::FileAppend::from_protobuf(v)?.into()
780            }
781            ServicesTransactionDataList::FileCreate(v) => {
782                data::FileCreate::from_protobuf(try_into_only_element(v)?)?.into()
783            }
784            ServicesTransactionDataList::FileUpdate(v) => {
785                data::FileUpdate::from_protobuf(try_into_only_element(v)?)?.into()
786            }
787            ServicesTransactionDataList::FileDelete(v) => {
788                data::FileDelete::from_protobuf(try_into_only_element(v)?)?.into()
789            }
790            ServicesTransactionDataList::TokenAssociate(v) => {
791                data::TokenAssociate::from_protobuf(try_into_only_element(v)?)?.into()
792            }
793            ServicesTransactionDataList::TokenBurn(v) => {
794                data::TokenBurn::from_protobuf(try_into_only_element(v)?)?.into()
795            }
796            ServicesTransactionDataList::TokenCreate(v) => {
797                data::TokenCreate::from_protobuf(try_into_only_element(v)?)?.into()
798            }
799            ServicesTransactionDataList::TokenDelete(v) => {
800                data::TokenDelete::from_protobuf(try_into_only_element(v)?)?.into()
801            }
802            ServicesTransactionDataList::TokenDissociate(v) => {
803                data::TokenDissociate::from_protobuf(try_into_only_element(v)?)?.into()
804            }
805            ServicesTransactionDataList::TokenFeeScheduleUpdate(v) => {
806                data::TokenFeeScheduleUpdate::from_protobuf(try_into_only_element(v)?)?.into()
807            }
808            ServicesTransactionDataList::TokenFreeze(v) => {
809                data::TokenFreeze::from_protobuf(try_into_only_element(v)?)?.into()
810            }
811            ServicesTransactionDataList::TokenGrantKyc(v) => {
812                data::TokenGrantKyc::from_protobuf(try_into_only_element(v)?)?.into()
813            }
814            ServicesTransactionDataList::TokenMint(v) => {
815                data::TokenMint::from_protobuf(try_into_only_element(v)?)?.into()
816            }
817            ServicesTransactionDataList::TokenPause(v) => {
818                data::TokenPause::from_protobuf(try_into_only_element(v)?)?.into()
819            }
820            ServicesTransactionDataList::TokenRevokeKyc(v) => {
821                data::TokenRevokeKyc::from_protobuf(try_into_only_element(v)?)?.into()
822            }
823            ServicesTransactionDataList::TokenUnfreeze(v) => {
824                data::TokenUnfreeze::from_protobuf(try_into_only_element(v)?)?.into()
825            }
826            ServicesTransactionDataList::TokenUnpause(v) => {
827                data::TokenUnpause::from_protobuf(try_into_only_element(v)?)?.into()
828            }
829            ServicesTransactionDataList::TokenUpdate(v) => {
830                data::TokenUpdate::from_protobuf(try_into_only_element(v)?)?.into()
831            }
832            ServicesTransactionDataList::TokenWipe(v) => {
833                data::TokenWipe::from_protobuf(try_into_only_element(v)?)?.into()
834            }
835            ServicesTransactionDataList::SystemDelete(v) => {
836                data::SystemDelete::from_protobuf(try_into_only_element(v)?)?.into()
837            }
838            ServicesTransactionDataList::SystemUndelete(v) => {
839                data::SystemUndelete::from_protobuf(try_into_only_element(v)?)?.into()
840            }
841            ServicesTransactionDataList::Freeze(v) => {
842                data::Freeze::from_protobuf(try_into_only_element(v)?)?.into()
843            }
844            ServicesTransactionDataList::ScheduleCreate(v) => {
845                data::ScheduleCreate::from_protobuf(try_into_only_element(v)?)?.into()
846            }
847            ServicesTransactionDataList::ScheduleSign(v) => {
848                data::ScheduleSign::from_protobuf(try_into_only_element(v)?)?.into()
849            }
850            ServicesTransactionDataList::ScheduleDelete(v) => {
851                data::ScheduleDelete::from_protobuf(try_into_only_element(v)?)?.into()
852            }
853            ServicesTransactionDataList::Ethereum(v) => {
854                data::Ethereum::from_protobuf(try_into_only_element(v)?)?.into()
855            }
856            ServicesTransactionDataList::UtilPrng(v) => {
857                data::Prng::from_protobuf(try_into_only_element(v)?)?.into()
858            }
859            ServicesTransactionDataList::TokenUpdateNfts(v) => {
860                data::TokenUpdateNfts::from_protobuf(try_into_only_element(v)?)?.into()
861            }
862            ServicesTransactionDataList::TokenReject(v) => {
863                data::TokenReject::from_protobuf(try_into_only_element(v)?)?.into()
864            }
865            ServicesTransactionDataList::NodeCreate(v) => {
866                data::NodeCreate::from_protobuf(try_into_only_element(v)?)?.into()
867            }
868            ServicesTransactionDataList::NodeUpdate(v) => {
869                data::NodeUpdate::from_protobuf(try_into_only_element(v)?)?.into()
870            }
871            ServicesTransactionDataList::NodeDelete(v) => {
872                data::NodeDelete::from_protobuf(try_into_only_element(v)?)?.into()
873            }
874            ServicesTransactionDataList::TokenAirdrop(v) => {
875                data::TokenAirdrop::from_protobuf(try_into_only_element(v)?)?.into()
876            }
877            ServicesTransactionDataList::TokenClaimAirdrop(v) => {
878                data::TokenClaimAirdrop::from_protobuf(try_into_only_element(v)?)?.into()
879            }
880            ServicesTransactionDataList::TokenCancelAirdrop(v) => {
881                data::TokenCancelAirdrop::from_protobuf(try_into_only_element(v)?)?.into()
882            }
883            ServicesTransactionDataList::AtomicBatch(v) => {
884                data::Batch::from_protobuf(try_into_only_element(v)?)?.into()
885            }
886        };
887
888        Ok(data)
889    }
890}
891
892impl AnyTransaction {
893    pub(super) fn from_protobuf(
894        first_body: services::TransactionBody,
895        data_chunks: Vec<services::transaction_body::Data>,
896    ) -> crate::Result<Self> {
897        let transaction_id: Option<TransactionId> = match first_body.transaction_id {
898            Some(id) => match TransactionId::from_protobuf(id) {
899                Ok(id) => Some(id),
900                Err(_) => None, // Or handle the error differently
901            },
902            None => None,
903        };
904
905        let node_account_ids = match first_body.node_account_id {
906            Some(id) => match AccountId::from_protobuf(id) {
907                Ok(id) => Some(vec![id]),
908                Err(_) => None, // Handle error gracefully
909            },
910            None => None,
911        };
912
913        // Default to 0 tinybars if transaction_fee is missing
914        let transaction_fee = Hbar::from_tinybars(first_body.transaction_fee as i64);
915
916        // Check if data_chunks is empty and handle gracefully
917        if data_chunks.is_empty() {
918            return Err(Error::from_protobuf("Transaction data is missing"));
919        }
920
921        let transaction_data = match AnyTransactionData::from_protobuf(
922            ServicesTransactionDataList::from_protobuf(data_chunks)?,
923        ) {
924            Ok(data) => data,
925            Err(e) => return Err(e),
926        };
927
928        Ok(Transaction {
929            body: TransactionBody {
930                data: transaction_data,
931                transaction_memo: first_body.memo,
932                node_account_ids,
933                transaction_valid_duration: first_body.transaction_valid_duration.map(Into::into),
934                max_transaction_fee: Some(transaction_fee),
935                transaction_id,
936                operator: None,
937                is_frozen: false,
938                regenerate_transaction_id: Some(false),
939                custom_fee_limits: first_body
940                    .max_custom_fees
941                    .into_iter()
942                    .map(CustomFeeLimit::from_protobuf)
943                    .collect::<Result<Vec<_>, _>>()?,
944                batch_key: first_body
945                    .batch_key
946                    .map(|key| crate::protobuf::FromProtobuf::from_protobuf(key).unwrap()),
947                high_volume: first_body.high_volume,
948            },
949            signers: Vec::new(),
950            sources: None,
951            grpc_deadline: None,
952            request_timeout: None,
953        })
954    }
955}
956
957// sigh.
958#[derive(Debug)]
959enum ServicesTransactionDataList {
960    AccountCreate(Vec<services::CryptoCreateTransactionBody>),
961    AccountUpdate(Vec<services::CryptoUpdateTransactionBody>),
962    AccountDelete(Vec<services::CryptoDeleteTransactionBody>),
963    AccountAllowanceApprove(Vec<services::CryptoApproveAllowanceTransactionBody>),
964    AccountAllowanceDelete(Vec<services::CryptoDeleteAllowanceTransactionBody>),
965    ContractCreate(Vec<services::ContractCreateTransactionBody>),
966    ContractUpdate(Vec<services::ContractUpdateTransactionBody>),
967    ContractDelete(Vec<services::ContractDeleteTransactionBody>),
968    ContractExecute(Vec<services::ContractCallTransactionBody>),
969    Transfer(Vec<services::CryptoTransferTransactionBody>),
970    TopicCreate(Vec<services::ConsensusCreateTopicTransactionBody>),
971    TopicUpdate(Vec<services::ConsensusUpdateTopicTransactionBody>),
972    TopicDelete(Vec<services::ConsensusDeleteTopicTransactionBody>),
973    TopicMessageSubmit(Vec<services::ConsensusSubmitMessageTransactionBody>),
974    FileAppend(Vec<services::FileAppendTransactionBody>),
975    FileCreate(Vec<services::FileCreateTransactionBody>),
976    FileUpdate(Vec<services::FileUpdateTransactionBody>),
977    FileDelete(Vec<services::FileDeleteTransactionBody>),
978    TokenAssociate(Vec<services::TokenAssociateTransactionBody>),
979    TokenBurn(Vec<services::TokenBurnTransactionBody>),
980    TokenCreate(Vec<services::TokenCreateTransactionBody>),
981    TokenDelete(Vec<services::TokenDeleteTransactionBody>),
982    TokenDissociate(Vec<services::TokenDissociateTransactionBody>),
983    TokenFeeScheduleUpdate(Vec<services::TokenFeeScheduleUpdateTransactionBody>),
984    TokenFreeze(Vec<services::TokenFreezeAccountTransactionBody>),
985    TokenGrantKyc(Vec<services::TokenGrantKycTransactionBody>),
986    TokenMint(Vec<services::TokenMintTransactionBody>),
987    TokenPause(Vec<services::TokenPauseTransactionBody>),
988    TokenRevokeKyc(Vec<services::TokenRevokeKycTransactionBody>),
989    TokenUnfreeze(Vec<services::TokenUnfreezeAccountTransactionBody>),
990    TokenUnpause(Vec<services::TokenUnpauseTransactionBody>),
991    TokenUpdate(Vec<services::TokenUpdateTransactionBody>),
992    TokenWipe(Vec<services::TokenWipeAccountTransactionBody>),
993    TokenUpdateNfts(Vec<services::TokenUpdateNftsTransactionBody>),
994    TokenReject(Vec<services::TokenRejectTransactionBody>),
995    SystemDelete(Vec<services::SystemDeleteTransactionBody>),
996    SystemUndelete(Vec<services::SystemUndeleteTransactionBody>),
997    Freeze(Vec<services::FreezeTransactionBody>),
998    ScheduleCreate(Vec<services::ScheduleCreateTransactionBody>),
999    ScheduleSign(Vec<services::ScheduleSignTransactionBody>),
1000    ScheduleDelete(Vec<services::ScheduleDeleteTransactionBody>),
1001    Ethereum(Vec<services::EthereumTransactionBody>),
1002    UtilPrng(Vec<services::UtilPrngTransactionBody>),
1003    NodeCreate(Vec<services::NodeCreateTransactionBody>),
1004    NodeUpdate(Vec<services::NodeUpdateTransactionBody>),
1005    NodeDelete(Vec<services::NodeDeleteTransactionBody>),
1006    TokenAirdrop(Vec<services::TokenAirdropTransactionBody>),
1007    TokenClaimAirdrop(Vec<services::TokenClaimAirdropTransactionBody>),
1008    TokenCancelAirdrop(Vec<services::TokenCancelAirdropTransactionBody>),
1009    AtomicBatch(Vec<services::AtomicBatchTransactionBody>),
1010}
1011
1012impl FromProtobuf<Vec<services::transaction_body::Data>> for ServicesTransactionDataList {
1013    fn from_protobuf(pb: Vec<services::transaction_body::Data>) -> crate::Result<Self> {
1014        use services::transaction_body::Data;
1015
1016        fn make_vec<T>(first: T, cap: usize) -> Vec<T> {
1017            let mut v = Vec::with_capacity(cap);
1018            v.push(first);
1019            v
1020        }
1021
1022        let len = pb.len();
1023
1024        let mut iter = pb.into_iter();
1025
1026        let first = iter
1027            .next()
1028            .expect("empty transaction data list (should be handled earlier up the pipeline)");
1029
1030        // note: this impl is what I (srr) believe to be the "best" impl
1031        let mut value = match first {
1032            Data::ContractCall(it) => Self::ContractExecute(make_vec(it, len)),
1033            Data::ContractCreateInstance(it) => Self::ContractCreate(make_vec(it, len)),
1034            Data::ContractUpdateInstance(it) => Self::ContractUpdate(make_vec(it, len)),
1035            Data::ContractDeleteInstance(it) => Self::ContractDelete(make_vec(it, len)),
1036            Data::EthereumTransaction(it) => Self::Ethereum(make_vec(it, len)),
1037            Data::CryptoApproveAllowance(it) => Self::AccountAllowanceApprove(make_vec(it, len)),
1038            Data::CryptoDeleteAllowance(it) => Self::AccountAllowanceDelete(make_vec(it, len)),
1039            Data::CryptoCreateAccount(it) => Self::AccountCreate(make_vec(it, len)),
1040            Data::CryptoDelete(it) => Self::AccountDelete(make_vec(it, len)),
1041            Data::CryptoTransfer(it) => Self::Transfer(make_vec(it, len)),
1042            Data::CryptoUpdateAccount(it) => Self::AccountUpdate(make_vec(it, len)),
1043            Data::FileAppend(it) => Self::FileAppend(make_vec(it, len)),
1044            Data::FileCreate(it) => Self::FileCreate(make_vec(it, len)),
1045            Data::FileDelete(it) => Self::FileDelete(make_vec(it, len)),
1046            Data::FileUpdate(it) => Self::FileUpdate(make_vec(it, len)),
1047            Data::SystemDelete(it) => Self::SystemDelete(make_vec(it, len)),
1048            Data::SystemUndelete(it) => Self::SystemUndelete(make_vec(it, len)),
1049            Data::Freeze(it) => Self::Freeze(make_vec(it, len)),
1050            Data::ConsensusCreateTopic(it) => Self::TopicCreate(make_vec(it, len)),
1051            Data::ConsensusUpdateTopic(it) => Self::TopicUpdate(make_vec(it, len)),
1052            Data::ConsensusDeleteTopic(it) => Self::TopicDelete(make_vec(it, len)),
1053            Data::ConsensusSubmitMessage(it) => Self::TopicMessageSubmit(make_vec(it, len)),
1054            Data::TokenCreation(it) => Self::TokenCreate(make_vec(it, len)),
1055            Data::TokenFreeze(it) => Self::TokenFreeze(make_vec(it, len)),
1056            Data::TokenUnfreeze(it) => Self::TokenUnfreeze(make_vec(it, len)),
1057            Data::TokenGrantKyc(it) => Self::TokenGrantKyc(make_vec(it, len)),
1058            Data::TokenRevokeKyc(it) => Self::TokenRevokeKyc(make_vec(it, len)),
1059            Data::TokenDeletion(it) => Self::TokenDelete(make_vec(it, len)),
1060            Data::TokenUpdate(it) => Self::TokenUpdate(make_vec(it, len)),
1061            Data::TokenMint(it) => Self::TokenMint(make_vec(it, len)),
1062            Data::TokenBurn(it) => Self::TokenBurn(make_vec(it, len)),
1063            Data::TokenWipe(it) => Self::TokenWipe(make_vec(it, len)),
1064            Data::TokenAssociate(it) => Self::TokenAssociate(make_vec(it, len)),
1065            Data::TokenDissociate(it) => Self::TokenDissociate(make_vec(it, len)),
1066            Data::TokenFeeScheduleUpdate(it) => Self::TokenFeeScheduleUpdate(make_vec(it, len)),
1067            Data::TokenPause(it) => Self::TokenPause(make_vec(it, len)),
1068            Data::TokenUnpause(it) => Self::TokenUnpause(make_vec(it, len)),
1069            Data::TokenReject(it) => Self::TokenReject(make_vec(it, len)),
1070            Data::ScheduleCreate(it) => Self::ScheduleCreate(make_vec(it, len)),
1071            Data::ScheduleDelete(it) => Self::ScheduleDelete(make_vec(it, len)),
1072            Data::ScheduleSign(it) => Self::ScheduleSign(make_vec(it, len)),
1073            Data::UtilPrng(it) => Self::UtilPrng(make_vec(it, len)),
1074            Data::TokenUpdateNfts(it) => Self::TokenUpdateNfts(make_vec(it, len)),
1075            Data::NodeCreate(it) => Self::NodeCreate(make_vec(it, len)),
1076            Data::NodeUpdate(it) => Self::NodeUpdate(make_vec(it, len)),
1077            Data::NodeDelete(it) => Self::NodeDelete(make_vec(it, len)),
1078            Data::TokenAirdrop(it) => Self::TokenAirdrop(make_vec(it, len)),
1079            Data::TokenClaimAirdrop(it) => Self::TokenClaimAirdrop(make_vec(it, len)),
1080            Data::TokenCancelAirdrop(it) => Self::TokenCancelAirdrop(make_vec(it, len)),
1081            Data::CryptoAddLiveHash(_) => {
1082                return Err(Error::from_protobuf(
1083                    "unsupported transaction `AddLiveHashTransaction`",
1084                ))
1085            }
1086            Data::CryptoDeleteLiveHash(_) => {
1087                return Err(Error::from_protobuf(
1088                    "unsupported transaction `DeleteLiveHashTransaction`",
1089                ))
1090            }
1091
1092            Data::UncheckedSubmit(_) => {
1093                return Err(Error::from_protobuf(
1094                    "unsupported transaction `UncheckedSubmitTransaction`",
1095                ))
1096            }
1097            Data::NodeStakeUpdate(_) => {
1098                return Err(Error::from_protobuf(
1099                    "unsupported transaction `NodeStakeUpdateTransaction`",
1100                ))
1101            }
1102            Data::HookStore(_) => {
1103                return Err(Error::from_protobuf("HookStore transactions cannot be chunked"))
1104            }
1105            Data::HookDispatch(_) => {
1106                return Err(Error::from_protobuf("HookDispatch transactions are not supported"))
1107            }
1108            Data::AtomicBatch(_) => {
1109                return Err(Error::from_protobuf("AtomicBatch transactions are not supported"))
1110            }
1111            Data::LedgerIdPublication(_) => {
1112                return Err(Error::from_protobuf(
1113                    "LedgerIdPublication transactions are not supported",
1114                ))
1115            }
1116            Data::RegisteredNodeCreate(_) => {
1117                return Err(Error::from_protobuf(
1118                    "RegisteredNodeCreate transactions are not supported",
1119                ))
1120            }
1121            Data::RegisteredNodeUpdate(_) => {
1122                return Err(Error::from_protobuf(
1123                    "RegisteredNodeUpdate transactions are not supported",
1124                ))
1125            }
1126            Data::RegisteredNodeDelete(_) => {
1127                return Err(Error::from_protobuf(
1128                    "RegisteredNodeDelete transactions are not supported",
1129                ))
1130            }
1131        };
1132
1133        for transaction in iter {
1134            match (&mut value, transaction) {
1135                (Self::AccountCreate(v), Data::CryptoCreateAccount(element)) => v.push(element),
1136                (Self::AccountUpdate(v), Data::CryptoUpdateAccount(element)) => v.push(element),
1137                (Self::AccountDelete(v), Data::CryptoDelete(element)) => v.push(element),
1138                (Self::AccountAllowanceApprove(v), Data::CryptoApproveAllowance(element)) => {
1139                    v.push(element);
1140                }
1141                (Self::AccountAllowanceDelete(v), Data::CryptoDeleteAllowance(element)) => {
1142                    v.push(element);
1143                }
1144                (Self::ContractCreate(v), Data::ContractCreateInstance(element)) => v.push(element),
1145                (Self::ContractUpdate(v), Data::ContractUpdateInstance(element)) => v.push(element),
1146                (Self::ContractDelete(v), Data::ContractDeleteInstance(element)) => v.push(element),
1147                (Self::ContractExecute(v), Data::ContractCall(element)) => v.push(element),
1148                (Self::Transfer(v), Data::CryptoTransfer(element)) => v.push(element),
1149                (Self::TopicCreate(v), Data::ConsensusCreateTopic(element)) => v.push(element),
1150                (Self::TopicUpdate(v), Data::ConsensusUpdateTopic(element)) => v.push(element),
1151                (Self::TopicDelete(v), Data::ConsensusDeleteTopic(element)) => v.push(element),
1152                (Self::TopicMessageSubmit(v), Data::ConsensusSubmitMessage(element)) => {
1153                    v.push(element);
1154                }
1155                (Self::FileAppend(v), Data::FileAppend(element)) => v.push(element),
1156                (Self::FileCreate(v), Data::FileCreate(element)) => v.push(element),
1157                (Self::FileUpdate(v), Data::FileUpdate(element)) => v.push(element),
1158                (Self::FileDelete(v), Data::FileDelete(element)) => v.push(element),
1159                (Self::TokenAssociate(v), Data::TokenAssociate(element)) => v.push(element),
1160                (Self::TokenBurn(v), Data::TokenBurn(element)) => v.push(element),
1161                (Self::TokenCreate(v), Data::TokenCreation(element)) => v.push(element),
1162                (Self::TokenDelete(v), Data::TokenDeletion(element)) => v.push(element),
1163                (Self::TokenDissociate(v), Data::TokenDissociate(element)) => v.push(element),
1164                (Self::TokenFeeScheduleUpdate(v), Data::TokenFeeScheduleUpdate(element)) => {
1165                    v.push(element);
1166                }
1167                (Self::TokenFreeze(v), Data::TokenFreeze(element)) => v.push(element),
1168                (Self::TokenGrantKyc(v), Data::TokenGrantKyc(element)) => v.push(element),
1169                (Self::TokenMint(v), Data::TokenMint(element)) => v.push(element),
1170                (Self::TokenPause(v), Data::TokenPause(element)) => v.push(element),
1171                (Self::TokenRevokeKyc(v), Data::TokenRevokeKyc(element)) => v.push(element),
1172                (Self::TokenUnfreeze(v), Data::TokenUnfreeze(element)) => v.push(element),
1173                (Self::TokenUnpause(v), Data::TokenUnpause(element)) => v.push(element),
1174                (Self::TokenUpdate(v), Data::TokenUpdate(element)) => v.push(element),
1175                (Self::TokenWipe(v), Data::TokenWipe(element)) => v.push(element),
1176                (Self::SystemDelete(v), Data::SystemDelete(element)) => v.push(element),
1177                (Self::SystemUndelete(v), Data::SystemUndelete(element)) => v.push(element),
1178                (Self::Freeze(v), Data::Freeze(element)) => v.push(element),
1179                (Self::ScheduleCreate(v), Data::ScheduleCreate(element)) => v.push(element),
1180                (Self::ScheduleSign(v), Data::ScheduleSign(element)) => v.push(element),
1181                (Self::ScheduleDelete(v), Data::ScheduleDelete(element)) => v.push(element),
1182                (Self::Ethereum(v), Data::EthereumTransaction(element)) => v.push(element),
1183                (Self::UtilPrng(v), Data::UtilPrng(element)) => v.push(element),
1184                (Self::TokenAirdrop(v), Data::TokenAirdrop(element)) => v.push(element),
1185                (Self::TokenClaimAirdrop(v), Data::TokenClaimAirdrop(element)) => v.push(element),
1186                (Self::TokenCancelAirdrop(v), Data::TokenCancelAirdrop(element)) => v.push(element),
1187                (Self::AtomicBatch(v), Data::AtomicBatch(element)) => v.push(element),
1188                _ => return Err(Error::from_protobuf("mismatched transaction types")),
1189            }
1190        }
1191
1192        Ok(value)
1193    }
1194}
1195
1196impl AnyTransaction {
1197    /// Attempt to downcast from any transaction to the given transaction kind.
1198    ///
1199    /// # Errors
1200    /// - If self doesn't match the given transaction type, the transaction is returned as-is.
1201    pub fn downcast<D>(self) -> Result<D, Self>
1202    where
1203        Self: DowncastOwned<D>,
1204    {
1205        self.downcast_owned()
1206    }
1207}
1208
1209// this is macro worthy (there's like 40 transactions that all do this the exact same way)
1210/// Impl `DowncastOwned` for `AnyTransactionData`.
1211///
1212/// This macro will ensure you get all variants via a pattern match, if something changes (say, another transaction type is added), you'll get a `Missing match arm` compiler error.
1213macro_rules! impl_cast_any {
1214    ($($id:ident),+$(,)?) => {
1215        $(
1216            impl $crate::downcast::DowncastOwned<data::$id> for AnyTransactionData {
1217                fn downcast_owned(self) -> Result<data::$id, Self> {
1218                    let Self::$id(data) = self else {
1219                        return Err(self)
1220                    };
1221
1222                    Ok(data)
1223                }
1224            }
1225
1226            impl From<Transaction<data::$id>> for AnyTransaction {
1227                fn from(transaction: Transaction<data::$id>) -> Self {
1228                    Self {
1229                        body: TransactionBody {
1230                            data: transaction.body.data.into(),
1231                            node_account_ids: transaction.body.node_account_ids,
1232                            transaction_valid_duration: transaction.body.transaction_valid_duration,
1233                            max_transaction_fee: transaction.body.max_transaction_fee,
1234                            transaction_memo: transaction.body.transaction_memo,
1235                            transaction_id: transaction.body.transaction_id,
1236                            operator: transaction.body.operator,
1237                            is_frozen: transaction.body.is_frozen,
1238                            regenerate_transaction_id: transaction.body.regenerate_transaction_id,
1239                            custom_fee_limits: transaction.body.custom_fee_limits,
1240                            batch_key: transaction.body.batch_key,
1241                            high_volume: transaction.body.high_volume,
1242                        },
1243                        signers: transaction.signers,
1244                        sources: transaction.sources,
1245                        grpc_deadline: transaction.grpc_deadline,
1246                        request_timeout: transaction.request_timeout,
1247                    }
1248                }
1249            }
1250        )*
1251
1252        #[allow(non_snake_case)]
1253        mod ___private_impl_cast_any {
1254            use super::AnyTransactionData;
1255            // ensure the what we were given is actually everything.
1256            fn _assert_exhaustive(d: AnyTransactionData)
1257            {
1258                match d {
1259                    $(AnyTransactionData::$id(_) => {},)+
1260                }
1261            }
1262        }
1263    };
1264}
1265
1266impl_cast_any! {
1267    AccountCreate,
1268    AccountUpdate,
1269    AccountDelete,
1270    AccountAllowanceApprove,
1271    AccountAllowanceDelete,
1272    ContractCreate,
1273    ContractUpdate,
1274    ContractDelete,
1275    ContractExecute,
1276    Transfer,
1277    TopicCreate,
1278    TopicUpdate,
1279    TopicDelete,
1280    TopicMessageSubmit,
1281    FileAppend,
1282    FileCreate,
1283    FileUpdate,
1284    FileDelete,
1285    Prng,
1286    ScheduleCreate,
1287    ScheduleSign,
1288    ScheduleDelete,
1289    TokenAssociate,
1290    TokenBurn,
1291    TokenCreate,
1292    TokenDelete,
1293    TokenDissociate,
1294    TokenFeeScheduleUpdate,
1295    TokenFreeze,
1296    TokenGrantKyc,
1297    TokenMint,
1298    TokenPause,
1299    TokenRevokeKyc,
1300    TokenUnfreeze,
1301    TokenUnpause,
1302    TokenUpdate,
1303    TokenWipe,
1304    SystemDelete,
1305    SystemUndelete,
1306    Freeze,
1307    Ethereum,
1308    TokenUpdateNfts,
1309    NodeCreate,
1310    NodeUpdate,
1311    NodeDelete,
1312    TokenReject,
1313             TokenAirdrop,
1314    TokenClaimAirdrop,
1315    TokenCancelAirdrop,
1316    Batch,
1317    HookStore
1318}