Skip to main content

hiero_sdk/account/
account_create_transaction.rs

1// SPDX-License-Identifier: Apache-2.0
2
3use hiero_sdk_proto::services;
4use hiero_sdk_proto::services::crypto_service_client::CryptoServiceClient;
5use time::Duration;
6use tonic::transport::Channel;
7
8use crate::hooks::{
9    EvmHook,
10    HookCreationDetails,
11};
12use crate::ledger_id::RefLedgerId;
13use crate::protobuf::{
14    FromProtobuf,
15    ToProtobuf,
16};
17use crate::staked_id::StakedId;
18use crate::transaction::{
19    AnyTransactionData,
20    ChunkInfo,
21    ToSchedulableTransactionDataProtobuf,
22    ToTransactionDataProtobuf,
23    TransactionData,
24    TransactionExecute,
25};
26use crate::{
27    AccountId,
28    BoxGrpcFuture,
29    Error,
30    EvmAddress,
31    Hbar,
32    Key,
33    Transaction,
34    ValidateChecksums,
35};
36
37/// Create a new Hieroâ„¢ account.
38pub type AccountCreateTransaction = Transaction<AccountCreateTransactionData>;
39
40// TODO: shard_id: Option<ShardId>
41// TODO: realm_id: Option<RealmId>
42// TODO: new_realm_admin_key: Option<Key>,
43
44#[derive(Debug, Clone)]
45pub struct AccountCreateTransactionData {
46    /// The key that must sign each transfer out of the account.
47    ///
48    /// If `receiver_signature_required` is true, then it must also sign any transfer
49    /// into the account.
50    key: Option<Key>,
51
52    /// The initial number of Hbar to put into the account.
53    initial_balance: Hbar,
54
55    /// If true, this account's key must sign any transaction depositing into this account.
56    receiver_signature_required: bool,
57
58    /// The account is charged to extend its expiration date every this many seconds.
59    auto_renew_period: Option<Duration>,
60
61    /// The account to be used at this account's expiration time to extend the
62    /// life of the account.  If `None`, this account pays for its own auto renewal fee.
63    auto_renew_account_id: Option<AccountId>,
64
65    /// The memo associated with the account.
66    account_memo: String,
67
68    /// The maximum number of tokens that an Account can be implicitly associated with.
69    ///
70    /// Defaults to `0`. Allows up to a maximum value of `1000`.
71    /// If the value is set to `-1`, unlimited automatic token associations are allowed.
72    max_automatic_token_associations: i32,
73
74    // notably *not* a PublicKey.
75    /// A 20-byte EVM address to be used as the account's alias.
76    alias: Option<EvmAddress>,
77
78    /// ID of the account or node to which this account is staking, if any.
79    staked_id: Option<StakedId>,
80
81    /// If true, the account declines receiving a staking reward. The default value is false.
82    decline_staking_reward: bool,
83
84    /// Hooks to add immediately after creating this account.
85    hooks: Vec<HookCreationDetails>,
86}
87
88impl Default for AccountCreateTransactionData {
89    fn default() -> Self {
90        Self {
91            key: None,
92            initial_balance: Hbar::ZERO,
93            receiver_signature_required: false,
94            auto_renew_period: Some(Duration::days(90)),
95            auto_renew_account_id: None,
96            account_memo: String::new(),
97            max_automatic_token_associations: 0,
98            alias: None,
99            staked_id: None,
100            decline_staking_reward: false,
101            hooks: Vec::new(),
102        }
103    }
104}
105
106impl AccountCreateTransaction {
107    /// Sets the ECDSA(secp256k1) private key as the account key and derives the alias (EVM address) from it.
108    pub fn set_ecdsa_key_with_alias(&mut self, ecdsa_key: crate::PrivateKey) -> &mut Self {
109        if !ecdsa_key.is_ecdsa() {
110            panic!("Provided key is not an ECDSA(secp256k1) private key");
111        }
112        let public_key = ecdsa_key.public_key();
113        let evm_address = public_key
114            .to_evm_address()
115            .expect("Failed to derive EVM address from ECDSA public key");
116        self.data_mut().key = Some(public_key.clone().into());
117        self.alias(evm_address);
118        self
119    }
120
121    /// Sets a generic key and an ECDSA(secp256k1) private key, and derives the alias from the ECDSA key.
122    pub fn set_key_with_alias(
123        &mut self,
124        key: impl Into<Key>,
125        ecdsa_key: crate::PrivateKey,
126    ) -> &mut Self {
127        if !ecdsa_key.is_ecdsa() {
128            panic!("Provided key is not an ECDSA(secp256k1) private key");
129        }
130        let public_key = ecdsa_key.public_key();
131        let evm_address = public_key
132            .to_evm_address()
133            .expect("Failed to derive EVM address from ECDSA public key");
134        self.data_mut().key = Some(key.into());
135        self.alias(evm_address);
136        self
137    }
138
139    /// Sets a generic key and unsets the alias.
140    pub fn set_key_without_alias(&mut self, key: impl Into<Key>) -> &mut Self {
141        self.data_mut().key = Some(key.into());
142        self.data_mut().alias = None;
143        self
144    }
145
146    /// Get the key this account will be created with.
147    ///
148    /// Returns `Some(key)` if previously set, `None` otherwise.
149    #[must_use]
150    pub fn get_key(&self) -> Option<&Key> {
151        self.data().key.as_ref()
152    }
153
154    /// Sets the key for this account.
155    #[deprecated(note = "use set_key_without_alias instead")]
156    pub fn key(&mut self, key: impl Into<Key>) -> &mut Self {
157        self.data_mut().key = Some(key.into());
158        self
159    }
160
161    /// Get the balance that will be transferred to this account on creation.
162    ///
163    /// Returns `initial_balance` if previously set, `0` otherwise.
164    #[must_use]
165    pub fn get_initial_balance(&self) -> Hbar {
166        self.data().initial_balance
167    }
168
169    /// Sets the balance that will be transferred to this account on creation.
170    pub fn initial_balance(&mut self, balance: Hbar) -> &mut Self {
171        self.data_mut().initial_balance = balance;
172        self
173    }
174
175    /// Returns `true` if this account must sign any transfer of hbars _to_ itself.
176    #[must_use]
177    pub fn get_receiver_signature_required(&self) -> bool {
178        self.data().receiver_signature_required
179    }
180
181    /// Sets to true to require this account to sign any transfer of hbars to this account.
182    pub fn receiver_signature_required(&mut self, required: bool) -> &mut Self {
183        self.data_mut().receiver_signature_required = required;
184        self
185    }
186
187    /// Returns the auto renew period for this account.
188    #[must_use]
189    pub fn get_auto_renew_period(&self) -> Option<Duration> {
190        self.data().auto_renew_period
191    }
192
193    /// Sets the auto renew period for this account.
194    pub fn auto_renew_period(&mut self, period: Duration) -> &mut Self {
195        self.data_mut().auto_renew_period = Some(period);
196        self
197    }
198
199    /// Gets the account to be used at this account's expiration time to extend the
200    /// life of the account.  If `None`, this account pays for its own auto renewal fee.
201    ///
202    /// # Network Support
203    /// Please note that this not supported on any hedera network at this time.
204    #[must_use]
205    pub fn get_auto_renew_account_id(&self) -> Option<AccountId> {
206        self.data().auto_renew_account_id
207    }
208
209    /// Sets the account to be used at this account's expiration time to extend the
210    /// life of the account.  If `None`, this account pays for its own auto renewal fee.
211    ///
212    /// # Network Support
213    /// Please note that this not supported on any hedera network at this time.
214    pub fn auto_renew_account_id(&mut self, id: AccountId) -> &mut Self {
215        self.data_mut().auto_renew_account_id = Some(id);
216        self
217    }
218
219    /// Get the memo associated with the account
220    #[must_use]
221    pub fn get_account_memo(&self) -> &str {
222        &self.data().account_memo
223    }
224
225    /// Sets the memo associated with the account.
226    pub fn account_memo(&mut self, memo: impl Into<String>) -> &mut Self {
227        self.data_mut().account_memo = memo.into();
228        self
229    }
230
231    /// Get the maximum number of tokens that an Account can be implicitly associated with.
232    ///
233    /// Defaults to `0`. Allows up to a maximum value of `1000`.
234    #[must_use]
235    pub fn get_max_automatic_token_associations(&self) -> i32 {
236        self.data().max_automatic_token_associations
237    }
238
239    /// Sets the maximum number of tokens that an Account can be implicitly associated with.
240    pub fn max_automatic_token_associations(&mut self, amount: i32) -> &mut Self {
241        self.data_mut().max_automatic_token_associations = amount;
242        self
243    }
244
245    /// Returns the evm address the account will be created with as an alias.
246    ///
247    /// # Network Support
248    /// Please note that this not currently supported on mainnet.
249    #[must_use]
250    pub fn get_alias(&self) -> Option<EvmAddress> {
251        self.data().alias
252    }
253
254    /// Sets the evm address the account will be created with as an alias.
255    ///
256    /// The last 20 bytes of the keccak-256 hash of a `ECDSA_SECP256K1` primitive key.
257    ///
258    /// # Network Support
259    /// Please note that this not currently supported on mainnet.
260    pub fn alias(&mut self, alias: EvmAddress) -> &mut Self {
261        self.data_mut().alias = Some(alias);
262        self
263    }
264
265    /// Returns the ID of the account to which this account is staking.
266    /// This is mutually exclusive with `staked_node_id`.
267    #[must_use]
268    pub fn get_staked_account_id(&self) -> Option<AccountId> {
269        self.data().staked_id.and_then(StakedId::to_account_id)
270    }
271
272    /// Sets the ID of the account to which this account is staking.
273    /// This is mutually exclusive with `staked_node_id`.
274    pub fn staked_account_id(&mut self, id: AccountId) -> &mut Self {
275        self.data_mut().staked_id = Some(StakedId::AccountId(id));
276        self
277    }
278
279    /// Returns the ID of the node to which this account is staking.
280    /// This is mutually exclusive with `staked_account_id`.
281    #[must_use]
282    pub fn get_staked_node_id(&self) -> Option<u64> {
283        self.data().staked_id.and_then(StakedId::to_node_id)
284    }
285
286    /// Sets the ID of the node to which this account is staking.
287    /// This is mutually exclusive with `staked_account_id`.
288    pub fn staked_node_id(&mut self, id: u64) -> &mut Self {
289        self.data_mut().staked_id = Some(StakedId::NodeId(id));
290        self
291    }
292
293    /// Returns `true` if the account should decline receiving staking rewards, `false` otherwise.
294    #[must_use]
295    pub fn get_decline_staking_reward(&self) -> bool {
296        self.data().decline_staking_reward
297    }
298
299    /// If `true`, the account declines receiving a staking reward. The default value is false.
300    pub fn decline_staking_reward(&mut self, decline: bool) -> &mut Self {
301        self.data_mut().decline_staking_reward = decline;
302        self
303    }
304
305    pub fn add_hook(&mut self, hook: HookCreationDetails) -> &mut Self {
306        self.data_mut().hooks.push(hook);
307        self
308    }
309
310    pub fn add_evm_hook(&mut self, hook: EvmHook) -> &mut Self {
311        // Helper to add a Lambda EVM hook with default extension point and hook ID
312        use crate::hooks::HookExtensionPoint;
313        let details =
314            HookCreationDetails::new(HookExtensionPoint::AccountAllowanceHook, 1, Some(hook));
315        self.data_mut().hooks.push(details);
316        self
317    }
318
319    pub fn set_hooks(&mut self, hooks: Vec<HookCreationDetails>) -> &mut Self {
320        self.data_mut().hooks = hooks;
321        self
322    }
323
324    pub fn get_hooks(&self) -> &[HookCreationDetails] {
325        &self.data().hooks
326    }
327}
328
329impl TransactionData for AccountCreateTransactionData {}
330
331impl TransactionExecute for AccountCreateTransactionData {
332    fn execute(
333        &self,
334        channel: Channel,
335        request: services::Transaction,
336    ) -> BoxGrpcFuture<'_, services::TransactionResponse> {
337        Box::pin(async { CryptoServiceClient::new(channel).create_account(request).await })
338    }
339}
340
341impl ValidateChecksums for AccountCreateTransactionData {
342    fn validate_checksums(&self, ledger_id: &RefLedgerId) -> Result<(), Error> {
343        self.staked_id.validate_checksums(ledger_id)
344    }
345}
346
347impl ToTransactionDataProtobuf for AccountCreateTransactionData {
348    fn to_transaction_data_protobuf(
349        &self,
350        chunk_info: &ChunkInfo,
351    ) -> services::transaction_body::Data {
352        let _ = chunk_info.assert_single_transaction();
353
354        services::transaction_body::Data::CryptoCreateAccount(self.to_protobuf())
355    }
356}
357
358impl ToSchedulableTransactionDataProtobuf for AccountCreateTransactionData {
359    fn to_schedulable_transaction_data_protobuf(
360        &self,
361    ) -> services::schedulable_transaction_body::Data {
362        services::schedulable_transaction_body::Data::CryptoCreateAccount(self.to_protobuf())
363    }
364}
365
366impl From<AccountCreateTransactionData> for AnyTransactionData {
367    fn from(transaction: AccountCreateTransactionData) -> Self {
368        Self::AccountCreate(transaction)
369    }
370}
371
372impl FromProtobuf<services::CryptoCreateTransactionBody> for AccountCreateTransactionData {
373    fn from_protobuf(pb: services::CryptoCreateTransactionBody) -> crate::Result<Self> {
374        let alias = (!pb.alias.is_empty()).then(|| EvmAddress::try_from(pb.alias)).transpose()?;
375
376        Ok(Self {
377            key: Option::from_protobuf(pb.key)?,
378            initial_balance: Hbar::from_tinybars(pb.initial_balance as i64),
379            receiver_signature_required: pb.receiver_sig_required,
380            auto_renew_period: pb.auto_renew_period.map(Into::into),
381            auto_renew_account_id: None,
382            account_memo: pb.memo,
383            max_automatic_token_associations: pb.max_automatic_token_associations,
384            alias,
385            staked_id: Option::from_protobuf(pb.staked_id)?,
386            decline_staking_reward: pb.decline_reward,
387            hooks: pb
388                .hook_creation_details
389                .into_iter()
390                .map(HookCreationDetails::from_protobuf)
391                .collect::<Result<Vec<_>, _>>()?,
392        })
393    }
394}
395
396impl ToProtobuf for AccountCreateTransactionData {
397    type Protobuf = services::CryptoCreateTransactionBody;
398
399    fn to_protobuf(&self) -> Self::Protobuf {
400        let key = self.key.to_protobuf();
401        let auto_renew_period = self.auto_renew_period.to_protobuf();
402        let staked_id = self.staked_id.map(|it| match it {
403            StakedId::NodeId(id) => {
404                services::crypto_create_transaction_body::StakedId::StakedNodeId(id as i64)
405            }
406            StakedId::AccountId(id) => {
407                services::crypto_create_transaction_body::StakedId::StakedAccountId(
408                    id.to_protobuf(),
409                )
410            }
411        });
412
413        #[allow(deprecated)]
414        services::CryptoCreateTransactionBody {
415            key,
416            initial_balance: self.initial_balance.to_tinybars() as u64,
417            proxy_account_id: None,
418            send_record_threshold: i64::MAX as u64,
419            receive_record_threshold: i64::MAX as u64,
420            receiver_sig_required: self.receiver_signature_required,
421            auto_renew_period,
422            shard_id: None,
423            realm_id: None,
424            new_realm_admin_key: None,
425            memo: self.account_memo.clone(),
426            max_automatic_token_associations: i32::from(self.max_automatic_token_associations),
427            alias: self.alias.map_or(vec![], |it| it.to_bytes().to_vec()),
428            decline_reward: self.decline_staking_reward,
429            staked_id,
430            hook_creation_details: self.hooks.iter().map(|h| h.to_protobuf()).collect(),
431            delegation_address: Vec::new(),
432        }
433    }
434}
435
436#[cfg(test)]
437mod tests {
438    use expect_test::expect;
439    use hex_literal::hex;
440    use hiero_sdk_proto::services;
441    use time::Duration;
442
443    use crate::account::AccountCreateTransactionData;
444    use crate::protobuf::{
445        FromProtobuf,
446        ToProtobuf,
447    };
448    use crate::staked_id::StakedId;
449    use crate::transaction::test_helpers::{
450        check_body,
451        transaction_body,
452        unused_private_key,
453    };
454    use crate::{
455        AccountCreateTransaction,
456        AccountId,
457        AnyTransaction,
458        ContractId,
459        EvmAddress,
460        EvmHook,
461        EvmHookSpec,
462        Hbar,
463        HookCreationDetails,
464        HookExtensionPoint,
465        PublicKey,
466    };
467
468    fn key() -> PublicKey {
469        unused_private_key().public_key()
470    }
471
472    const INITIAL_BALANCE: Hbar = Hbar::from_tinybars(450);
473    const ACCOUNT_MEMO: &str = "some memo";
474    const RECEIVER_SIGNATURE_REQUIRED: bool = true;
475    const AUTO_RENEW_PERIOD: Duration = Duration::hours(10);
476    const STAKED_ACCOUNT_ID: AccountId = AccountId::new(0, 0, 3);
477    const STAKED_NODE_ID: u64 = 4;
478    const ALIAS: EvmAddress = EvmAddress(hex!("5c562e90feaf0eebd33ea75d21024f249d451417"));
479    const MAX_AUTOMATIC_TOKEN_ASSOCIATIONS: i32 = 100;
480
481    fn make_transaction() -> AccountCreateTransaction {
482        let mut tx = AccountCreateTransaction::new_for_tests();
483
484        tx.set_key_without_alias(key())
485            .initial_balance(INITIAL_BALANCE)
486            .account_memo(ACCOUNT_MEMO)
487            .receiver_signature_required(RECEIVER_SIGNATURE_REQUIRED)
488            .auto_renew_period(AUTO_RENEW_PERIOD)
489            .staked_account_id(STAKED_ACCOUNT_ID)
490            .alias(ALIAS)
491            .max_automatic_token_associations(MAX_AUTOMATIC_TOKEN_ASSOCIATIONS)
492            .freeze()
493            .unwrap();
494
495        return tx;
496    }
497
498    fn make_transaction2() -> AccountCreateTransaction {
499        let mut tx = AccountCreateTransaction::new_for_tests();
500
501        tx.set_key_without_alias(key())
502            .initial_balance(INITIAL_BALANCE)
503            .account_memo(ACCOUNT_MEMO)
504            .receiver_signature_required(RECEIVER_SIGNATURE_REQUIRED)
505            .auto_renew_period(AUTO_RENEW_PERIOD)
506            .staked_node_id(STAKED_NODE_ID)
507            .alias(ALIAS)
508            .max_automatic_token_associations(MAX_AUTOMATIC_TOKEN_ASSOCIATIONS)
509            .freeze()
510            .unwrap();
511
512        return tx;
513    }
514
515    #[test]
516    fn serialize() {
517        let tx = make_transaction();
518
519        let tx = transaction_body(tx);
520
521        let tx = check_body(tx);
522
523        expect![[r#"
524            CryptoCreateAccount(
525                CryptoCreateTransactionBody {
526                    key: Some(
527                        Key {
528                            key: Some(
529                                Ed25519(
530                                    [
531                                        224,
532                                        200,
533                                        236,
534                                        39,
535                                        88,
536                                        165,
537                                        135,
538                                        159,
539                                        250,
540                                        194,
541                                        38,
542                                        161,
543                                        60,
544                                        12,
545                                        81,
546                                        107,
547                                        121,
548                                        158,
549                                        114,
550                                        227,
551                                        81,
552                                        65,
553                                        160,
554                                        221,
555                                        130,
556                                        143,
557                                        148,
558                                        211,
559                                        121,
560                                        136,
561                                        164,
562                                        183,
563                                    ],
564                                ),
565                            ),
566                        },
567                    ),
568                    initial_balance: 450,
569                    proxy_account_id: None,
570                    send_record_threshold: 9223372036854775807,
571                    receive_record_threshold: 9223372036854775807,
572                    receiver_sig_required: true,
573                    auto_renew_period: Some(
574                        Duration {
575                            seconds: 36000,
576                        },
577                    ),
578                    shard_id: None,
579                    realm_id: None,
580                    new_realm_admin_key: None,
581                    memo: "some memo",
582                    max_automatic_token_associations: 100,
583                    decline_reward: false,
584                    alias: [
585                        92,
586                        86,
587                        46,
588                        144,
589                        254,
590                        175,
591                        14,
592                        235,
593                        211,
594                        62,
595                        167,
596                        93,
597                        33,
598                        2,
599                        79,
600                        36,
601                        157,
602                        69,
603                        20,
604                        23,
605                    ],
606                    hook_creation_details: [],
607                    delegation_address: [],
608                    staked_id: Some(
609                        StakedAccountId(
610                            AccountId {
611                                shard_num: 0,
612                                realm_num: 0,
613                                account: Some(
614                                    AccountNum(
615                                        3,
616                                    ),
617                                ),
618                            },
619                        ),
620                    ),
621                },
622            )
623        "#]]
624        .assert_debug_eq(&tx)
625    }
626
627    #[test]
628    fn to_from_bytes() {
629        let tx = make_transaction();
630
631        let tx2 = AnyTransaction::from_bytes(&tx.to_bytes().unwrap()).unwrap();
632
633        let tx = transaction_body(tx);
634
635        let tx2 = transaction_body(tx2);
636
637        assert_eq!(tx, tx2);
638    }
639
640    #[test]
641    fn serialize2() {
642        let tx = make_transaction2();
643
644        let tx = transaction_body(tx);
645
646        let tx = check_body(tx);
647
648        expect![[r#"
649            CryptoCreateAccount(
650                CryptoCreateTransactionBody {
651                    key: Some(
652                        Key {
653                            key: Some(
654                                Ed25519(
655                                    [
656                                        224,
657                                        200,
658                                        236,
659                                        39,
660                                        88,
661                                        165,
662                                        135,
663                                        159,
664                                        250,
665                                        194,
666                                        38,
667                                        161,
668                                        60,
669                                        12,
670                                        81,
671                                        107,
672                                        121,
673                                        158,
674                                        114,
675                                        227,
676                                        81,
677                                        65,
678                                        160,
679                                        221,
680                                        130,
681                                        143,
682                                        148,
683                                        211,
684                                        121,
685                                        136,
686                                        164,
687                                        183,
688                                    ],
689                                ),
690                            ),
691                        },
692                    ),
693                    initial_balance: 450,
694                    proxy_account_id: None,
695                    send_record_threshold: 9223372036854775807,
696                    receive_record_threshold: 9223372036854775807,
697                    receiver_sig_required: true,
698                    auto_renew_period: Some(
699                        Duration {
700                            seconds: 36000,
701                        },
702                    ),
703                    shard_id: None,
704                    realm_id: None,
705                    new_realm_admin_key: None,
706                    memo: "some memo",
707                    max_automatic_token_associations: 100,
708                    decline_reward: false,
709                    alias: [
710                        92,
711                        86,
712                        46,
713                        144,
714                        254,
715                        175,
716                        14,
717                        235,
718                        211,
719                        62,
720                        167,
721                        93,
722                        33,
723                        2,
724                        79,
725                        36,
726                        157,
727                        69,
728                        20,
729                        23,
730                    ],
731                    hook_creation_details: [],
732                    delegation_address: [],
733                    staked_id: Some(
734                        StakedNodeId(
735                            4,
736                        ),
737                    ),
738                },
739            )
740        "#]]
741        .assert_debug_eq(&tx)
742    }
743
744    #[test]
745    fn to_from_bytes2() {
746        let tx = make_transaction2();
747
748        let tx2 = AnyTransaction::from_bytes(&tx.to_bytes().unwrap()).unwrap();
749
750        let tx = transaction_body(tx);
751
752        let tx2 = transaction_body(tx2);
753
754        assert_eq!(tx, tx2);
755    }
756
757    #[test]
758    fn from_proto_body() {
759        #[allow(deprecated)]
760        let contract_id = ContractId::new(0, 0, 1);
761        let hooks = vec![HookCreationDetails::new(
762            HookExtensionPoint::AccountAllowanceHook,
763            0,
764            Some(EvmHook::new(EvmHookSpec::new(Some(contract_id)), vec![])),
765        )];
766
767        let tx = services::CryptoCreateTransactionBody {
768            key: Some(key().to_protobuf()),
769            initial_balance: INITIAL_BALANCE.to_tinybars() as u64,
770            proxy_account_id: None,
771            send_record_threshold: i64::MAX as u64,
772            receive_record_threshold: i64::MAX as u64,
773            receiver_sig_required: RECEIVER_SIGNATURE_REQUIRED,
774            auto_renew_period: Some(AUTO_RENEW_PERIOD.to_protobuf()),
775            shard_id: None,
776            realm_id: None,
777            new_realm_admin_key: None,
778            memo: ACCOUNT_MEMO.to_owned(),
779            max_automatic_token_associations: MAX_AUTOMATIC_TOKEN_ASSOCIATIONS,
780            decline_reward: false,
781            alias: ALIAS.to_bytes().to_vec(),
782            staked_id: Some(services::crypto_create_transaction_body::StakedId::StakedAccountId(
783                STAKED_ACCOUNT_ID.to_protobuf(),
784            )),
785            hook_creation_details: hooks.iter().map(|h| h.to_protobuf()).collect(),
786            delegation_address: Vec::new(),
787        };
788
789        let tx = AccountCreateTransactionData::from_protobuf(tx).unwrap();
790
791        assert_eq!(tx.key, Some(key().into()));
792        assert_eq!(tx.initial_balance, INITIAL_BALANCE);
793        assert_eq!(tx.account_memo, ACCOUNT_MEMO);
794        assert_eq!(tx.receiver_signature_required, RECEIVER_SIGNATURE_REQUIRED);
795        assert_eq!(tx.auto_renew_period, Some(AUTO_RENEW_PERIOD));
796        assert_eq!(tx.staked_id.and_then(StakedId::to_account_id), Some(STAKED_ACCOUNT_ID));
797        assert_eq!(tx.alias, Some(ALIAS));
798        assert_eq!(tx.max_automatic_token_associations, MAX_AUTOMATIC_TOKEN_ASSOCIATIONS);
799    }
800
801    #[test]
802    fn properties() {
803        let tx = make_transaction();
804
805        assert_eq!(tx.get_key(), Some(&key().into()));
806        assert_eq!(tx.get_initial_balance(), INITIAL_BALANCE);
807        assert_eq!(tx.get_account_memo(), ACCOUNT_MEMO);
808        assert_eq!(tx.get_receiver_signature_required(), RECEIVER_SIGNATURE_REQUIRED);
809        assert_eq!(tx.get_auto_renew_period(), Some(AUTO_RENEW_PERIOD));
810        assert_eq!(tx.get_staked_account_id(), Some(STAKED_ACCOUNT_ID));
811        assert_eq!(tx.get_alias(), Some(ALIAS));
812        assert_eq!(tx.get_max_automatic_token_associations(), MAX_AUTOMATIC_TOKEN_ASSOCIATIONS);
813    }
814
815    #[test]
816    fn get_set_key() {
817        let mut tx = AccountCreateTransaction::new();
818        tx.set_key_without_alias(key());
819
820        assert_eq!(tx.get_key(), Some(&key().into()));
821    }
822
823    #[test]
824    #[should_panic]
825    fn get_set_key_frozen_panics() {
826        let mut tx = make_transaction();
827
828        tx.set_key_without_alias(key());
829    }
830
831    #[test]
832    fn get_set_initial_balance() {
833        let mut tx = AccountCreateTransaction::new();
834        tx.initial_balance(INITIAL_BALANCE);
835
836        assert_eq!(tx.get_initial_balance(), INITIAL_BALANCE);
837    }
838
839    #[test]
840    #[should_panic]
841    fn get_set_initial_balance_frozen_panics() {
842        let mut tx = make_transaction();
843
844        tx.initial_balance(INITIAL_BALANCE);
845    }
846
847    #[test]
848    fn get_set_account_memo() {
849        let mut tx = AccountCreateTransaction::new();
850        tx.account_memo(ACCOUNT_MEMO);
851
852        assert_eq!(tx.get_account_memo(), ACCOUNT_MEMO);
853    }
854
855    #[test]
856    #[should_panic]
857    fn get_set_account_memo_frozen_panics() {
858        let mut tx = make_transaction();
859
860        tx.account_memo(ACCOUNT_MEMO);
861    }
862
863    #[test]
864    fn get_set_receiver_signature_required() {
865        let mut tx = AccountCreateTransaction::new();
866        tx.receiver_signature_required(RECEIVER_SIGNATURE_REQUIRED);
867
868        assert_eq!(tx.get_receiver_signature_required(), RECEIVER_SIGNATURE_REQUIRED);
869    }
870
871    #[test]
872    #[should_panic]
873    fn get_set_receiver_signature_required_frozen_panics() {
874        let mut tx = make_transaction();
875
876        tx.receiver_signature_required(RECEIVER_SIGNATURE_REQUIRED);
877    }
878
879    #[test]
880    fn get_set_auto_renew_period() {
881        let mut tx = AccountCreateTransaction::new();
882        tx.auto_renew_period(AUTO_RENEW_PERIOD);
883
884        assert_eq!(tx.get_auto_renew_period(), Some(AUTO_RENEW_PERIOD));
885    }
886
887    #[test]
888    #[should_panic]
889    fn get_set_auto_renew_period_frozen_panics() {
890        let mut tx = make_transaction();
891
892        tx.auto_renew_period(AUTO_RENEW_PERIOD);
893    }
894
895    #[test]
896    fn get_set_staked_account_id() {
897        let mut tx = AccountCreateTransaction::new();
898        tx.staked_account_id(STAKED_ACCOUNT_ID);
899
900        assert_eq!(tx.get_staked_account_id(), Some(STAKED_ACCOUNT_ID));
901    }
902
903    #[test]
904    #[should_panic]
905    fn get_set_staked_account_id_frozen_panics() {
906        let mut tx = make_transaction();
907
908        tx.staked_account_id(STAKED_ACCOUNT_ID);
909    }
910
911    #[test]
912    fn get_set_alias() {
913        let mut tx = AccountCreateTransaction::new();
914        tx.alias(ALIAS);
915
916        assert_eq!(tx.get_alias(), Some(ALIAS));
917    }
918
919    #[test]
920    #[should_panic]
921    fn get_set_alias_frozen_panics() {
922        let mut tx = make_transaction();
923
924        tx.alias(ALIAS);
925    }
926
927    #[test]
928    fn get_set_max_automatic_token_associations() {
929        let mut tx = AccountCreateTransaction::new();
930        tx.max_automatic_token_associations(MAX_AUTOMATIC_TOKEN_ASSOCIATIONS);
931
932        assert_eq!(tx.get_max_automatic_token_associations(), MAX_AUTOMATIC_TOKEN_ASSOCIATIONS);
933    }
934
935    #[test]
936    #[should_panic]
937    fn get_set_max_automatic_token_associations_frozen_panics() {
938        let mut tx = make_transaction();
939
940        tx.max_automatic_token_associations(MAX_AUTOMATIC_TOKEN_ASSOCIATIONS);
941    }
942
943    #[test]
944    fn set_ecdsa_key_with_alias_sets_key_and_alias() {
945        use crate::PrivateKey;
946        let ecdsa_key = PrivateKey::generate_ecdsa();
947        let public_key = ecdsa_key.public_key();
948        let evm_address = public_key.to_evm_address().unwrap();
949
950        let mut tx = AccountCreateTransaction::new();
951        tx.set_ecdsa_key_with_alias(ecdsa_key.clone());
952
953        assert_eq!(tx.get_key(), Some(&public_key.into()));
954        assert_eq!(tx.get_alias(), Some(evm_address));
955    }
956
957    #[test]
958    fn set_key_with_alias_sets_key_and_alias() {
959        use crate::{
960            Key,
961            PrivateKey,
962        };
963        let ecdsa_key = PrivateKey::generate_ecdsa();
964        let public_key = ecdsa_key.public_key();
965        let evm_address = public_key.to_evm_address().unwrap();
966        let generic_key = Key::Single(public_key.clone());
967
968        let mut tx = AccountCreateTransaction::new();
969        tx.set_key_with_alias(generic_key.clone(), ecdsa_key.clone());
970
971        assert_eq!(tx.get_key(), Some(&generic_key));
972        assert_eq!(tx.get_alias(), Some(evm_address));
973    }
974
975    #[test]
976    fn set_key_without_alias_sets_key_and_unsets_alias() {
977        use crate::{
978            Key,
979            PrivateKey,
980        };
981        let ecdsa_key = PrivateKey::generate_ecdsa();
982        let public_key = ecdsa_key.public_key();
983        let generic_key = Key::Single(public_key.clone());
984
985        let mut tx = AccountCreateTransaction::new();
986        tx.set_key_without_alias(generic_key.clone());
987
988        assert_eq!(tx.get_key(), Some(&generic_key));
989        assert_eq!(tx.get_alias(), None);
990    }
991}