Skip to main content

hiero_sdk/contract/
contract_update_transaction.rs

1// SPDX-License-Identifier: Apache-2.0
2
3use hiero_sdk_proto::services;
4use hiero_sdk_proto::services::smart_contract_service_client::SmartContractServiceClient;
5use time::{
6    Duration,
7    OffsetDateTime,
8};
9use tonic::transport::Channel;
10
11use crate::hooks::HookCreationDetails;
12use crate::ledger_id::RefLedgerId;
13use crate::protobuf::FromProtobuf;
14use crate::staked_id::StakedId;
15use crate::transaction::{
16    AnyTransactionData,
17    ChunkInfo,
18    ToSchedulableTransactionDataProtobuf,
19    ToTransactionDataProtobuf,
20    TransactionData,
21    TransactionExecute,
22};
23use crate::{
24    AccountId,
25    BoxGrpcFuture,
26    ContractId,
27    Error,
28    Key,
29    ToProtobuf,
30    Transaction,
31    ValidateChecksums,
32};
33
34/// Updates the fields of a smart contract to the given values.
35pub type ContractUpdateTransaction = Transaction<ContractUpdateTransactionData>;
36
37#[derive(Debug, Default, Clone)]
38pub struct ContractUpdateTransactionData {
39    contract_id: Option<ContractId>,
40
41    expiration_time: Option<OffsetDateTime>,
42
43    admin_key: Option<Key>,
44
45    auto_renew_period: Option<Duration>,
46
47    contract_memo: Option<String>,
48
49    max_automatic_token_associations: Option<i32>,
50
51    auto_renew_account_id: Option<AccountId>,
52
53    proxy_account_id: Option<AccountId>,
54
55    /// ID of the account or node to which this contract is staking, if any.
56    staked_id: Option<StakedId>,
57
58    decline_staking_reward: Option<bool>,
59
60    /// Hooks to add immediately after updating this contract.
61    hooks: Vec<HookCreationDetails>,
62    hook_ids_to_delete: Vec<i64>,
63}
64
65impl ContractUpdateTransaction {
66    /// Returns the contract to be updated.
67    #[must_use]
68    pub fn get_contract_id(&self) -> Option<ContractId> {
69        self.data().contract_id
70    }
71
72    /// Sets the contract to be updated.
73    pub fn contract_id(&mut self, contract_id: ContractId) -> &mut Self {
74        self.data_mut().contract_id = Some(contract_id);
75        self
76    }
77
78    /// Returns the new admin key.
79    #[must_use]
80    pub fn get_admin_key(&self) -> Option<&Key> {
81        self.data().admin_key.as_ref()
82    }
83
84    /// Sets the new admin key.
85    pub fn admin_key(&mut self, key: impl Into<Key>) -> &mut Self {
86        self.data_mut().admin_key = Some(key.into());
87        self
88    }
89
90    /// Returns the new expiration time to extend to (ignored if equal to or before the current one).
91    #[must_use]
92    pub fn get_expiration_time(&self) -> Option<OffsetDateTime> {
93        self.data().expiration_time
94    }
95
96    /// Sets the new expiration time to extend to (ignored if equal to or before the current one).
97    pub fn expiration_time(&mut self, at: OffsetDateTime) -> &mut Self {
98        self.data_mut().expiration_time = Some(at);
99        self
100    }
101
102    /// Returns the auto renew period for this smart contract.
103    #[must_use]
104    pub fn get_auto_renew_period(&self) -> Option<Duration> {
105        self.data().auto_renew_period
106    }
107
108    /// Sets the auto renew period for this smart contract.
109    pub fn auto_renew_period(&mut self, period: Duration) -> &mut Self {
110        self.data_mut().auto_renew_period = Some(period);
111        self
112    }
113
114    /// Returns the new memo for the smart contract.
115    #[must_use]
116    pub fn get_contract_memo(&self) -> Option<&str> {
117        self.data().contract_memo.as_deref()
118    }
119
120    /// Sets the new memo for the smart contract.
121    pub fn contract_memo(&mut self, memo: impl Into<String>) -> &mut Self {
122        self.data_mut().contract_memo = Some(memo.into());
123        self
124    }
125
126    /// Returns the maximum number of tokens that this contract can be automatically associated with.
127    #[must_use]
128    pub fn get_max_automatic_token_associations(&self) -> Option<i32> {
129        self.data().max_automatic_token_associations
130    }
131
132    /// Sets the maximum number of tokens that this contract can be automatically associated with.
133    pub fn max_automatic_token_associations(&mut self, max: i32) -> &mut Self {
134        self.data_mut().max_automatic_token_associations = Some(max);
135        self
136    }
137
138    /// Returns the account to be used at the contract's expiration time to extend the
139    /// life of the contract.
140    #[must_use]
141    pub fn get_auto_renew_account_id(&self) -> Option<AccountId> {
142        self.data().auto_renew_account_id
143    }
144
145    /// Sets the account to be used at the contract's expiration time to extend the
146    /// life of the contract.
147    pub fn auto_renew_account_id(&mut self, account_id: AccountId) -> &mut Self {
148        self.data_mut().auto_renew_account_id = Some(account_id);
149        self
150    }
151
152    /// Returns the ID of the account to which this contract is proxy staked.
153    #[must_use]
154    pub fn get_proxy_account_id(&self) -> Option<AccountId> {
155        self.data().proxy_account_id
156    }
157
158    /// Sets the ID of the account to which this contract is proxy staked.
159    pub fn proxy_account_id(&mut self, id: AccountId) -> &mut Self {
160        self.data_mut().proxy_account_id = Some(id);
161        self
162    }
163
164    /// Returns the ID of the account to which this contract is staking.
165    #[must_use]
166    pub fn get_staked_account_id(&self) -> Option<AccountId> {
167        self.data().staked_id.and_then(StakedId::to_account_id)
168    }
169
170    /// Sets the ID of the account to which this contract is staking.
171    /// This is mutually exclusive with `staked_node_id`.
172    pub fn staked_account_id(&mut self, id: AccountId) -> &mut Self {
173        self.data_mut().staked_id = Some(id.into());
174        self
175    }
176
177    /// Returns the ID of the node to which this contract is staking.
178    #[must_use]
179    pub fn get_staked_node_id(&self) -> Option<u64> {
180        self.data().staked_id.and_then(StakedId::to_node_id)
181    }
182
183    /// Sets the ID of the node to which this contract is staking.
184    /// This is mutually exclusive with `staked_account_id`.
185    pub fn staked_node_id(&mut self, id: u64) -> &mut Self {
186        self.data_mut().staked_id = Some(id.into());
187        self
188    }
189
190    /// Returns `true` if the contract will be updated decline staking rewards,
191    /// `false` if it will be updated to _not_,
192    /// and `None` if it will not be updated.
193    #[must_use]
194    pub fn get_decline_staking_reward(&self) -> Option<bool> {
195        self.data().decline_staking_reward
196    }
197
198    /// Sets to true, the contract declines receiving a staking reward. The default value is false.
199    pub fn decline_staking_reward(&mut self, decline: bool) -> &mut Self {
200        self.data_mut().decline_staking_reward = Some(decline);
201        self
202    }
203
204    /// Returns the hooks to be created.
205    #[must_use]
206    pub fn get_hooks_to_create(&self) -> &[HookCreationDetails] {
207        &self.data().hooks
208    }
209
210    /// Adds a hook to be created.
211    pub fn add_hook(&mut self, hook: HookCreationDetails) -> &mut Self {
212        self.data_mut().hooks.push(hook);
213        self
214    }
215
216    /// Sets the hooks to be created.
217    pub fn set_hooks(&mut self, hooks: Vec<HookCreationDetails>) -> &mut Self {
218        self.data_mut().hooks = hooks;
219        self
220    }
221
222    /// Returns the hook IDs to be deleted.
223    #[must_use]
224    pub fn get_hooks_to_delete(&self) -> &[i64] {
225        &self.data().hook_ids_to_delete
226    }
227
228    /// Adds a hook ID to be deleted.
229    pub fn delete_hook(&mut self, hook_id: i64) -> &mut Self {
230        self.data_mut().hook_ids_to_delete.push(hook_id);
231        self
232    }
233
234    /// Sets the hook IDs to be deleted.
235    pub fn delete_hooks(&mut self, hook_ids: Vec<i64>) -> &mut Self {
236        self.data_mut().hook_ids_to_delete = hook_ids;
237        self
238    }
239}
240
241impl TransactionData for ContractUpdateTransactionData {}
242
243impl TransactionExecute for ContractUpdateTransactionData {
244    fn execute(
245        &self,
246        channel: Channel,
247        request: services::Transaction,
248    ) -> BoxGrpcFuture<'_, services::TransactionResponse> {
249        Box::pin(async { SmartContractServiceClient::new(channel).update_contract(request).await })
250    }
251}
252
253impl ValidateChecksums for ContractUpdateTransactionData {
254    fn validate_checksums(&self, ledger_id: &RefLedgerId) -> Result<(), Error> {
255        self.contract_id.validate_checksums(ledger_id)?;
256        self.auto_renew_account_id.validate_checksums(ledger_id)?;
257        self.staked_id.validate_checksums(ledger_id)?;
258        self.proxy_account_id.validate_checksums(ledger_id)
259    }
260}
261
262impl ToTransactionDataProtobuf for ContractUpdateTransactionData {
263    fn to_transaction_data_protobuf(
264        &self,
265        chunk_info: &ChunkInfo,
266    ) -> services::transaction_body::Data {
267        let _ = chunk_info.assert_single_transaction();
268
269        services::transaction_body::Data::ContractUpdateInstance(self.to_protobuf())
270    }
271}
272
273impl ToSchedulableTransactionDataProtobuf for ContractUpdateTransactionData {
274    fn to_schedulable_transaction_data_protobuf(
275        &self,
276    ) -> services::schedulable_transaction_body::Data {
277        services::schedulable_transaction_body::Data::ContractUpdateInstance(self.to_protobuf())
278    }
279}
280
281impl FromProtobuf<services::ContractUpdateTransactionBody> for ContractUpdateTransactionData {
282    #[allow(deprecated)]
283    fn from_protobuf(pb: services::ContractUpdateTransactionBody) -> crate::Result<Self> {
284        use services::contract_update_transaction_body::MemoField;
285
286        Ok(Self {
287            contract_id: Option::from_protobuf(pb.contract_id)?,
288            expiration_time: pb.expiration_time.map(Into::into),
289            admin_key: Option::from_protobuf(pb.admin_key)?,
290            auto_renew_period: pb.auto_renew_period.map(Into::into),
291            contract_memo: pb.memo_field.map(|it| match it {
292                MemoField::Memo(it) | MemoField::MemoWrapper(it) => it,
293            }),
294            max_automatic_token_associations: pb.max_automatic_token_associations,
295            auto_renew_account_id: Option::from_protobuf(pb.auto_renew_account_id)?,
296            proxy_account_id: Option::from_protobuf(pb.proxy_account_id)?,
297            staked_id: Option::from_protobuf(pb.staked_id)?,
298            decline_staking_reward: pb.decline_reward,
299            hooks: pb
300                .hook_creation_details
301                .into_iter()
302                .map(HookCreationDetails::from_protobuf)
303                .collect::<Result<Vec<_>, _>>()?,
304            hook_ids_to_delete: pb.hook_ids_to_delete,
305        })
306    }
307}
308
309impl ToProtobuf for ContractUpdateTransactionData {
310    type Protobuf = services::ContractUpdateTransactionBody;
311
312    fn to_protobuf(&self) -> Self::Protobuf {
313        let contract_id = self.contract_id.to_protobuf();
314        let expiration_time = self.expiration_time.map(Into::into);
315        let admin_key = self.admin_key.to_protobuf();
316        let auto_renew_period = self.auto_renew_period.map(Into::into);
317
318        // Special handling for 0.0.0: create an empty AccountID to clear the field
319        // This matches the behavior of the JavaScript SDK which calls AccountID.create()
320        let auto_renew_account_id = self.auto_renew_account_id.map(|account_id| {
321            if account_id.shard == 0
322                && account_id.realm == 0
323                && account_id.num == 0
324                && account_id.alias.is_none()
325                && account_id.evm_address.is_none()
326            {
327                // For 0.0.0, create an empty AccountID (no account field set)
328                services::AccountId { shard_num: 0, realm_num: 0, account: None }
329            } else {
330                account_id.to_protobuf()
331            }
332        });
333
334        let staked_id = self.staked_id.map(|id| match id {
335            StakedId::NodeId(id) => {
336                services::contract_update_transaction_body::StakedId::StakedNodeId(id as i64)
337            }
338
339            StakedId::AccountId(id) => {
340                services::contract_update_transaction_body::StakedId::StakedAccountId(
341                    id.to_protobuf(),
342                )
343            }
344        });
345
346        let memo_field = self
347            .contract_memo
348            .clone()
349            .map(services::contract_update_transaction_body::MemoField::MemoWrapper);
350
351        #[allow(deprecated)]
352        services::ContractUpdateTransactionBody {
353            contract_id,
354            expiration_time,
355            admin_key,
356            proxy_account_id: self.proxy_account_id.to_protobuf(),
357            auto_renew_period,
358            max_automatic_token_associations: self
359                .max_automatic_token_associations
360                .map(|max| max as i32),
361            auto_renew_account_id,
362            decline_reward: self.decline_staking_reward,
363            staked_id,
364            file_id: None,
365            memo_field,
366            hook_creation_details: self.hooks.iter().map(|hook| hook.to_protobuf()).collect(),
367            hook_ids_to_delete: self.hook_ids_to_delete.clone(),
368        }
369    }
370}
371
372impl From<ContractUpdateTransactionData> for AnyTransactionData {
373    fn from(transaction: ContractUpdateTransactionData) -> Self {
374        Self::ContractUpdate(transaction)
375    }
376}
377
378#[cfg(test)]
379mod tests {
380
381    use expect_test::expect;
382    use hiero_sdk_proto::services;
383    use time::{
384        Duration,
385        OffsetDateTime,
386    };
387
388    use crate::contract::ContractUpdateTransactionData;
389    use crate::protobuf::{
390        FromProtobuf,
391        ToProtobuf,
392    };
393    use crate::transaction::test_helpers::{
394        check_body,
395        transaction_body,
396        unused_private_key,
397    };
398    use crate::{
399        AccountId,
400        AnyTransaction,
401        ContractId,
402        ContractUpdateTransaction,
403        EvmHook,
404        EvmHookSpec,
405        HookCreationDetails,
406        HookExtensionPoint,
407        PublicKey,
408    };
409
410    fn admin_key() -> PublicKey {
411        unused_private_key().public_key()
412    }
413
414    const CONTRACT_ID: ContractId = ContractId::new(0, 0, 5007);
415
416    const MAX_AUTOMATIC_TOKEN_ASSOCIATIONS: i32 = 101;
417    const AUTO_RENEW_PERIOD: Duration = Duration::days(1);
418    const CONTRACT_MEMO: &str = "3";
419    const EXPIRATION_TIME: OffsetDateTime =
420        match OffsetDateTime::from_unix_timestamp_nanos(4_000_000) {
421            Ok(it) => it,
422            Err(_) => panic!("Panic in `const` unwrap"),
423        };
424    const PROXY_ACCOUNT_ID: AccountId = AccountId::new(0, 0, 4);
425    const AUTO_RENEW_ACCOUNT_ID: AccountId = AccountId::new(0, 0, 30);
426    const STAKED_ACCOUNT_ID: AccountId = AccountId::new(0, 0, 3);
427    const STAKED_NODE_ID: u64 = 4;
428
429    fn make_transaction() -> ContractUpdateTransaction {
430        let mut tx = ContractUpdateTransaction::new_for_tests();
431
432        tx.contract_id(CONTRACT_ID)
433            .admin_key(admin_key())
434            .max_automatic_token_associations(MAX_AUTOMATIC_TOKEN_ASSOCIATIONS)
435            .auto_renew_period(AUTO_RENEW_PERIOD)
436            .contract_memo(CONTRACT_MEMO)
437            .expiration_time(EXPIRATION_TIME)
438            .proxy_account_id(PROXY_ACCOUNT_ID)
439            .auto_renew_account_id(AUTO_RENEW_ACCOUNT_ID)
440            .staked_account_id(STAKED_ACCOUNT_ID)
441            .freeze()
442            .unwrap();
443
444        tx
445    }
446
447    fn make_transaction2() -> ContractUpdateTransaction {
448        let mut tx = ContractUpdateTransaction::new_for_tests();
449
450        tx.contract_id(CONTRACT_ID)
451            .admin_key(admin_key())
452            .max_automatic_token_associations(MAX_AUTOMATIC_TOKEN_ASSOCIATIONS)
453            .auto_renew_period(AUTO_RENEW_PERIOD)
454            .contract_memo(CONTRACT_MEMO)
455            .expiration_time(EXPIRATION_TIME)
456            .proxy_account_id(PROXY_ACCOUNT_ID)
457            .auto_renew_account_id(AUTO_RENEW_ACCOUNT_ID)
458            .staked_node_id(STAKED_NODE_ID)
459            .freeze()
460            .unwrap();
461
462        tx
463    }
464
465    #[test]
466    fn serialize() {
467        let tx = make_transaction();
468
469        let tx = transaction_body(tx);
470
471        let tx = check_body(tx);
472
473        expect![[r#"
474            ContractUpdateInstance(
475                ContractUpdateTransactionBody {
476                    contract_id: Some(
477                        ContractId {
478                            shard_num: 0,
479                            realm_num: 0,
480                            contract: Some(
481                                ContractNum(
482                                    5007,
483                                ),
484                            ),
485                        },
486                    ),
487                    expiration_time: Some(
488                        Timestamp {
489                            seconds: 0,
490                            nanos: 4000000,
491                        },
492                    ),
493                    admin_key: Some(
494                        Key {
495                            key: Some(
496                                Ed25519(
497                                    [
498                                        224,
499                                        200,
500                                        236,
501                                        39,
502                                        88,
503                                        165,
504                                        135,
505                                        159,
506                                        250,
507                                        194,
508                                        38,
509                                        161,
510                                        60,
511                                        12,
512                                        81,
513                                        107,
514                                        121,
515                                        158,
516                                        114,
517                                        227,
518                                        81,
519                                        65,
520                                        160,
521                                        221,
522                                        130,
523                                        143,
524                                        148,
525                                        211,
526                                        121,
527                                        136,
528                                        164,
529                                        183,
530                                    ],
531                                ),
532                            ),
533                        },
534                    ),
535                    proxy_account_id: Some(
536                        AccountId {
537                            shard_num: 0,
538                            realm_num: 0,
539                            account: Some(
540                                AccountNum(
541                                    4,
542                                ),
543                            ),
544                        },
545                    ),
546                    auto_renew_period: Some(
547                        Duration {
548                            seconds: 86400,
549                        },
550                    ),
551                    file_id: None,
552                    max_automatic_token_associations: Some(
553                        101,
554                    ),
555                    auto_renew_account_id: Some(
556                        AccountId {
557                            shard_num: 0,
558                            realm_num: 0,
559                            account: Some(
560                                AccountNum(
561                                    30,
562                                ),
563                            ),
564                        },
565                    ),
566                    decline_reward: None,
567                    hook_ids_to_delete: [],
568                    hook_creation_details: [],
569                    memo_field: Some(
570                        MemoWrapper(
571                            "3",
572                        ),
573                    ),
574                    staked_id: Some(
575                        StakedAccountId(
576                            AccountId {
577                                shard_num: 0,
578                                realm_num: 0,
579                                account: Some(
580                                    AccountNum(
581                                        3,
582                                    ),
583                                ),
584                            },
585                        ),
586                    ),
587                },
588            )
589        "#]]
590        .assert_debug_eq(&tx)
591    }
592
593    #[test]
594    fn to_from_bytes() {
595        let tx = make_transaction();
596
597        let tx2 = AnyTransaction::from_bytes(&tx.to_bytes().unwrap()).unwrap();
598
599        let tx = transaction_body(tx);
600
601        let tx2 = transaction_body(tx2);
602
603        assert_eq!(tx, tx2);
604    }
605
606    #[test]
607    fn serialize2() {
608        let tx = make_transaction2();
609
610        let tx = transaction_body(tx);
611
612        let tx = check_body(tx);
613
614        expect![[r#"
615            ContractUpdateInstance(
616                ContractUpdateTransactionBody {
617                    contract_id: Some(
618                        ContractId {
619                            shard_num: 0,
620                            realm_num: 0,
621                            contract: Some(
622                                ContractNum(
623                                    5007,
624                                ),
625                            ),
626                        },
627                    ),
628                    expiration_time: Some(
629                        Timestamp {
630                            seconds: 0,
631                            nanos: 4000000,
632                        },
633                    ),
634                    admin_key: Some(
635                        Key {
636                            key: Some(
637                                Ed25519(
638                                    [
639                                        224,
640                                        200,
641                                        236,
642                                        39,
643                                        88,
644                                        165,
645                                        135,
646                                        159,
647                                        250,
648                                        194,
649                                        38,
650                                        161,
651                                        60,
652                                        12,
653                                        81,
654                                        107,
655                                        121,
656                                        158,
657                                        114,
658                                        227,
659                                        81,
660                                        65,
661                                        160,
662                                        221,
663                                        130,
664                                        143,
665                                        148,
666                                        211,
667                                        121,
668                                        136,
669                                        164,
670                                        183,
671                                    ],
672                                ),
673                            ),
674                        },
675                    ),
676                    proxy_account_id: Some(
677                        AccountId {
678                            shard_num: 0,
679                            realm_num: 0,
680                            account: Some(
681                                AccountNum(
682                                    4,
683                                ),
684                            ),
685                        },
686                    ),
687                    auto_renew_period: Some(
688                        Duration {
689                            seconds: 86400,
690                        },
691                    ),
692                    file_id: None,
693                    max_automatic_token_associations: Some(
694                        101,
695                    ),
696                    auto_renew_account_id: Some(
697                        AccountId {
698                            shard_num: 0,
699                            realm_num: 0,
700                            account: Some(
701                                AccountNum(
702                                    30,
703                                ),
704                            ),
705                        },
706                    ),
707                    decline_reward: None,
708                    hook_ids_to_delete: [],
709                    hook_creation_details: [],
710                    memo_field: Some(
711                        MemoWrapper(
712                            "3",
713                        ),
714                    ),
715                    staked_id: Some(
716                        StakedNodeId(
717                            4,
718                        ),
719                    ),
720                },
721            )
722        "#]]
723        .assert_debug_eq(&tx)
724    }
725
726    #[test]
727    fn to_from_bytes2() {
728        let tx = make_transaction2();
729
730        let tx2 = AnyTransaction::from_bytes(&tx.to_bytes().unwrap()).unwrap();
731
732        let tx = transaction_body(tx);
733
734        let tx2 = transaction_body(tx2);
735
736        assert_eq!(tx, tx2);
737    }
738
739    #[test]
740    fn from_proto_body() {
741        let hooks = vec![HookCreationDetails::new(
742            HookExtensionPoint::AccountAllowanceHook,
743            0,
744            Some(EvmHook::new(EvmHookSpec::new(Some(CONTRACT_ID)), vec![])),
745        )];
746
747        let hook_ids_to_delete = vec![1, 2, 3];
748
749        #[allow(deprecated)]
750        let tx = services::ContractUpdateTransactionBody {
751            contract_id: Some(CONTRACT_ID.to_protobuf()),
752            expiration_time: Some(EXPIRATION_TIME.to_protobuf()),
753            admin_key: Some(admin_key().to_protobuf()),
754            proxy_account_id: Some(PROXY_ACCOUNT_ID.to_protobuf()),
755            auto_renew_period: Some(AUTO_RENEW_PERIOD.to_protobuf()),
756            max_automatic_token_associations: Some(MAX_AUTOMATIC_TOKEN_ASSOCIATIONS),
757            auto_renew_account_id: Some(AUTO_RENEW_ACCOUNT_ID.to_protobuf()),
758            decline_reward: None,
759            memo_field: Some(services::contract_update_transaction_body::MemoField::MemoWrapper(
760                CONTRACT_MEMO.to_owned(),
761            )),
762            staked_id: Some(services::contract_update_transaction_body::StakedId::StakedAccountId(
763                STAKED_ACCOUNT_ID.to_protobuf(),
764            )),
765            file_id: None,
766            hook_creation_details: hooks.iter().map(|h| h.to_protobuf()).collect(),
767            hook_ids_to_delete: hook_ids_to_delete,
768        };
769
770        let tx = ContractUpdateTransactionData::from_protobuf(tx).unwrap();
771
772        assert_eq!(tx.contract_id, Some(CONTRACT_ID));
773        assert_eq!(tx.admin_key, Some(admin_key().into()));
774        assert_eq!(tx.max_automatic_token_associations, Some(MAX_AUTOMATIC_TOKEN_ASSOCIATIONS));
775        assert_eq!(tx.auto_renew_period, Some(AUTO_RENEW_PERIOD));
776        assert_eq!(tx.contract_memo, Some(CONTRACT_MEMO.to_owned()));
777        assert_eq!(tx.expiration_time, Some(EXPIRATION_TIME));
778        assert_eq!(tx.proxy_account_id, Some(PROXY_ACCOUNT_ID));
779        assert_eq!(tx.auto_renew_account_id, Some(AUTO_RENEW_ACCOUNT_ID));
780        assert_eq!(tx.staked_id, Some(crate::staked_id::StakedId::AccountId(STAKED_ACCOUNT_ID)));
781    }
782
783    mod get_set {
784        use super::*;
785
786        #[test]
787        fn contract_id() {
788            let mut tx = ContractUpdateTransaction::new();
789            tx.contract_id(CONTRACT_ID);
790
791            assert_eq!(tx.get_contract_id(), Some(CONTRACT_ID));
792        }
793
794        #[test]
795        #[should_panic]
796        fn contract_id_frozen_panics() {
797            make_transaction().contract_id(CONTRACT_ID);
798        }
799
800        #[test]
801        fn admin_key() {
802            let mut tx = ContractUpdateTransaction::new();
803            tx.admin_key(super::admin_key());
804
805            assert_eq!(tx.get_admin_key(), Some(&super::admin_key().into()));
806        }
807
808        #[test]
809        #[should_panic]
810        fn admin_key_frozen_panics() {
811            make_transaction().admin_key(super::admin_key());
812        }
813
814        #[test]
815        fn max_automatic_token_associations() {
816            let mut tx = ContractUpdateTransaction::new();
817            tx.max_automatic_token_associations(MAX_AUTOMATIC_TOKEN_ASSOCIATIONS);
818
819            assert_eq!(
820                tx.get_max_automatic_token_associations(),
821                Some(MAX_AUTOMATIC_TOKEN_ASSOCIATIONS)
822            );
823        }
824
825        #[test]
826        #[should_panic]
827        fn max_automatic_token_associations_frozen_panics() {
828            make_transaction().max_automatic_token_associations(MAX_AUTOMATIC_TOKEN_ASSOCIATIONS);
829        }
830
831        #[test]
832        fn auto_renew_period() {
833            let mut tx = ContractUpdateTransaction::new();
834            tx.auto_renew_period(AUTO_RENEW_PERIOD);
835
836            assert_eq!(tx.get_auto_renew_period(), Some(AUTO_RENEW_PERIOD));
837        }
838
839        #[test]
840        #[should_panic]
841        fn auto_renew_period_frozen_panics() {
842            make_transaction().auto_renew_period(AUTO_RENEW_PERIOD);
843        }
844
845        #[test]
846        fn contract_memo() {
847            let mut tx = ContractUpdateTransaction::new();
848            tx.contract_memo(CONTRACT_MEMO);
849
850            assert_eq!(tx.get_contract_memo(), Some(CONTRACT_MEMO));
851        }
852
853        #[test]
854        #[should_panic]
855        fn contract_memo_frozen_panics() {
856            make_transaction().contract_memo(CONTRACT_MEMO);
857        }
858
859        #[test]
860        fn expiration_time() {
861            let mut tx = ContractUpdateTransaction::new();
862            tx.expiration_time(EXPIRATION_TIME);
863
864            assert_eq!(tx.get_expiration_time(), Some(EXPIRATION_TIME));
865        }
866
867        #[test]
868        #[should_panic]
869        fn expiration_time_frozen_panics() {
870            make_transaction().expiration_time(EXPIRATION_TIME);
871        }
872
873        #[test]
874        fn proxy_account_id() {
875            let mut tx = ContractUpdateTransaction::new();
876            tx.proxy_account_id(PROXY_ACCOUNT_ID);
877
878            assert_eq!(tx.get_proxy_account_id(), Some(PROXY_ACCOUNT_ID));
879        }
880
881        #[test]
882        #[should_panic]
883        fn proxy_account_id_frozen_panics() {
884            make_transaction().proxy_account_id(PROXY_ACCOUNT_ID);
885        }
886
887        #[test]
888        fn auto_renew_account_id() {
889            let mut tx = ContractUpdateTransaction::new();
890            tx.auto_renew_account_id(AUTO_RENEW_ACCOUNT_ID);
891
892            assert_eq!(tx.get_auto_renew_account_id(), Some(AUTO_RENEW_ACCOUNT_ID));
893        }
894
895        #[test]
896        #[should_panic]
897        fn auto_renew_account_id_frozen_panics() {
898            make_transaction().auto_renew_account_id(AUTO_RENEW_ACCOUNT_ID);
899        }
900
901        #[test]
902        fn staked_account_id() {
903            let mut tx = ContractUpdateTransaction::new();
904            tx.staked_account_id(STAKED_ACCOUNT_ID);
905
906            assert_eq!(tx.get_staked_account_id(), Some(STAKED_ACCOUNT_ID));
907        }
908
909        #[test]
910        #[should_panic]
911        fn staked_account_id_frozen_panics() {
912            make_transaction().staked_account_id(STAKED_ACCOUNT_ID);
913        }
914
915        #[test]
916        fn staked_node_id() {
917            let mut tx = ContractUpdateTransaction::new();
918            tx.staked_node_id(STAKED_NODE_ID);
919
920            assert_eq!(tx.get_staked_node_id(), Some(STAKED_NODE_ID));
921        }
922
923        #[test]
924        #[should_panic]
925        fn staked_node_id_frozen_panics() {
926            make_transaction().staked_node_id(STAKED_NODE_ID);
927        }
928    }
929}