Skip to main content

iota_sdk_types/transaction/
mod.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2025 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use std::collections::BTreeSet;
6
7use super::{
8    Address, CheckpointTimestamp, ConsensusCommitDigest, EpochId, Event, GenesisObject, Identifier,
9    Intent, IntentMessage, MoveAuthenticator, ObjectId, ObjectReference, ProtocolVersion,
10    TransactionDigest, TypeTag, UserSignature, Version,
11};
12
13mod randomness_round;
14pub use randomness_round::RandomnessRound;
15
16#[cfg(feature = "serde")]
17#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
18mod serialization;
19#[cfg(feature = "serde")]
20#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
21pub(crate) use serialization::SignedTransactionWithIntentMessage;
22
23/// Transaction
24///
25/// # BCS
26///
27/// The BCS serialized form for this type is defined by the following ABNF:
28///
29/// ```text
30/// transaction = %d00 transaction-v1
31///
32/// transaction-v1 = transaction-kind address gas-payment transaction-expiration
33/// ```
34#[derive(Clone, Debug, Eq, Hash, PartialEq)]
35#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
36#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
37#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
38#[non_exhaustive]
39pub enum Transaction {
40    V1(TransactionV1),
41    // When new variants are introduced, it is important that we check version support
42    // in the validity_check function based on the protocol config.
43}
44
45impl Transaction {
46    crate::def_is_as_into_opt!(V1(TransactionV1));
47
48    /// Wraps a reference to this transaction in the transaction signing
49    /// intent, producing the message that user signatures commit to.
50    pub fn intent_message(&self) -> IntentMessage<&Self> {
51        IntentMessage::new(Intent::iota_transaction(), self)
52    }
53}
54
55impl From<TransactionV1> for Transaction {
56    fn from(v1: TransactionV1) -> Self {
57        Transaction::V1(v1)
58    }
59}
60
61impl crate::TreeDisplay for Transaction {
62    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
63        w.enum_name("Transaction");
64        match self {
65            Self::V1(v1) => v1.fmt_tree(w),
66        }
67    }
68}
69
70#[derive(Clone, Debug, Eq, Hash, PartialEq)]
71#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
72#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
73#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
74pub struct TransactionV1 {
75    pub kind: TransactionKind,
76    pub sender: Address,
77    pub gas_payment: GasPayment,
78    pub expiration: TransactionExpiration,
79}
80
81impl crate::TreeDisplay for TransactionV1 {
82    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
83        w.header("Transaction V1")?;
84        w.child("Kind", &self.kind, false)?;
85        w.leaf("Sender", &self.sender, false)?;
86        w.child("Gas Payment", &self.gas_payment, false)?;
87        w.leaf("Expiration", &self.expiration, true)
88    }
89}
90
91/// A [`SignedTransaction`] in its intent-message serialized form.
92///
93/// # BCS
94///
95/// The BCS serialized form for this type is defined by the following ABNF:
96///
97/// ```text
98/// sender-signed-transaction = %d01 intent-signed-transaction
99/// ```
100#[derive(Clone, Debug, derive_more::Deref, Eq, Hash, PartialEq)]
101#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
102#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
103pub struct SenderSignedTransaction(
104    #[cfg_attr(
105        feature = "serde",
106        serde(with = "::serde_with::As::<crate::_serde::SignedTransactionWithIntentMessage>")
107    )]
108    SignedTransaction,
109);
110
111impl SenderSignedTransaction {
112    pub fn new(transaction: Transaction, signatures: Vec<UserSignature>) -> Self {
113        Self(SignedTransaction {
114            transaction,
115            signatures,
116        })
117    }
118
119    /// The signed transaction carried by this intent message.
120    pub fn signed_transaction(&self) -> &SignedTransaction {
121        &self.0
122    }
123
124    /// Access the signed transaction carried by this intent message mutably.
125    pub fn signed_transaction_mut(&mut self) -> &mut SignedTransaction {
126        &mut self.0
127    }
128
129    /// Consume this intent message and return the signed transaction it
130    /// carries.
131    pub fn into_signed_transaction(self) -> SignedTransaction {
132        self.0
133    }
134}
135
136impl From<SignedTransaction> for SenderSignedTransaction {
137    fn from(transaction: SignedTransaction) -> Self {
138        Self(transaction)
139    }
140}
141
142impl std::fmt::Display for SenderSignedTransaction {
143    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
144        write!(f, "{}", self.0)
145    }
146}
147
148#[derive(Clone, Debug, Eq, Hash, PartialEq)]
149#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
150#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
151#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
152pub struct SignedTransaction {
153    pub transaction: Transaction,
154    pub signatures: Vec<UserSignature>,
155}
156
157impl SignedTransaction {
158    pub fn transaction(&self) -> &Transaction {
159        &self.transaction
160    }
161
162    pub fn signatures(&self) -> &[UserSignature] {
163        &self.signatures
164    }
165
166    /// Wraps a reference to the transaction in the transaction signing
167    /// intent, producing the message that the signatures commit to.
168    pub fn intent_message(&self) -> IntentMessage<&Transaction> {
169        self.transaction.intent_message()
170    }
171
172    /// Returns all [`MoveAuthenticator`] signatures.
173    pub fn move_authenticators(&self) -> Vec<&MoveAuthenticator> {
174        self.signatures
175            .iter()
176            .filter_map(|signature| signature.as_opt_move_authenticator())
177            .collect()
178    }
179
180    /// Returns the sender's [`MoveAuthenticator`], if the sender uses one.
181    pub fn sender_move_authenticator(&self) -> Option<&MoveAuthenticator> {
182        let Transaction::V1(transaction) = &self.transaction;
183
184        self.move_authenticators()
185            .into_iter()
186            .find(|authenticator| authenticator.address() == transaction.sender)
187    }
188
189    /// Returns the sponsor's [`MoveAuthenticator`], if the transaction is
190    /// sponsored and the sponsor uses one.
191    pub fn sponsor_move_authenticator(&self) -> Option<&MoveAuthenticator> {
192        let Transaction::V1(transaction) = &self.transaction;
193        let gas_owner = transaction.gas_payment.owner;
194
195        if gas_owner != transaction.sender {
196            self.move_authenticators()
197                .into_iter()
198                .find(|authenticator| authenticator.address() == gas_owner)
199        } else {
200            None
201        }
202    }
203}
204
205impl From<SenderSignedTransaction> for SignedTransaction {
206    fn from(transaction: SenderSignedTransaction) -> Self {
207        transaction.0
208    }
209}
210
211impl crate::TreeDisplay for SignedTransaction {
212    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
213        w.header("Signed Transaction")?;
214        w.child("Transaction", &self.transaction, false)?;
215        w.children("Signatures", &self.signatures, true)
216    }
217}
218
219/// A TTL for a transaction
220///
221/// # BCS
222///
223/// The BCS serialized form for this type is defined by the following ABNF:
224///
225/// ```text
226/// transaction-expiration =  %d00      ; none
227///                        =/ %d01 u64  ; epoch
228/// ```
229#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
230#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
231#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
232#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
233#[non_exhaustive]
234pub enum TransactionExpiration {
235    /// The transaction has no expiration
236    #[default]
237    None,
238    /// Validators won't sign a transaction unless the expiration Epoch
239    /// is greater than or equal to the current epoch
240    Epoch(
241        #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
242        #[cfg_attr(feature = "bcs-schema", bcs_schema(as_type = "u64"))]
243        EpochId,
244    ),
245}
246
247impl TransactionExpiration {
248    crate::def_is!(None);
249
250    crate::def_is_as_into_opt!(Epoch(EpochId));
251}
252
253impl std::fmt::Display for TransactionExpiration {
254    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
255        match self {
256            TransactionExpiration::None => write!(f, "None"),
257            TransactionExpiration::Epoch(id) => write!(f, "Epoch({id})"),
258        }
259    }
260}
261
262/// Payment information for executing a transaction
263///
264/// # BCS
265///
266/// The BCS serialized form for this type is defined by the following ABNF:
267///
268/// ```text
269/// gas-payment = (vector object-reference) ; gas coin objects
270///               address                   ; owner
271///               u64                       ; price
272///               u64                       ; budget
273/// ```
274#[derive(Clone, Debug, Eq, Hash, PartialEq)]
275#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
276#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
277#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
278pub struct GasPayment {
279    pub objects: Vec<ObjectReference>,
280    /// Owner of the gas objects, either the transaction sender or a sponsor
281    pub owner: Address,
282    /// Gas unit price to use when charging for computation
283    ///
284    /// Must be greater-than-or-equal-to the network's current RGP (reference
285    /// gas price)
286    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
287    pub price: u64,
288    /// Total budget willing to spend for the execution of a transaction
289    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
290    pub budget: u64,
291}
292
293impl crate::TreeDisplay for GasPayment {
294    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
295        w.header("Gas Payment")?;
296        w.children("Objects", &self.objects, false)?;
297        w.leaf("Owner", &self.owner, false)?;
298        w.leaf("Price", &self.price, false)?;
299        w.leaf("Budget", &self.budget, true)
300    }
301}
302
303/// Randomness update
304///
305/// # BCS
306///
307/// The BCS serialized form for this type is defined by the following ABNF:
308///
309/// ```text
310/// randomness-state-update = u64 randomness-round bytes version
311/// ```
312#[derive(Clone, derive_more::Debug, Eq, Hash, PartialEq)]
313#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
314#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
315#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
316pub struct RandomnessStateUpdate {
317    /// Epoch of the randomness state update transaction
318    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
319    pub epoch: u64,
320    /// Randomness round of the update
321    pub randomness_round: RandomnessRound,
322    /// Updated random bytes
323    #[cfg_attr(
324        feature = "serde",
325        serde(with = "crate::_serde::ReadableBase64Encoded")
326    )]
327    #[debug("{:?}", <base64ct::Base64 as base64ct::Encoding>::encode_string(random_bytes))]
328    pub random_bytes: Vec<u8>,
329    /// The initial version of the randomness object that it was shared at.
330    pub randomness_obj_initial_shared_version: Version,
331}
332
333impl crate::TreeDisplay for RandomnessStateUpdate {
334    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
335        w.header("Randomness State Update")?;
336        w.leaf("Epoch", &self.epoch, false)?;
337        w.leaf("Randomness Round", &self.randomness_round, false)?;
338        w.leaf("Random Bytes", &hex::encode(&self.random_bytes), false)?;
339        w.leaf(
340            "Randomness Obj Initial Shared Version",
341            &self.randomness_obj_initial_shared_version,
342            true,
343        )
344    }
345}
346
347/// A complete set of transaction deny rules.
348///
349/// The set-typed deny lists encode in canonical form — ascending order
350/// without duplicates — by construction, like BCS map keys. Note that
351/// decoding normalizes: a non-canonical sequence encoding (unsorted or
352/// duplicated elements) is accepted and sorted/deduplicated into the set, so
353/// re-encoding it does not reproduce the original bytes.
354///
355/// # BCS
356///
357/// The BCS serialized form for this type is defined by the following ABNF:
358///
359/// ```text
360/// deny-rule-set = (vector address)   ; denied addresses
361///                 (vector object-id) ; denied objects
362///                 (vector object-id) ; denied packages
363///                 bool               ; package publish disabled
364///                 bool               ; package upgrade disabled
365///                 bool               ; shared object disabled
366///                 bool               ; user transaction disabled
367///                 bool               ; receiving objects disabled
368///                 bool               ; move authenticator disabled
369/// ```
370#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
371#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
372#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
373#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
374pub struct DenyRuleSet {
375    /// Addresses denied as transaction sender or gas sponsor. A denied
376    /// address can still receive objects.
377    pub denied_addresses: BTreeSet<Address>,
378    /// Objects denied as transaction inputs or receiving objects.
379    pub denied_objects: BTreeSet<ObjectId>,
380    /// Packages denied as a (transitive) dependency of any command; upgrading
381    /// a denied package is denied too.
382    pub denied_packages: BTreeSet<ObjectId>,
383    /// Denies all package publishing.
384    pub package_publish_disabled: bool,
385    /// Denies all package upgrades.
386    pub package_upgrade_disabled: bool,
387    /// Denies transactions that use shared objects as inputs.
388    pub shared_object_disabled: bool,
389    /// Denies all user transactions (kill switch).
390    pub user_transaction_disabled: bool,
391    /// Denies transactions that contain receiving objects.
392    pub receiving_objects_disabled: bool,
393    /// Denies transactions signed with a Move authenticator.
394    pub move_authenticator_disabled: bool,
395}
396
397/// Update of the on-chain transaction deny rules.
398///
399/// Carries an add/remove delta for each deny list plus the absolute switch
400/// states. The added and removed sets of a list are disjoint by producer
401/// contract (validators compute them as a diff); a delta too large for one
402/// transaction arrives split across several update transactions in the same
403/// commit. Set-typed fields decode normalizing, like [`DenyRuleSet`]'s.
404///
405/// # BCS
406///
407/// The BCS serialized form for this type is defined by the following ABNF:
408///
409/// ```text
410/// transaction-deny-rules-update = u64               ; epoch
411///                                 u64               ; round
412///                                 (vector address)  ; added addresses
413///                                 (vector address)  ; removed addresses
414///                                 (vector object-id) ; added objects
415///                                 (vector object-id) ; removed objects
416///                                 (vector object-id) ; added packages
417///                                 (vector object-id) ; removed packages
418///                                 bool              ; package publish disabled
419///                                 bool              ; package upgrade disabled
420///                                 bool              ; shared object disabled
421///                                 bool              ; user transaction disabled
422///                                 bool              ; receiving objects disabled
423///                                 bool              ; move authenticator disabled
424///                                 version           ; initial shared version
425/// ```
426#[derive(Clone, Debug, Eq, Hash, PartialEq)]
427#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
428#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
429#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
430pub struct TransactionDenyRulesUpdate {
431    /// Epoch of the deny-rules update transaction
432    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
433    pub epoch: u64,
434    /// Consensus round of the update
435    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
436    pub round: u64,
437    /// Addresses added to the sender-or-sponsor deny list.
438    pub added_addresses: BTreeSet<Address>,
439    /// Addresses removed from the sender-or-sponsor deny list.
440    pub removed_addresses: BTreeSet<Address>,
441    /// Objects added to the input-or-receiving deny list.
442    pub added_objects: BTreeSet<ObjectId>,
443    /// Objects removed from the input-or-receiving deny list.
444    pub removed_objects: BTreeSet<ObjectId>,
445    /// Packages added to the dependency deny list.
446    pub added_packages: BTreeSet<ObjectId>,
447    /// Packages removed from the dependency deny list.
448    pub removed_packages: BTreeSet<ObjectId>,
449    /// Denies all package publishing.
450    pub package_publish_disabled: bool,
451    /// Denies all package upgrades.
452    pub package_upgrade_disabled: bool,
453    /// Denies transactions that use shared objects as inputs.
454    pub shared_object_disabled: bool,
455    /// Denies all user transactions (kill switch).
456    pub user_transaction_disabled: bool,
457    /// Denies transactions that contain receiving objects.
458    pub receiving_objects_disabled: bool,
459    /// Denies transactions signed with a Move authenticator.
460    pub move_authenticator_disabled: bool,
461    /// The initial version of the deny-rules object that it was shared at.
462    pub deny_rules_obj_initial_shared_version: Version,
463}
464
465impl crate::TreeDisplay for DenyRuleSet {
466    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
467        w.header("Deny Rule Set")?;
468        w.leaves("Denied Addresses", &self.denied_addresses, false)?;
469        w.leaves("Denied Objects", &self.denied_objects, false)?;
470        w.leaves("Denied Packages", &self.denied_packages, false)?;
471        w.leaf(
472            "Package Publish Disabled",
473            &self.package_publish_disabled,
474            false,
475        )?;
476        w.leaf(
477            "Package Upgrade Disabled",
478            &self.package_upgrade_disabled,
479            false,
480        )?;
481        w.leaf(
482            "Shared Object Disabled",
483            &self.shared_object_disabled,
484            false,
485        )?;
486        w.leaf(
487            "User Transaction Disabled",
488            &self.user_transaction_disabled,
489            false,
490        )?;
491        w.leaf(
492            "Receiving Objects Disabled",
493            &self.receiving_objects_disabled,
494            false,
495        )?;
496        w.leaf(
497            "Move Authenticator Disabled",
498            &self.move_authenticator_disabled,
499            true,
500        )
501    }
502}
503
504impl crate::TreeDisplay for TransactionDenyRulesUpdate {
505    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
506        w.header("Transaction Deny Rules Update")?;
507        w.leaf("Epoch", &self.epoch, false)?;
508        w.leaf("Round", &self.round, false)?;
509        w.leaves("Added Addresses", &self.added_addresses, false)?;
510        w.leaves("Removed Addresses", &self.removed_addresses, false)?;
511        w.leaves("Added Objects", &self.added_objects, false)?;
512        w.leaves("Removed Objects", &self.removed_objects, false)?;
513        w.leaves("Added Packages", &self.added_packages, false)?;
514        w.leaves("Removed Packages", &self.removed_packages, false)?;
515        w.leaf(
516            "Package Publish Disabled",
517            &self.package_publish_disabled,
518            false,
519        )?;
520        w.leaf(
521            "Package Upgrade Disabled",
522            &self.package_upgrade_disabled,
523            false,
524        )?;
525        w.leaf(
526            "Shared Object Disabled",
527            &self.shared_object_disabled,
528            false,
529        )?;
530        w.leaf(
531            "User Transaction Disabled",
532            &self.user_transaction_disabled,
533            false,
534        )?;
535        w.leaf(
536            "Receiving Objects Disabled",
537            &self.receiving_objects_disabled,
538            false,
539        )?;
540        w.leaf(
541            "Move Authenticator Disabled",
542            &self.move_authenticator_disabled,
543            false,
544        )?;
545        w.leaf(
546            "Deny Rules Obj Initial Shared Version",
547            &self.deny_rules_obj_initial_shared_version,
548            true,
549        )
550    }
551}
552
553/// Transaction type
554///
555/// # BCS
556///
557/// The BCS serialized form for this type is defined by the following ABNF:
558///
559/// ```text
560/// transaction-kind    =  %d00 programmable-transaction               ; Programmable
561///                     =/ %d01 genesis-transaction                    ; Genesis
562///                     =/ %d02 consensus-commit-prologue-v1           ; ConsensusCommitPrologueV1
563///                     =/ %d03                                        ; AuthenticatorStateUpdateV1Deprecated
564///                     =/ %d04 (vector end-of-epoch-transaction-kind) ; EndOfEpoch
565///                     =/ %d05 randomness-state-update                ; RandomnessStateUpdate
566///                     =/ %d06 transaction-deny-rules-update          ; TransactionDenyRulesUpdate
567/// ```
568#[derive(Clone, Debug, Eq, Hash, PartialEq)]
569#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
570#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
571#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
572#[non_exhaustive]
573pub enum TransactionKind {
574    /// A user transaction comprised of a list of native commands and move calls
575    Programmable(ProgrammableTransaction),
576    /// Transaction used to initialize the chain state.
577    ///
578    /// Only valid if in the genesis checkpoint (0) and if this is the very
579    /// first transaction ever executed on the chain.
580    Genesis(GenesisTransaction),
581    /// V1 consensus commit update
582    ConsensusCommitPrologueV1(ConsensusCommitPrologueV1),
583    /// Update set of valid JWKs used for zklogin - Deprecated
584    AuthenticatorStateUpdateV1Deprecated,
585    /// Set of operations to run at the end of the epoch to close out the
586    /// current epoch and start the next one.
587    EndOfEpoch(Vec<EndOfEpochTransactionKind>),
588    /// Randomness update
589    RandomnessStateUpdate(RandomnessStateUpdate),
590    /// Update of the on-chain transaction deny rules
591    TransactionDenyRulesUpdate(TransactionDenyRulesUpdate),
592}
593
594impl TransactionKind {
595    crate::def_is_as_into_opt! {
596        ConsensusCommitPrologueV1,
597        RandomnessStateUpdate,
598        TransactionDenyRulesUpdate,
599    }
600
601    crate::def_is_as_into_opt! {
602        Programmable(ProgrammableTransaction),
603        Genesis(GenesisTransaction),
604        EndOfEpoch(Vec<EndOfEpochTransactionKind>),
605    }
606
607    /// Create a [`TransactionKind::Programmable`].
608    pub fn new_programmable(transaction: ProgrammableTransaction) -> Self {
609        Self::Programmable(transaction)
610    }
611
612    /// Create a [`TransactionKind::Genesis`].
613    pub fn new_genesis(transaction: GenesisTransaction) -> Self {
614        Self::Genesis(transaction)
615    }
616
617    /// Create a [`TransactionKind::ConsensusCommitPrologueV1`].
618    pub fn new_consensus_commit_prologue_v1(transaction: ConsensusCommitPrologueV1) -> Self {
619        Self::ConsensusCommitPrologueV1(transaction)
620    }
621
622    /// Create a [`TransactionKind::EndOfEpoch`].
623    pub fn new_end_of_epoch(transaction: Vec<EndOfEpochTransactionKind>) -> Self {
624        Self::EndOfEpoch(transaction)
625    }
626
627    /// Create a [`TransactionKind::RandomnessStateUpdate`].
628    pub fn new_randomness_state_update(transaction: RandomnessStateUpdate) -> Self {
629        Self::RandomnessStateUpdate(transaction)
630    }
631
632    /// Create a [`TransactionKind::TransactionDenyRulesUpdate`].
633    pub fn new_transaction_deny_rules_update(transaction: TransactionDenyRulesUpdate) -> Self {
634        Self::TransactionDenyRulesUpdate(transaction)
635    }
636
637    /// Returns `true` if this is a system transaction.
638    pub fn is_system(&self) -> bool {
639        match self {
640            TransactionKind::Genesis(_)
641            | TransactionKind::ConsensusCommitPrologueV1(_)
642            | TransactionKind::AuthenticatorStateUpdateV1Deprecated
643            | TransactionKind::RandomnessStateUpdate(_)
644            | TransactionKind::TransactionDenyRulesUpdate(_)
645            | TransactionKind::EndOfEpoch(_) => true,
646            TransactionKind::Programmable(_) => false,
647        }
648    }
649
650    /// Returns the number of commands, or 0 if it is a system transaction.
651    pub fn num_commands(&self) -> usize {
652        match self {
653            TransactionKind::Programmable(pt) => pt.commands.len(),
654            _ => 0,
655        }
656    }
657
658    /// Returns the number of transactions, or 1 if it is a system transaction.
659    pub fn num_transactions(&self) -> usize {
660        match self {
661            TransactionKind::Programmable(pt) => pt.commands.len(),
662            _ => 1,
663        }
664    }
665}
666
667impl crate::TreeDisplay for TransactionKind {
668    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
669        w.enum_name("Transaction Kind");
670        match self {
671            Self::Programmable(pt) => pt.fmt_tree(w),
672            Self::Genesis(v) => v.fmt_tree(w),
673            Self::ConsensusCommitPrologueV1(v) => v.fmt_tree(w),
674            Self::AuthenticatorStateUpdateV1Deprecated => {
675                w.header("Authenticator State Update V1 (Deprecated)")
676            }
677            Self::EndOfEpoch(items) => {
678                w.header("End of Epoch")?;
679                w.children("Transactions", items, true)
680            }
681            Self::RandomnessStateUpdate(v) => v.fmt_tree(w),
682            Self::TransactionDenyRulesUpdate(v) => v.fmt_tree(w),
683        }
684    }
685}
686
687/// Operation run at the end of an epoch
688///
689/// # BCS
690///
691/// The BCS serialized form for this type is defined by the following ABNF:
692///
693/// ```text
694/// end-of-epoch-transaction-kind =  %d00 change-epoch     ; ChangeEpoch
695///                               =/ %d01 change-epoch-v2  ; ChangeEpochV2
696///                               =/ %d02 change-epoch-v3  ; ChangeEpochV3
697///                               =/ %d03 change-epoch-v4  ; ChangeEpochV4
698///                               =/ %d04                  ; TransactionDenyRulesCreate
699/// ```
700#[derive(Clone, Debug, Eq, Hash, PartialEq)]
701#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
702#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
703#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
704#[non_exhaustive]
705pub enum EndOfEpochTransactionKind {
706    /// End the epoch and start the next one
707    ChangeEpoch(ChangeEpoch),
708    /// End the epoch and start the next one
709    ChangeEpochV2(ChangeEpochV2),
710    /// End the epoch and start the next one
711    ChangeEpochV3(ChangeEpochV3),
712    /// End the epoch and start the next one
713    ChangeEpochV4(ChangeEpochV4),
714    /// Create and share the transaction deny rules object
715    TransactionDenyRulesCreate,
716}
717
718impl EndOfEpochTransactionKind {
719    crate::def_is_as_into_opt!(ChangeEpoch, ChangeEpochV2, ChangeEpochV3, ChangeEpochV4,);
720
721    crate::def_is!(TransactionDenyRulesCreate);
722
723    /// Creates a [`ChangeEpoch`] end-of-epoch transaction kind.
724    #[expect(clippy::too_many_arguments)]
725    pub fn new_change_epoch(
726        next_epoch: EpochId,
727        protocol_version: ProtocolVersion,
728        storage_charge: u64,
729        computation_charge: u64,
730        storage_rebate: u64,
731        non_refundable_storage_fee: u64,
732        epoch_start_timestamp_ms: u64,
733        system_packages: Vec<SystemPackage>,
734    ) -> Self {
735        Self::ChangeEpoch(ChangeEpoch {
736            epoch: next_epoch,
737            protocol_version,
738            storage_charge,
739            computation_charge,
740            storage_rebate,
741            non_refundable_storage_fee,
742            epoch_start_timestamp_ms,
743            system_packages,
744        })
745    }
746
747    /// Creates a [`ChangeEpochV2`] end-of-epoch transaction kind.
748    #[expect(clippy::too_many_arguments)]
749    pub fn new_change_epoch_v2(
750        next_epoch: EpochId,
751        protocol_version: ProtocolVersion,
752        storage_charge: u64,
753        computation_charge: u64,
754        computation_charge_burned: u64,
755        storage_rebate: u64,
756        non_refundable_storage_fee: u64,
757        epoch_start_timestamp_ms: u64,
758        system_packages: Vec<SystemPackage>,
759    ) -> Self {
760        Self::ChangeEpochV2(ChangeEpochV2 {
761            epoch: next_epoch,
762            protocol_version,
763            storage_charge,
764            computation_charge,
765            computation_charge_burned,
766            storage_rebate,
767            non_refundable_storage_fee,
768            epoch_start_timestamp_ms,
769            system_packages,
770        })
771    }
772
773    /// Creates a [`ChangeEpochV3`] end-of-epoch transaction kind.
774    #[expect(clippy::too_many_arguments)]
775    pub fn new_change_epoch_v3(
776        next_epoch: EpochId,
777        protocol_version: ProtocolVersion,
778        storage_charge: u64,
779        computation_charge: u64,
780        computation_charge_burned: u64,
781        storage_rebate: u64,
782        non_refundable_storage_fee: u64,
783        epoch_start_timestamp_ms: u64,
784        system_packages: Vec<SystemPackage>,
785        eligible_active_validators: Vec<u64>,
786    ) -> Self {
787        Self::ChangeEpochV3(ChangeEpochV3 {
788            epoch: next_epoch,
789            protocol_version,
790            storage_charge,
791            computation_charge,
792            computation_charge_burned,
793            storage_rebate,
794            non_refundable_storage_fee,
795            epoch_start_timestamp_ms,
796            system_packages,
797            eligible_active_validators,
798        })
799    }
800
801    /// Creates a [`ChangeEpochV4`] end-of-epoch transaction kind.
802    #[expect(clippy::too_many_arguments)]
803    pub fn new_change_epoch_v4(
804        next_epoch: EpochId,
805        protocol_version: ProtocolVersion,
806        storage_charge: u64,
807        computation_charge: u64,
808        computation_charge_burned: u64,
809        storage_rebate: u64,
810        non_refundable_storage_fee: u64,
811        epoch_start_timestamp_ms: u64,
812        system_packages: Vec<SystemPackage>,
813        eligible_active_validators: Vec<u64>,
814        scores: Vec<u64>,
815        adjust_rewards_by_score: bool,
816    ) -> Self {
817        Self::ChangeEpochV4(ChangeEpochV4 {
818            epoch: next_epoch,
819            protocol_version,
820            storage_charge,
821            computation_charge,
822            computation_charge_burned,
823            storage_rebate,
824            non_refundable_storage_fee,
825            epoch_start_timestamp_ms,
826            system_packages,
827            eligible_active_validators,
828            scores,
829            adjust_rewards_by_score,
830        })
831    }
832
833    /// Creates a [`Self::TransactionDenyRulesCreate`] end-of-epoch transaction
834    /// kind.
835    pub fn new_transaction_deny_rules_create() -> Self {
836        Self::TransactionDenyRulesCreate
837    }
838
839    /// Returns an iterator over the shared input objects required by this
840    /// transaction kind.
841    pub fn shared_input_objects(&self) -> impl Iterator<Item = SharedObjectReference> + '_ {
842        match self {
843            Self::ChangeEpoch(_)
844            | Self::ChangeEpochV2(_)
845            | Self::ChangeEpochV3(_)
846            | Self::ChangeEpochV4(_) => {
847                vec![SharedObjectReference::IOTA_SYSTEM_STATE_OBJ_MUTABLE].into_iter()
848            }
849            // The deny-rules object is created by this transaction, so there
850            // is no shared input to reference yet.
851            Self::TransactionDenyRulesCreate => vec![].into_iter(),
852        }
853    }
854}
855
856impl crate::TreeDisplay for EndOfEpochTransactionKind {
857    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
858        w.enum_name("End of Epoch Transaction Kind");
859        match self {
860            Self::ChangeEpoch(v) => v.fmt_tree(w),
861            Self::ChangeEpochV2(v) => v.fmt_tree(w),
862            Self::ChangeEpochV3(v) => v.fmt_tree(w),
863            Self::ChangeEpochV4(v) => v.fmt_tree(w),
864            Self::TransactionDenyRulesCreate => w.header("Transaction Deny Rules Create"),
865        }
866    }
867}
868
869#[derive(Clone, Debug, Eq, Hash, PartialEq)]
870#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
871#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
872#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
873#[non_exhaustive]
874pub enum ConsensusDeterminedVersionAssignments {
875    /// Canceled transaction version assignment.
876    CanceledTransactions {
877        #[cfg_attr(feature = "proptest", any(proptest::collection::size_range(0..=2).lift()))]
878        canceled_transactions: Vec<CanceledTransaction>,
879    },
880}
881
882impl ConsensusDeterminedVersionAssignments {
883    crate::def_is!(CanceledTransactions);
884
885    pub fn as_canceled_transactions(&self) -> &[CanceledTransaction] {
886        let Self::CanceledTransactions {
887            canceled_transactions,
888        } = self;
889        canceled_transactions
890    }
891}
892
893impl crate::TreeDisplay for ConsensusDeterminedVersionAssignments {
894    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
895        w.enum_name("Consensus Determined Version Assignments");
896        match self {
897            ConsensusDeterminedVersionAssignments::CanceledTransactions {
898                canceled_transactions,
899            } => {
900                w.header("Canceled Transactions")?;
901                w.children("Transactions", canceled_transactions, true)
902            }
903        }
904    }
905}
906
907/// A transaction that was canceled
908///
909/// # BCS
910///
911/// The BCS serialized form for this type is defined by the following ABNF:
912///
913/// ```text
914/// canceled-transaction = transaction-digest (vector version-assignment)
915/// ```
916#[derive(Clone, Debug, Eq, Hash, PartialEq)]
917#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
918#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
919#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
920pub struct CanceledTransaction {
921    pub digest: TransactionDigest,
922    #[cfg_attr(feature = "proptest", any(proptest::collection::size_range(0..=2).lift()))]
923    pub version_assignments: Vec<VersionAssignment>,
924}
925
926impl crate::TreeDisplay for CanceledTransaction {
927    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
928        w.header("Canceled Transaction")?;
929        w.leaf("Digest", &self.digest, false)?;
930        w.children("Version Assignments", &self.version_assignments, true)
931    }
932}
933
934/// Object version assignment from consensus
935///
936/// # BCS
937///
938/// The BCS serialized form for this type is defined by the
939/// following ABNF:
940///
941/// ```text
942/// version-assignment = object-id u64
943/// ```
944#[derive(Clone, Debug, Eq, Hash, PartialEq)]
945#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
946#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
947#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
948pub struct VersionAssignment {
949    pub object_id: ObjectId,
950    pub version: Version,
951}
952
953impl VersionAssignment {
954    /// Creates a [`VersionAssignment`].
955    pub fn new(object_id: ObjectId, version: Version) -> Self {
956        Self { object_id, version }
957    }
958}
959
960impl crate::TreeDisplay for VersionAssignment {
961    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
962        w.header("Version Assignment")?;
963        w.leaf("Object ID", &self.object_id, false)?;
964        w.leaf("Version", &self.version, true)
965    }
966}
967
968/// V1 of the consensus commit prologue system transaction
969///
970/// # BCS
971///
972/// The BCS serialized form for this type is defined by the following ABNF:
973///
974/// ```text
975/// consensus-commit-prologue-v1 = u64 u64 (option u64) u64 consensus-commit-digest
976///                                consensus-determined-version-assignments
977/// ```
978#[derive(Clone, Debug, Eq, Hash, PartialEq)]
979#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
980#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
981#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
982pub struct ConsensusCommitPrologueV1 {
983    /// Epoch of the commit prologue transaction
984    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
985    pub epoch: u64,
986    /// Consensus round of the commit
987    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
988    pub round: u64,
989    /// The sub DAG index of the consensus commit. This field will be populated
990    /// if there are multiple consensus commits per round.
991    #[cfg_attr(
992        feature = "serde",
993        serde(with = "crate::_serde::OptionReadableDisplay")
994    )]
995    pub sub_dag_index: Option<u64>,
996    /// Unix timestamp from consensus
997    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
998    #[cfg_attr(feature = "bcs-schema", bcs_schema(as_type = "u64"))]
999    pub commit_timestamp_ms: CheckpointTimestamp,
1000    /// Digest of consensus output
1001    pub consensus_commit_digest: ConsensusCommitDigest,
1002    /// Stores consensus handler determined shared object version assignments.
1003    pub consensus_determined_version_assignments: ConsensusDeterminedVersionAssignments,
1004}
1005
1006impl crate::TreeDisplay for ConsensusCommitPrologueV1 {
1007    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
1008        w.header("Consensus Commit Prologue V1")?;
1009        w.leaf("Epoch", &self.epoch, false)?;
1010        w.leaf("Round", &self.round, false)?;
1011        w.option_leaf("Sub DAG Index", &self.sub_dag_index, false)?;
1012        w.leaf("Commit Timestamp Ms", &self.commit_timestamp_ms, false)?;
1013        w.leaf(
1014            "Consensus Commit Digest",
1015            &self.consensus_commit_digest,
1016            false,
1017        )?;
1018        w.child(
1019            "Consensus Determined Version Assignments",
1020            &self.consensus_determined_version_assignments,
1021            true,
1022        )
1023    }
1024}
1025
1026/// System transaction used to change the epoch
1027///
1028/// # BCS
1029///
1030/// The BCS serialized form for this type is defined by the following ABNF:
1031///
1032/// ```text
1033/// change-epoch = u64  ; next epoch
1034///                u64  ; protocol version
1035///                u64  ; storage charge
1036///                u64  ; computation charge
1037///                u64  ; storage rebate
1038///                u64  ; non-refundable storage fee
1039///                u64  ; epoch start timestamp
1040///                (vector system-package)
1041/// ```
1042#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1043#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
1044#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
1045#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
1046pub struct ChangeEpoch {
1047    /// The next (to become) epoch ID.
1048    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1049    #[cfg_attr(feature = "bcs-schema", bcs_schema(as_type = "u64"))]
1050    pub epoch: EpochId,
1051    /// The protocol version in effect in the new epoch.
1052    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1053    #[cfg_attr(feature = "bcs-schema", bcs_schema(as_type = "u64"))]
1054    pub protocol_version: ProtocolVersion,
1055    /// The total amount of gas charged for storage during the epoch.
1056    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1057    pub storage_charge: u64,
1058    /// The total amount of gas charged for computation during the epoch.
1059    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1060    pub computation_charge: u64,
1061    /// The amount of storage rebate refunded to the txn senders.
1062    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1063    pub storage_rebate: u64,
1064    /// The non-refundable storage fee.
1065    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1066    pub non_refundable_storage_fee: u64,
1067    /// Unix timestamp when epoch started
1068    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1069    pub epoch_start_timestamp_ms: u64,
1070    /// System packages (specifically framework and move stdlib) that are
1071    /// written before the new epoch starts. This tracks framework upgrades
1072    /// on chain. When executing the ChangeEpoch txn, the validator must
1073    /// write out the modules below.  Modules are provided with the version they
1074    /// will be upgraded to, their modules in serialized form (which include
1075    /// their package ID), and a list of their transitive dependencies.
1076    #[cfg_attr(feature = "proptest", any(proptest::collection::size_range(0..=2).lift()))]
1077    pub system_packages: Vec<SystemPackage>,
1078}
1079
1080impl crate::TreeDisplay for ChangeEpoch {
1081    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
1082        w.header("Change Epoch")?;
1083        w.leaf("Epoch", &self.epoch, false)?;
1084        w.leaf("Protocol Version", &self.protocol_version, false)?;
1085        w.leaf("Storage Charge", &self.storage_charge, false)?;
1086        w.leaf("Computation Charge", &self.computation_charge, false)?;
1087        w.leaf("Storage Rebate", &self.storage_rebate, false)?;
1088        w.leaf(
1089            "Non-Refundable Storage Fee",
1090            &self.non_refundable_storage_fee,
1091            false,
1092        )?;
1093        w.leaf(
1094            "Epoch Start Timestamp Ms",
1095            &self.epoch_start_timestamp_ms,
1096            false,
1097        )?;
1098        w.children("System Packages", &self.system_packages, true)
1099    }
1100}
1101
1102/// System transaction used to change the epoch
1103///
1104/// # BCS
1105///
1106/// The BCS serialized form for this type is defined by the following ABNF:
1107///
1108/// ```text
1109/// change-epoch-v2 = u64  ; next epoch
1110///                   u64  ; protocol version
1111///                   u64  ; storage charge
1112///                   u64  ; computation charge
1113///                   u64  ; computation charge burned
1114///                   u64  ; storage rebate
1115///                   u64  ; non-refundable storage fee
1116///                   u64  ; epoch start timestamp
1117///                   (vector system-package)
1118/// ```
1119#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1120#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
1121#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
1122#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
1123pub struct ChangeEpochV2 {
1124    /// The next (to become) epoch ID.
1125    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1126    #[cfg_attr(feature = "bcs-schema", bcs_schema(as_type = "u64"))]
1127    pub epoch: EpochId,
1128    /// The protocol version in effect in the new epoch.
1129    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1130    #[cfg_attr(feature = "bcs-schema", bcs_schema(as_type = "u64"))]
1131    pub protocol_version: ProtocolVersion,
1132    /// The total amount of gas charged for storage during the epoch.
1133    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1134    pub storage_charge: u64,
1135    /// The total amount of gas charged for computation during the epoch.
1136    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1137    pub computation_charge: u64,
1138    /// The total amount of gas burned for computation during the epoch.
1139    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1140    pub computation_charge_burned: u64,
1141    /// The amount of storage rebate refunded to the txn senders.
1142    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1143    pub storage_rebate: u64,
1144    /// The non-refundable storage fee.
1145    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1146    pub non_refundable_storage_fee: u64,
1147    /// Unix timestamp when epoch started
1148    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1149    pub epoch_start_timestamp_ms: u64,
1150    /// System packages (specifically framework and move stdlib) that are
1151    /// written before the new epoch starts. This tracks framework upgrades
1152    /// on chain. When executing the ChangeEpoch txn, the validator must
1153    /// write out the modules below.  Modules are provided with the version they
1154    /// will be upgraded to, their modules in serialized form (which include
1155    /// their package ID), and a list of their transitive dependencies.
1156    #[cfg_attr(feature = "proptest", any(proptest::collection::size_range(0..=2).lift()))]
1157    pub system_packages: Vec<SystemPackage>,
1158}
1159
1160impl crate::TreeDisplay for ChangeEpochV2 {
1161    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
1162        w.header("Change Epoch V2")?;
1163        w.leaf("Epoch", &self.epoch, false)?;
1164        w.leaf("Protocol Version", &self.protocol_version, false)?;
1165        w.leaf("Storage Charge", &self.storage_charge, false)?;
1166        w.leaf("Computation Charge", &self.computation_charge, false)?;
1167        w.leaf(
1168            "Computation Charge Burned",
1169            &self.computation_charge_burned,
1170            false,
1171        )?;
1172        w.leaf("Storage Rebate", &self.storage_rebate, false)?;
1173        w.leaf(
1174            "Non-Refundable Storage Fee",
1175            &self.non_refundable_storage_fee,
1176            false,
1177        )?;
1178        w.leaf(
1179            "Epoch Start Timestamp Ms",
1180            &self.epoch_start_timestamp_ms,
1181            false,
1182        )?;
1183        w.children("System Packages", &self.system_packages, true)
1184    }
1185}
1186
1187#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1188#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
1189#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
1190#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
1191pub struct ChangeEpochV3 {
1192    /// The next (to become) epoch ID.
1193    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1194    #[cfg_attr(feature = "bcs-schema", bcs_schema(as_type = "u64"))]
1195    pub epoch: EpochId,
1196    /// The protocol version in effect in the new epoch.
1197    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1198    #[cfg_attr(feature = "bcs-schema", bcs_schema(as_type = "u64"))]
1199    pub protocol_version: ProtocolVersion,
1200    /// The total amount of gas charged for storage during the epoch.
1201    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1202    pub storage_charge: u64,
1203    /// The total amount of gas charged for computation during the epoch.
1204    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1205    pub computation_charge: u64,
1206    /// The total amount of gas burned for computation during the epoch.
1207    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1208    pub computation_charge_burned: u64,
1209    /// The amount of storage rebate refunded to the txn senders.
1210    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1211    pub storage_rebate: u64,
1212    /// The non-refundable storage fee.
1213    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1214    pub non_refundable_storage_fee: u64,
1215    /// Unix timestamp when epoch started
1216    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1217    pub epoch_start_timestamp_ms: u64,
1218    /// System packages (specifically framework and move stdlib) that are
1219    /// written before the new epoch starts. This tracks framework upgrades
1220    /// on chain. When executing the ChangeEpoch txn, the validator must
1221    /// write out the modules below.  Modules are provided with the version they
1222    /// will be upgraded to, their modules in serialized form (which include
1223    /// their package ID), and a list of their transitive dependencies.
1224    #[cfg_attr(feature = "proptest", any(proptest::collection::size_range(0..=2).lift()))]
1225    pub system_packages: Vec<SystemPackage>,
1226    /// Vector of active validator indices eligible to take part in committee
1227    /// selection because they support the new, target protocol version.
1228    pub eligible_active_validators: Vec<u64>,
1229}
1230
1231impl crate::TreeDisplay for ChangeEpochV3 {
1232    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
1233        w.header("Change Epoch V3")?;
1234        w.leaf("Epoch", &self.epoch, false)?;
1235        w.leaf("Protocol Version", &self.protocol_version, false)?;
1236        w.leaf("Storage Charge", &self.storage_charge, false)?;
1237        w.leaf("Computation Charge", &self.computation_charge, false)?;
1238        w.leaf(
1239            "Computation Charge Burned",
1240            &self.computation_charge_burned,
1241            false,
1242        )?;
1243        w.leaf("Storage Rebate", &self.storage_rebate, false)?;
1244        w.leaf(
1245            "Non-Refundable Storage Fee",
1246            &self.non_refundable_storage_fee,
1247            false,
1248        )?;
1249        w.leaf(
1250            "Epoch Start Timestamp Ms",
1251            &self.epoch_start_timestamp_ms,
1252            false,
1253        )?;
1254        w.children("System Packages", &self.system_packages, false)?;
1255        w.leaves(
1256            "Eligible Active Validators",
1257            &self.eligible_active_validators,
1258            true,
1259        )
1260    }
1261}
1262
1263#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1264#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
1265#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
1266#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
1267pub struct ChangeEpochV4 {
1268    /// The next (to become) epoch ID.
1269    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1270    #[cfg_attr(feature = "bcs-schema", bcs_schema(as_type = "u64"))]
1271    pub epoch: EpochId,
1272    /// The protocol version in effect in the new epoch.
1273    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1274    #[cfg_attr(feature = "bcs-schema", bcs_schema(as_type = "u64"))]
1275    pub protocol_version: ProtocolVersion,
1276    /// The total amount of gas charged for storage during the epoch.
1277    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1278    pub storage_charge: u64,
1279    /// The total amount of gas charged for computation during the epoch.
1280    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1281    pub computation_charge: u64,
1282    /// The total amount of gas burned for computation during the epoch.
1283    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1284    pub computation_charge_burned: u64,
1285    /// The amount of storage rebate refunded to the txn senders.
1286    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1287    pub storage_rebate: u64,
1288    /// The non-refundable storage fee.
1289    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1290    pub non_refundable_storage_fee: u64,
1291    /// Unix timestamp when epoch started
1292    #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
1293    pub epoch_start_timestamp_ms: u64,
1294    /// System packages (specifically framework and move stdlib) that are
1295    /// written before the new epoch starts. This tracks framework upgrades
1296    /// on chain. When executing the ChangeEpoch txn, the validator must
1297    /// write out the modules below.  Modules are provided with the version they
1298    /// will be upgraded to, their modules in serialized form (which include
1299    /// their package ID), and a list of their transitive dependencies.
1300    #[cfg_attr(feature = "proptest", any(proptest::collection::size_range(0..=2).lift()))]
1301    pub system_packages: Vec<SystemPackage>,
1302    /// Vector of active validator indices eligible to take part in committee
1303    /// selection because they support the new, target protocol version.
1304    pub eligible_active_validators: Vec<u64>,
1305    /// Vector of scores relative to the past epoch performance of each
1306    /// validator, ordered by the past epoch's validator index.
1307    pub scores: Vec<u64>,
1308    /// Whether to adjust validator rewards based on score.
1309    pub adjust_rewards_by_score: bool,
1310}
1311
1312impl crate::TreeDisplay for ChangeEpochV4 {
1313    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
1314        w.header("Change Epoch V4")?;
1315        w.leaf("Epoch", &self.epoch, false)?;
1316        w.leaf("Protocol Version", &self.protocol_version, false)?;
1317        w.leaf("Storage Charge", &self.storage_charge, false)?;
1318        w.leaf("Computation Charge", &self.computation_charge, false)?;
1319        w.leaf(
1320            "Computation Charge Burned",
1321            &self.computation_charge_burned,
1322            false,
1323        )?;
1324        w.leaf("Storage Rebate", &self.storage_rebate, false)?;
1325        w.leaf(
1326            "Non-Refundable Storage Fee",
1327            &self.non_refundable_storage_fee,
1328            false,
1329        )?;
1330        w.leaf(
1331            "Epoch Start Timestamp Ms",
1332            &self.epoch_start_timestamp_ms,
1333            false,
1334        )?;
1335        w.children("System Packages", &self.system_packages, false)?;
1336        w.leaves(
1337            "Eligible Active Validators",
1338            &self.eligible_active_validators,
1339            false,
1340        )?;
1341        w.leaves("Scores", &self.scores, false)?;
1342        w.leaf(
1343            "Adjust Rewards By Score",
1344            &self.adjust_rewards_by_score,
1345            true,
1346        )
1347    }
1348}
1349
1350#[derive(Clone, derive_more::Debug, Eq, Hash, PartialEq)]
1351#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
1352#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
1353#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
1354pub struct SystemPackage {
1355    pub version: Version,
1356    #[cfg_attr(
1357        feature = "serde",
1358        serde(
1359            with = "::serde_with::As::<Vec<::serde_with::IfIsHumanReadable<crate::_serde::Base64Encoded, ::serde_with::Bytes>>>"
1360        )
1361    )]
1362    #[cfg_attr(feature = "proptest", any(proptest::collection::size_range(0..=2).lift()))]
1363    #[debug(
1364        "{:?}",
1365        modules
1366            .iter()
1367            .map(|m| <base64ct::Base64 as base64ct::Encoding>::encode_string(m))
1368            .collect::<Vec<_>>()
1369    )]
1370    pub modules: Vec<Vec<u8>>,
1371    pub dependencies: Vec<ObjectId>,
1372}
1373
1374impl crate::TreeDisplay for SystemPackage {
1375    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
1376        w.header("System Package")?;
1377        w.leaf("Version", &self.version, false)?;
1378        w.base64_leaves("Modules", &self.modules, false)?;
1379        w.leaves("Dependencies", &self.dependencies, true)
1380    }
1381}
1382
1383/// The genesis transaction
1384///
1385/// # BCS
1386///
1387/// The BCS serialized form for this type is defined by the following ABNF:
1388///
1389/// ```text
1390/// genesis-transaction = (vector genesis-object)
1391/// ```
1392#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1393#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
1394#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
1395#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
1396pub struct GenesisTransaction {
1397    #[cfg_attr(feature = "proptest", any(proptest::collection::size_range(0..=2).lift()))]
1398    pub objects: Vec<GenesisObject>,
1399    #[cfg_attr(feature = "proptest", any(proptest::collection::size_range(0..=10).lift()))]
1400    pub events: Vec<Event>,
1401}
1402
1403impl crate::TreeDisplay for GenesisTransaction {
1404    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
1405        w.header("Genesis Transaction")?;
1406        w.children("Objects", &self.objects, false)?;
1407        w.children("Events", &self.events, true)
1408    }
1409}
1410
1411/// A user transaction
1412///
1413/// Contains a series of native commands and move calls where the results of one
1414/// command can be used in future commands.
1415///
1416/// # BCS
1417///
1418/// The BCS serialized form for this type is defined by the following ABNF:
1419///
1420/// ```text
1421/// ptb = (vector input) (vector command)
1422/// ```
1423#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1424#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
1425#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
1426#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
1427pub struct ProgrammableTransaction {
1428    /// Input objects or primitive values
1429    #[cfg_attr(feature = "proptest", any(proptest::collection::size_range(0..=10).lift()))]
1430    pub inputs: Vec<Input>,
1431    /// The commands to be executed sequentially. A failure in any command will
1432    /// result in the failure of the entire transaction.
1433    #[cfg_attr(feature = "proptest", any(proptest::collection::size_range(0..=10).lift()))]
1434    pub commands: Vec<Command>,
1435}
1436
1437impl crate::TreeDisplay for ProgrammableTransaction {
1438    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
1439        w.header("Programmable Transaction")?;
1440        w.children("Inputs", &self.inputs, false)?;
1441        w.children("Commands", &self.commands, true)
1442    }
1443}
1444/// An input to a user transaction
1445///
1446/// # BCS
1447///
1448/// The BCS serialized form for this type is defined by the following ABNF:
1449///
1450/// ```text
1451/// input = call-arg
1452///
1453/// call-arg   =  %d00 bytes        ; Pure
1454///            =/ %d01 object-arg   ; Object
1455///
1456/// object-arg =  %d00 object-reference     ; ImmutableOrOwned
1457///            =/ %d01 object-id u64 bool   ; Shared
1458///            =/ %d02 object-reference     ; Receiving
1459/// ```
1460#[derive(Clone, derive_more::Debug, Eq, Hash, PartialEq)]
1461#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
1462#[cfg_attr(
1463    feature = "bcs-schema",
1464    derive(iota_bcs_schema::BcsSchema),
1465    bcs_schema(definition = "call-arg")
1466)]
1467#[non_exhaustive]
1468pub enum Input {
1469    /// A move value serialized as BCS.
1470    ///
1471    /// For normal operations this is required to be a move primitive type and
1472    /// not contain structs or objects.
1473    Pure(#[debug("{:?}", <base64ct::Base64 as base64ct::Encoding>::encode_string(_0))] Vec<u8>),
1474    /// A move object that is either immutable or address owned
1475    ImmutableOrOwned(ObjectReference),
1476    /// A move object whose owner is "Shared"
1477    Shared(SharedObjectReference),
1478    /// A move object that is attempted to be received in this transaction.
1479    // TODO add discussion around what receiving is
1480    Receiving(ObjectReference),
1481}
1482
1483impl Input {
1484    /// Shared `Input` for the IOTA system state object.
1485    pub const IOTA_SYSTEM_MUTABLE: Self = Self::Shared(SharedObjectReference {
1486        object_id: ObjectId::SYSTEM_STATE,
1487        initial_shared_version: Version::INITIAL_SHARED_VERSION,
1488        mutable: true,
1489    });
1490
1491    /// Shared `Input` for the clock object.
1492    pub const CLOCK_IMMUTABLE: Self = Self::Shared(SharedObjectReference {
1493        object_id: ObjectId::CLOCK,
1494        initial_shared_version: Version::INITIAL_SHARED_VERSION,
1495        mutable: false,
1496    });
1497
1498    /// Shared `Input` for the clock object.
1499    pub const CLOCK_MUTABLE: Self = Self::Shared(SharedObjectReference {
1500        object_id: ObjectId::CLOCK,
1501        initial_shared_version: Version::INITIAL_SHARED_VERSION,
1502        mutable: true,
1503    });
1504
1505    crate::def_is_as_into_opt!(
1506        Pure(Vec<u8>),
1507        ImmutableOrOwned(ObjectReference),
1508        Shared(SharedObjectReference),
1509        Receiving(ObjectReference)
1510    );
1511
1512    /// Create a `Pure` input from a BCS-serializable value.
1513    #[cfg(feature = "serde")]
1514    #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
1515    pub fn pure<T: serde::Serialize>(value: &T) -> Self {
1516        Self::Pure(bcs::to_bytes(value).expect("value should be serializable"))
1517    }
1518
1519    /// Returns the object id referenced by this input, if any.
1520    ///
1521    /// Returns `None` for `Pure` inputs.
1522    pub fn opt_object_id(&self) -> Option<&ObjectId> {
1523        match self {
1524            Self::Pure { .. } => None,
1525            Self::ImmutableOrOwned(obj_ref) | Self::Receiving(obj_ref) => Some(&obj_ref.object_id),
1526            Self::Shared(SharedObjectReference { object_id, .. }) => Some(object_id),
1527        }
1528    }
1529
1530    /// Returns `true` if this input references a mutable shared object.
1531    pub fn is_mutable_shared(&self) -> bool {
1532        matches!(
1533            self,
1534            Self::Shared(SharedObjectReference { mutable: true, .. })
1535        )
1536    }
1537
1538    /// Returns the [`ObjectReference`] if this is an `ImmutableOrOwned` or
1539    /// `Receiving` input.
1540    pub fn as_opt_object_ref(&self) -> Option<&ObjectReference> {
1541        match self {
1542            Self::ImmutableOrOwned(obj_ref) | Self::Receiving(obj_ref) => Some(obj_ref),
1543            _ => None,
1544        }
1545    }
1546}
1547
1548impl crate::TreeDisplay for Input {
1549    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
1550        w.enum_name("Input");
1551        match self {
1552            Self::Pure(value) => {
1553                w.header("Pure")?;
1554                w.leaf("Value", &hex::encode(value), true)
1555            }
1556            Self::ImmutableOrOwned(obj_ref) => {
1557                w.header("Immutable Or Owned")?;
1558                w.inline_child(obj_ref)
1559            }
1560            Self::Shared(shared) => {
1561                w.header("Shared")?;
1562                w.inline_child(shared)
1563            }
1564            Self::Receiving(obj_ref) => {
1565                w.header("Receiving")?;
1566                w.inline_child(obj_ref)
1567            }
1568        }
1569    }
1570}
1571
1572/// A shared object input to a programmable transaction
1573#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1574#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
1575#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
1576pub struct SharedObjectReference {
1577    pub object_id: ObjectId,
1578    pub initial_shared_version: Version,
1579    /// Controls whether the caller asks for a mutable reference to the
1580    /// shared object.
1581    pub mutable: bool,
1582}
1583
1584impl SharedObjectReference {
1585    pub const IOTA_SYSTEM_STATE_OBJ_MUTABLE: Self = Self {
1586        object_id: ObjectId::SYSTEM_STATE,
1587        initial_shared_version: Version::INITIAL_SHARED_VERSION,
1588        mutable: true,
1589    };
1590
1591    /// Creates a new shared object reference from the object's id, initial
1592    /// shared version, and mutability.
1593    pub const fn new(object_id: ObjectId, initial_shared_version: Version, mutable: bool) -> Self {
1594        Self {
1595            object_id,
1596            initial_shared_version,
1597            mutable,
1598        }
1599    }
1600}
1601
1602impl crate::TreeDisplay for SharedObjectReference {
1603    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
1604        w.header("Shared Object Reference")?;
1605        w.leaf("Object ID", &self.object_id, false)?;
1606        w.leaf(
1607            "Initial Shared Version",
1608            &self.initial_shared_version,
1609            false,
1610        )?;
1611        w.leaf("Mutable", &self.mutable, true)
1612    }
1613}
1614
1615/// A single command in a programmable transaction.
1616///
1617/// # BCS
1618///
1619/// The BCS serialized form for this type is defined by the following ABNF:
1620///
1621/// ```text
1622/// command =  command-move-call
1623///         =/ command-transfer-objects
1624///         =/ command-split-coins
1625///         =/ command-merge-coins
1626///         =/ command-publish
1627///         =/ command-make-move-vector
1628///         =/ command-upgrade
1629///
1630/// command-move-call           = %d00 move-call
1631/// command-transfer-objects    = %d01 transfer-objects
1632/// command-split-coins         = %d02 split-coins
1633/// command-merge-coins         = %d03 merge-coins
1634/// command-publish             = %d04 publish
1635/// command-make-move-vector    = %d05 make-move-vector
1636/// command-upgrade             = %d06 upgrade
1637/// ```
1638#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1639#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
1640#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
1641#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
1642#[non_exhaustive]
1643pub enum Command {
1644    /// A call to either an entry or a public Move function
1645    MoveCall(MoveCall),
1646    /// `(Vec<forall T:key+store. T>, address)`
1647    /// It sends n-objects to the specified address. These objects must have
1648    /// store (public transfer) and either the previous owner must be an
1649    /// address or the object must be newly created.
1650    TransferObjects(TransferObjects),
1651    /// `(&mut Coin<T>, Vec<u64>)` -> `Vec<Coin<T>>`
1652    /// It splits off some amounts into a new coins with those amounts
1653    SplitCoins(SplitCoins),
1654    /// `(&mut Coin<T>, Vec<Coin<T>>)`
1655    /// It merges n-coins into the first coin
1656    MergeCoins(MergeCoins),
1657    /// Publishes a Move package. It takes the package bytes and a list of the
1658    /// package's transitive dependencies to link against on-chain.
1659    Publish(Publish),
1660    /// `forall T: Vec<T> -> vector<T>`
1661    /// Given n-values of the same type, it constructs a vector. For non objects
1662    /// or an empty vector, the type tag must be specified.
1663    MakeMoveVector(MakeMoveVector),
1664    /// Upgrades a Move package
1665    /// Takes (in order):
1666    /// 1. A vector of serialized modules for the package.
1667    /// 2. A vector of object ids for the transitive dependencies of the new
1668    ///    package.
1669    /// 3. The object ID of the package being upgraded.
1670    /// 4. An argument holding the `UpgradeTicket` that must have been produced
1671    ///    from an earlier command in the same programmable transaction.
1672    Upgrade(Upgrade),
1673}
1674
1675impl Command {
1676    crate::def_is_as_into_opt!(
1677        MoveCall,
1678        TransferObjects,
1679        SplitCoins,
1680        MergeCoins,
1681        Publish,
1682        MakeMoveVector,
1683        Upgrade,
1684    );
1685
1686    /// Create a command to call a Move function.
1687    pub fn new_move_call(
1688        package: ObjectId,
1689        module: Identifier,
1690        function: Identifier,
1691        type_arguments: Vec<TypeTag>,
1692        arguments: Vec<Argument>,
1693    ) -> Self {
1694        Command::MoveCall(MoveCall {
1695            package,
1696            module,
1697            function,
1698            type_arguments,
1699            arguments,
1700        })
1701    }
1702
1703    /// Create a command to transfer objects to an address.
1704    pub fn new_transfer_objects(objects: Vec<Argument>, address: Argument) -> Self {
1705        Command::TransferObjects(TransferObjects { objects, address })
1706    }
1707
1708    /// Create a command to split a coin into multiple coins by amounts.
1709    pub fn new_split_coins(coin: Argument, amounts: Vec<Argument>) -> Self {
1710        Command::SplitCoins(SplitCoins { coin, amounts })
1711    }
1712
1713    /// Create a command to merge multiple coins into one.
1714    pub fn new_merge_coins(coin: Argument, coins_to_merge: Vec<Argument>) -> Self {
1715        Command::MergeCoins(MergeCoins {
1716            coin,
1717            coins_to_merge,
1718        })
1719    }
1720
1721    /// Create a command to publish a new Move package.
1722    pub fn new_publish(modules: Vec<Vec<u8>>, dependencies: Vec<ObjectId>) -> Self {
1723        Command::Publish(Publish {
1724            modules,
1725            dependencies,
1726        })
1727    }
1728
1729    /// Create a command to construct a Move vector from elements.
1730    pub fn new_make_move_vector(type_tag: Option<TypeTag>, elements: Vec<Argument>) -> Self {
1731        Command::MakeMoveVector(MakeMoveVector { type_tag, elements })
1732    }
1733
1734    /// Create a command to upgrade an existing Move package.
1735    pub fn new_upgrade(
1736        modules: Vec<Vec<u8>>,
1737        dependencies: Vec<ObjectId>,
1738        package: ObjectId,
1739        ticket: Argument,
1740    ) -> Self {
1741        Command::Upgrade(Upgrade {
1742            modules,
1743            dependencies,
1744            package,
1745            ticket,
1746        })
1747    }
1748}
1749
1750impl crate::TreeDisplay for Command {
1751    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
1752        w.enum_name("Command");
1753        match self {
1754            Self::MoveCall(v) => v.fmt_tree(w),
1755            Self::TransferObjects(v) => v.fmt_tree(w),
1756            Self::SplitCoins(v) => v.fmt_tree(w),
1757            Self::MergeCoins(v) => v.fmt_tree(w),
1758            Self::Publish(v) => v.fmt_tree(w),
1759            Self::MakeMoveVector(v) => v.fmt_tree(w),
1760            Self::Upgrade(v) => v.fmt_tree(w),
1761        }
1762    }
1763}
1764
1765/// Command to transfer ownership of a set of objects to an address
1766///
1767/// # BCS
1768///
1769/// The BCS serialized form for this type is defined by the following ABNF:
1770///
1771/// ```text
1772/// transfer-objects = (vector argument) argument
1773/// ```
1774#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1775#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
1776#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
1777#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
1778pub struct TransferObjects {
1779    /// Set of objects to transfer
1780    #[cfg_attr(feature = "proptest", any(proptest::collection::size_range(0..=2).lift()))]
1781    pub objects: Vec<Argument>,
1782    /// The address to transfer ownership to
1783    pub address: Argument,
1784}
1785
1786impl crate::TreeDisplay for TransferObjects {
1787    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
1788        w.header("Transfer Objects")?;
1789        w.leaves("Objects", &self.objects, false)?;
1790        w.leaf("Address", &self.address, true)
1791    }
1792}
1793
1794/// Command to split a single coin object into multiple coins
1795///
1796/// # BCS
1797///
1798/// The BCS serialized form for this type is defined by the following ABNF:
1799///
1800/// ```text
1801/// split-coins = argument (vector argument)
1802/// ```
1803#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1804#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
1805#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
1806#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
1807pub struct SplitCoins {
1808    /// The coin to split
1809    pub coin: Argument,
1810    /// The amounts to split off
1811    #[cfg_attr(feature = "proptest", any(proptest::collection::size_range(0..=2).lift()))]
1812    pub amounts: Vec<Argument>,
1813}
1814
1815impl crate::TreeDisplay for SplitCoins {
1816    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
1817        w.header("Split Coins")?;
1818        w.leaf("Coin", &self.coin, false)?;
1819        w.leaves("Amounts", &self.amounts, true)
1820    }
1821}
1822
1823/// Command to merge multiple coins of the same type into a single coin
1824///
1825/// # BCS
1826///
1827/// The BCS serialized form for this type is defined by the following ABNF:
1828///
1829/// ```text
1830/// merge-coins = argument (vector argument)
1831/// ```
1832#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1833#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
1834#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
1835#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
1836pub struct MergeCoins {
1837    /// Coin to merge coins into
1838    pub coin: Argument,
1839    /// Set of coins to merge into `coin`
1840    ///
1841    /// All listed coins must be of the same type and be the same type as `coin`
1842    #[cfg_attr(feature = "proptest", any(proptest::collection::size_range(0..=2).lift()))]
1843    pub coins_to_merge: Vec<Argument>,
1844}
1845
1846impl crate::TreeDisplay for MergeCoins {
1847    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
1848        w.header("Merge Coins")?;
1849        w.leaf("Coin", &self.coin, false)?;
1850        w.leaves("Coins To Merge", &self.coins_to_merge, true)
1851    }
1852}
1853
1854/// Command to publish a new move package
1855///
1856/// # BCS
1857///
1858/// The BCS serialized form for this type is defined by the following ABNF:
1859///
1860/// ```text
1861/// publish = (vector bytes)        ; the serialized move modules
1862///           (vector object-id)    ; the set of package dependencies
1863/// ```
1864#[derive(Clone, derive_more::Debug, Eq, Hash, PartialEq)]
1865#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
1866#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
1867#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
1868pub struct Publish {
1869    /// The serialized move modules
1870    #[cfg_attr(
1871        feature = "serde",
1872        serde(
1873            with = "::serde_with::As::<Vec<::serde_with::IfIsHumanReadable<crate::_serde::Base64Encoded, ::serde_with::Bytes>>>"
1874        )
1875    )]
1876    #[debug(
1877        "{:?}",
1878        modules
1879            .iter()
1880            .map(|m| <base64ct::Base64 as base64ct::Encoding>::encode_string(m))
1881            .collect::<Vec<_>>()
1882    )]
1883    pub modules: Vec<Vec<u8>>,
1884    /// Set of packages that the to-be published package depends on
1885    pub dependencies: Vec<ObjectId>,
1886}
1887
1888impl crate::TreeDisplay for Publish {
1889    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
1890        w.header("Publish")?;
1891        w.base64_leaves("Modules", &self.modules, false)?;
1892        w.leaves("Dependencies", &self.dependencies, true)
1893    }
1894}
1895
1896/// Command to build a move vector out of a set of individual elements
1897///
1898/// # BCS
1899///
1900/// The BCS serialized form for this type is defined by the following ABNF:
1901///
1902/// ```text
1903/// make-move-vector = (option type-tag) (vector argument)
1904/// ```
1905#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1906#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
1907#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
1908#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
1909pub struct MakeMoveVector {
1910    /// Type of the individual elements
1911    ///
1912    /// This is required to be set when the type can't be inferred, for example
1913    /// when the set of provided arguments are all pure input values.
1914    #[cfg_attr(feature = "serde", serde(rename = "type"))]
1915    pub type_tag: Option<TypeTag>,
1916    /// The set individual elements to build the vector with
1917    #[cfg_attr(feature = "proptest", any(proptest::collection::size_range(0..=2).lift()))]
1918    pub elements: Vec<Argument>,
1919}
1920
1921impl crate::TreeDisplay for MakeMoveVector {
1922    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
1923        w.header("Make Move Vector")?;
1924        w.option_leaf("Type Tag", &self.type_tag, false)?;
1925        w.leaves("Elements", &self.elements, true)
1926    }
1927}
1928
1929/// Command to upgrade an already published package
1930///
1931/// # BCS
1932///
1933/// The BCS serialized form for this type is defined by the following ABNF:
1934///
1935/// ```text
1936/// upgrade = (vector bytes)        ; move modules
1937///           (vector object-id)    ; dependencies
1938///           object-id             ; package-id of the package
1939///           argument              ; upgrade ticket
1940/// ```
1941#[derive(Clone, derive_more::Debug, Eq, Hash, PartialEq)]
1942#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
1943#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
1944#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
1945pub struct Upgrade {
1946    /// The serialized move modules
1947    #[cfg_attr(
1948        feature = "serde",
1949        serde(
1950            with = "::serde_with::As::<Vec<::serde_with::IfIsHumanReadable<crate::_serde::Base64Encoded, ::serde_with::Bytes>>>"
1951        )
1952    )]
1953    #[debug(
1954        "{:?}",
1955        modules
1956            .iter()
1957            .map(|m| <base64ct::Base64 as base64ct::Encoding>::encode_string(m))
1958            .collect::<Vec<_>>()
1959    )]
1960    pub modules: Vec<Vec<u8>>,
1961    /// Set of packages that the to-be published package depends on
1962    pub dependencies: Vec<ObjectId>,
1963    /// Package id of the package to upgrade
1964    pub package: ObjectId,
1965    /// Ticket authorizing the upgrade
1966    pub ticket: Argument,
1967}
1968
1969impl crate::TreeDisplay for Upgrade {
1970    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
1971        w.header("Upgrade")?;
1972        w.base64_leaves("Modules", &self.modules, false)?;
1973        w.leaves("Dependencies", &self.dependencies, false)?;
1974        w.leaf("Package", &self.package, false)?;
1975        w.leaf("Ticket", &self.ticket, true)
1976    }
1977}
1978
1979/// An argument to a programmable transaction command
1980///
1981/// # BCS
1982///
1983/// The BCS serialized form for this type is defined by the following ABNF:
1984///
1985/// ```text
1986/// argument    =  argument-gas
1987///             =/ argument-input
1988///             =/ argument-result
1989///             =/ argument-nested-result
1990///
1991/// argument-gas            = %d00
1992/// argument-input          = %d01 u16
1993/// argument-result         = %d02 u16
1994/// argument-nested-result  = %d03 u16 u16
1995/// ```
1996#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1997#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
1998#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
1999#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
2000#[non_exhaustive]
2001pub enum Argument {
2002    /// The gas coin. The gas coin can only be used by-ref, except for with
2003    /// `TransferObjects`, which can use it by-value.
2004    Gas,
2005    /// One of the input objects or primitive values (from
2006    /// `ProgrammableTransaction` inputs)
2007    Input(u16),
2008    /// The result of another command (from `ProgrammableTransaction` commands)
2009    Result(u16),
2010    /// Like a `Result` but it accesses a nested result. Currently, the only
2011    /// usage of this is to access a value from a Move call with multiple
2012    /// return values.
2013    // (command index, subresult index)
2014    NestedResult(u16, u16),
2015}
2016
2017impl std::fmt::Display for Argument {
2018    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2019        match self {
2020            Argument::Gas => write!(f, "Gas"),
2021            Argument::Input(i) => write!(f, "Input({i})"),
2022            Argument::Result(i) => write!(f, "Result({i})"),
2023            Argument::NestedResult(i, j) => write!(f, "NestedResult({i}, {j})"),
2024        }
2025    }
2026}
2027
2028impl Argument {
2029    crate::def_is!(Gas, Input, Result, NestedResult);
2030
2031    pub fn as_opt_input(&self) -> Option<u16> {
2032        if let Self::Input(idx) = self {
2033            Some(*idx)
2034        } else {
2035            None
2036        }
2037    }
2038
2039    pub fn as_input(&self) -> u16 {
2040        self.as_opt_input().expect("not an input")
2041    }
2042
2043    pub fn as_opt_result(&self) -> Option<u16> {
2044        if let Self::Result(idx) = self {
2045            Some(*idx)
2046        } else {
2047            None
2048        }
2049    }
2050
2051    pub fn as_result(&self) -> u16 {
2052        self.as_opt_result().expect("not a result")
2053    }
2054
2055    pub fn as_opt_nested_result(&self) -> Option<(u16, u16)> {
2056        if let Self::NestedResult(idx0, idx1) = self {
2057            Some((*idx0, *idx1))
2058        } else {
2059            None
2060        }
2061    }
2062
2063    pub fn as_nested_result(&self) -> (u16, u16) {
2064        self.as_opt_nested_result().expect("not a nested result")
2065    }
2066
2067    /// Get the nested result for this result at the given index. Returns None
2068    /// if this is not a Result.
2069    pub fn get_nested_result(&self, ix: u16) -> Option<Argument> {
2070        match self {
2071            Argument::Result(i) => Some(Argument::NestedResult(*i, ix)),
2072            _ => None,
2073        }
2074    }
2075}
2076
2077/// Command to call a move function
2078///
2079/// Functions that can be called by a `MoveCall` command are those that have a
2080/// function signature that is either `entry` or `public` (which don't have a
2081/// reference return type).
2082///
2083/// # BCS
2084///
2085/// The BCS serialized form for this type is defined by the following ABNF:
2086///
2087/// ```text
2088/// move-call = object-id           ; package id
2089///             identifier          ; module name
2090///             identifier          ; function name
2091///             (vector type-tag)   ; type arguments, if any
2092///             (vector argument)   ; input arguments
2093/// ```
2094#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2095#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
2096#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
2097#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
2098pub struct MoveCall {
2099    /// The package containing the module and function.
2100    pub package: ObjectId,
2101    /// The specific module in the package containing the function.
2102    #[cfg_attr(
2103        feature = "serde",
2104        serde(deserialize_with = "serialization::deserialize_ident_unchecked")
2105    )]
2106    pub module: Identifier,
2107    /// The function to be called.
2108    pub function: Identifier,
2109    /// The type arguments to the function.
2110    #[cfg_attr(feature = "proptest", any(proptest::collection::size_range(0..=2).lift()))]
2111    pub type_arguments: Vec<TypeTag>,
2112    /// The arguments to the function.
2113    #[cfg_attr(feature = "proptest", any(proptest::collection::size_range(0..=2).lift()))]
2114    pub arguments: Vec<Argument>,
2115}
2116
2117impl crate::TreeDisplay for MoveCall {
2118    fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
2119        w.header("Move Call")?;
2120        w.leaf("Package", &self.package, false)?;
2121        w.leaf("Module", &self.module, false)?;
2122        w.leaf("Function", &self.function, false)?;
2123        w.leaves("Type Arguments", &self.type_arguments, false)?;
2124        w.leaves("Arguments", &self.arguments, true)
2125    }
2126}
2127
2128crate::impl_tree_display!(
2129    Transaction,
2130    DenyRuleSet,
2131    TransactionDenyRulesUpdate,
2132    TransactionV1,
2133    SignedTransaction,
2134    GasPayment,
2135    RandomnessStateUpdate,
2136    TransactionKind,
2137    EndOfEpochTransactionKind,
2138    ConsensusDeterminedVersionAssignments,
2139    CanceledTransaction,
2140    VersionAssignment,
2141    ConsensusCommitPrologueV1,
2142    ChangeEpoch,
2143    ChangeEpochV2,
2144    ChangeEpochV3,
2145    ChangeEpochV4,
2146    SystemPackage,
2147    GenesisTransaction,
2148    ProgrammableTransaction,
2149    SharedObjectReference,
2150    Input,
2151    Command,
2152    TransferObjects,
2153    SplitCoins,
2154    MergeCoins,
2155    Publish,
2156    MakeMoveVector,
2157    Upgrade,
2158    MoveCall,
2159);