Skip to main content

sui_types/
rpc_proto_conversions.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Module for conversions from sui-core types to rpc protos
5
6use crate::crypto::SuiSignature;
7use nonempty::NonEmpty;
8
9fn ms_to_timestamp(ms: u64) -> prost_types::Timestamp {
10    prost_types::Timestamp {
11        seconds: (ms / 1000) as _,
12        nanos: ((ms % 1000) * 1_000_000) as _,
13    }
14}
15
16fn timestamp_to_ms(timestamp: &prost_types::Timestamp) -> Result<u64, &'static str> {
17    let seconds: u64 = timestamp
18        .seconds
19        .try_into()
20        .map_err(|_| "invalid timestamp: negative seconds")?;
21    let nanos: u64 = timestamp
22        .nanos
23        .try_into()
24        .map_err(|_| "invalid timestamp: negative nanos")?;
25    seconds
26        .checked_mul(1000)
27        .and_then(|ms| ms.checked_add(nanos / 1_000_000))
28        .ok_or("invalid timestamp: out of range")
29}
30use crate::message_envelope::Message as _;
31use fastcrypto::traits::ToFromBytes;
32use sui_rpc::field::FieldMaskTree;
33use sui_rpc::merge::Merge;
34use sui_rpc::proto::TryFromProtoError;
35use sui_rpc::proto::sui::rpc::v2::*;
36
37//
38// CheckpointSummary
39//
40
41impl Merge<&crate::full_checkpoint_content::Checkpoint> for Checkpoint {
42    fn merge(&mut self, source: &crate::full_checkpoint_content::Checkpoint, mask: &FieldMaskTree) {
43        let sequence_number = source.summary.sequence_number;
44        let timestamp_ms = source.summary.timestamp_ms;
45
46        let summary = source.summary.data();
47        let signature = source.summary.auth_sig();
48
49        self.merge(summary, mask);
50        self.merge(signature.clone(), mask);
51
52        if mask.contains(Checkpoint::CONTENTS_FIELD.name) {
53            self.merge(&source.contents, mask);
54        }
55
56        if let Some(submask) = mask
57            .subtree(Checkpoint::OBJECTS_FIELD)
58            .and_then(|submask| submask.subtree(ObjectSet::OBJECTS_FIELD))
59        {
60            let set = source
61                .object_set
62                .iter()
63                .map(|o| sui_rpc::proto::sui::rpc::v2::Object::merge_from(o, &submask))
64                .collect();
65            self.objects = Some(ObjectSet::default().with_objects(set));
66        }
67
68        if let Some(submask) = mask.subtree(Checkpoint::TRANSACTIONS_FIELD.name) {
69            self.transactions = source
70                .transactions
71                .iter()
72                .map(|t| {
73                    let mut transaction = ExecutedTransaction::merge_from(t, &submask);
74                    transaction.checkpoint = submask
75                        .contains(ExecutedTransaction::CHECKPOINT_FIELD)
76                        .then_some(sequence_number);
77                    transaction.timestamp = submask
78                        .contains(ExecutedTransaction::TIMESTAMP_FIELD)
79                        .then(|| sui_rpc::proto::timestamp_ms_to_proto(timestamp_ms));
80                    transaction
81                })
82                .collect();
83        }
84    }
85}
86
87impl Merge<&crate::full_checkpoint_content::ExecutedTransaction> for ExecutedTransaction {
88    fn merge(
89        &mut self,
90        source: &crate::full_checkpoint_content::ExecutedTransaction,
91        mask: &FieldMaskTree,
92    ) {
93        use crate::effects::TransactionEffectsAPI;
94
95        let transaction_mask = mask.subtree(ExecutedTransaction::TRANSACTION_FIELD);
96        let top_level_digest_selected = mask.contains(ExecutedTransaction::DIGEST_FIELD);
97        let nested_digest_selected = transaction_mask
98            .as_ref()
99            .is_some_and(|submask| submask.contains(Transaction::DIGEST_FIELD.name));
100        let (top_level_digest_string, nested_digest_string) =
101            match (top_level_digest_selected, nested_digest_selected) {
102                (false, false) => (None, None),
103                (true, false) => (
104                    Some(source.effects.transaction_digest().base58_encode()),
105                    None,
106                ),
107                (false, true) => (
108                    None,
109                    Some(source.effects.transaction_digest().base58_encode()),
110                ),
111                (true, true) => {
112                    let digest_string = source.effects.transaction_digest().base58_encode();
113                    (Some(digest_string.clone()), Some(digest_string))
114                }
115            };
116
117        if top_level_digest_selected {
118            self.digest = top_level_digest_string;
119        }
120
121        if let Some(submask) = transaction_mask {
122            let mut transaction = Transaction::default();
123            merge_transaction_data(
124                &mut transaction,
125                &source.transaction,
126                nested_digest_string,
127                &submask,
128            );
129            self.transaction = Some(transaction);
130        }
131
132        if let Some(submask) = mask.subtree(ExecutedTransaction::SIGNATURES_FIELD) {
133            self.signatures = source
134                .signatures
135                .iter()
136                .map(|s| UserSignature::merge_from(s, &submask))
137                .collect();
138        }
139
140        if let Some(submask) = mask.subtree(ExecutedTransaction::EFFECTS_FIELD) {
141            let mut effects = TransactionEffects::merge_from(&source.effects, &submask);
142            if submask.contains(TransactionEffects::UNCHANGED_LOADED_RUNTIME_OBJECTS_FIELD) {
143                effects.set_unchanged_loaded_runtime_objects(
144                    source
145                        .unchanged_loaded_runtime_objects
146                        .iter()
147                        .map(Into::into)
148                        .collect(),
149                );
150            }
151            self.effects = Some(effects);
152        }
153
154        if let Some(submask) = mask.subtree(ExecutedTransaction::EVENTS_FIELD) {
155            self.events = source
156                .events
157                .as_ref()
158                .map(|events| TransactionEvents::merge_from(events, &submask));
159        }
160    }
161}
162
163impl TryFrom<&Checkpoint> for crate::full_checkpoint_content::Checkpoint {
164    type Error = TryFromProtoError;
165
166    fn try_from(checkpoint: &Checkpoint) -> Result<Self, Self::Error> {
167        let summary = checkpoint
168            .summary()
169            .bcs()
170            .deserialize()
171            .map_err(|e| TryFromProtoError::invalid("summary.bcs", e))?;
172
173        let signature =
174            crate::crypto::AuthorityStrongQuorumSignInfo::try_from(checkpoint.signature())?;
175
176        let summary = crate::messages_checkpoint::CertifiedCheckpointSummary::new_from_data_and_sig(
177            summary, signature,
178        );
179
180        let contents: crate::messages_checkpoint::CheckpointContents = checkpoint
181            .contents()
182            .bcs()
183            .deserialize()
184            .map_err(|e| TryFromProtoError::invalid("contents.bcs", e))?;
185
186        let user_signatures: Vec<_> = contents
187            .clone()
188            .into_iter_with_signatures()
189            .map(|(_, user_signatures)| user_signatures)
190            .collect();
191
192        #[allow(clippy::disallowed_methods)]
193        // Intentional zip: transactions field may be partially populated via field masks
194        let transactions = checkpoint
195            .transactions()
196            .iter()
197            .zip(user_signatures)
198            .map(|(tx, user_signatures)| {
199                let mut executed_tx: crate::full_checkpoint_content::ExecutedTransaction =
200                    tx.try_into()?;
201                executed_tx.signatures = user_signatures;
202                Ok(executed_tx)
203            })
204            .collect::<Result<_, TryFromProtoError>>()?;
205
206        let object_set = checkpoint.objects().try_into()?;
207
208        Ok(Self {
209            summary,
210            contents,
211            transactions,
212            object_set,
213        })
214    }
215}
216
217impl TryFrom<&ExecutedTransaction> for crate::full_checkpoint_content::ExecutedTransaction {
218    type Error = TryFromProtoError;
219
220    fn try_from(value: &ExecutedTransaction) -> Result<Self, Self::Error> {
221        Ok(Self {
222            transaction: value
223                .transaction()
224                .bcs()
225                .deserialize()
226                .map_err(|e| TryFromProtoError::invalid("transaction.bcs", e))?,
227            signatures: value
228                .signatures()
229                .iter()
230                .map(|sig| {
231                    crate::signature::GenericSignature::from_bytes(sig.bcs().value())
232                        .map_err(|e| TryFromProtoError::invalid("signature.bcs", e))
233                })
234                .collect::<Result<_, _>>()?,
235            effects: value
236                .effects()
237                .bcs()
238                .deserialize()
239                .map_err(|e| TryFromProtoError::invalid("effects.bcs", e))?,
240            events: value
241                .events_opt()
242                .map(|events| {
243                    events
244                        .bcs()
245                        .deserialize()
246                        .map_err(|e| TryFromProtoError::invalid("effects.bcs", e))
247                })
248                .transpose()?,
249            unchanged_loaded_runtime_objects: value
250                .effects()
251                .unchanged_loaded_runtime_objects()
252                .iter()
253                .map(TryInto::try_into)
254                .collect::<Result<_, _>>()?,
255        })
256    }
257}
258
259impl TryFrom<&ObjectReference> for crate::storage::ObjectKey {
260    type Error = TryFromProtoError;
261
262    fn try_from(value: &ObjectReference) -> Result<Self, Self::Error> {
263        Ok(Self(
264            value
265                .object_id()
266                .parse()
267                .map_err(|e| TryFromProtoError::invalid("object_id", e))?,
268            value.version().into(),
269        ))
270    }
271}
272
273//
274// CheckpointSummary
275//
276
277impl From<crate::messages_checkpoint::CheckpointSummary> for CheckpointSummary {
278    fn from(summary: crate::messages_checkpoint::CheckpointSummary) -> Self {
279        Self::merge_from(summary, &FieldMaskTree::new_wildcard())
280    }
281}
282
283impl Merge<crate::messages_checkpoint::CheckpointSummary> for CheckpointSummary {
284    fn merge(
285        &mut self,
286        source: crate::messages_checkpoint::CheckpointSummary,
287        mask: &FieldMaskTree,
288    ) {
289        if mask.contains(Self::BCS_FIELD) {
290            let mut bcs = Bcs::serialize(&source).unwrap();
291            bcs.name = Some("CheckpointSummary".to_owned());
292            self.bcs = Some(bcs);
293        }
294
295        if mask.contains(Self::DIGEST_FIELD) {
296            self.digest = Some(source.digest().to_string());
297        }
298
299        let crate::messages_checkpoint::CheckpointSummary {
300            epoch,
301            sequence_number,
302            network_total_transactions,
303            content_digest,
304            previous_digest,
305            epoch_rolling_gas_cost_summary,
306            timestamp_ms,
307            checkpoint_commitments,
308            end_of_epoch_data,
309            version_specific_data,
310        } = source;
311
312        if mask.contains(Self::EPOCH_FIELD) {
313            self.epoch = Some(epoch);
314        }
315
316        if mask.contains(Self::SEQUENCE_NUMBER_FIELD) {
317            self.sequence_number = Some(sequence_number);
318        }
319
320        if mask.contains(Self::TOTAL_NETWORK_TRANSACTIONS_FIELD) {
321            self.total_network_transactions = Some(network_total_transactions);
322        }
323
324        if mask.contains(Self::CONTENT_DIGEST_FIELD) {
325            self.content_digest = Some(content_digest.to_string());
326        }
327
328        if mask.contains(Self::PREVIOUS_DIGEST_FIELD) {
329            self.previous_digest = previous_digest.map(|d| d.to_string());
330        }
331
332        if mask.contains(Self::EPOCH_ROLLING_GAS_COST_SUMMARY_FIELD) {
333            self.epoch_rolling_gas_cost_summary = Some(epoch_rolling_gas_cost_summary.into());
334        }
335
336        if mask.contains(Self::TIMESTAMP_FIELD) {
337            self.timestamp = Some(sui_rpc::proto::timestamp_ms_to_proto(timestamp_ms));
338        }
339
340        if mask.contains(Self::COMMITMENTS_FIELD) {
341            self.commitments = checkpoint_commitments.into_iter().map(Into::into).collect();
342        }
343
344        if mask.contains(Self::END_OF_EPOCH_DATA_FIELD) {
345            self.end_of_epoch_data = end_of_epoch_data.map(Into::into);
346        }
347
348        if mask.contains(Self::VERSION_SPECIFIC_DATA_FIELD) {
349            self.version_specific_data = Some(version_specific_data.into());
350        }
351    }
352}
353
354//
355// GasCostSummary
356//
357
358impl From<crate::gas::GasCostSummary> for GasCostSummary {
359    fn from(
360        crate::gas::GasCostSummary {
361            computation_cost,
362            storage_cost,
363            storage_rebate,
364            non_refundable_storage_fee,
365        }: crate::gas::GasCostSummary,
366    ) -> Self {
367        let mut message = Self::default();
368        message.computation_cost = Some(computation_cost);
369        message.storage_cost = Some(storage_cost);
370        message.storage_rebate = Some(storage_rebate);
371        message.non_refundable_storage_fee = Some(non_refundable_storage_fee);
372        message
373    }
374}
375
376//
377// CheckpointCommitment
378//
379
380impl From<crate::messages_checkpoint::CheckpointCommitment> for CheckpointCommitment {
381    fn from(value: crate::messages_checkpoint::CheckpointCommitment) -> Self {
382        use checkpoint_commitment::CheckpointCommitmentKind;
383
384        let mut message = Self::default();
385
386        let kind = match value {
387            crate::messages_checkpoint::CheckpointCommitment::ECMHLiveObjectSetDigest(digest) => {
388                message.digest = Some(digest.digest.to_string());
389                CheckpointCommitmentKind::EcmhLiveObjectSet
390            }
391            crate::messages_checkpoint::CheckpointCommitment::CheckpointArtifactsDigest(digest) => {
392                message.digest = Some(digest.to_string());
393                CheckpointCommitmentKind::CheckpointArtifacts
394            }
395        };
396
397        message.set_kind(kind);
398        message
399    }
400}
401
402//
403// EndOfEpochData
404//
405
406impl From<crate::messages_checkpoint::EndOfEpochData> for EndOfEpochData {
407    fn from(
408        crate::messages_checkpoint::EndOfEpochData {
409            next_epoch_committee,
410            next_epoch_protocol_version,
411            epoch_commitments,
412        }: crate::messages_checkpoint::EndOfEpochData,
413    ) -> Self {
414        let mut message = Self::default();
415
416        message.next_epoch_committee = next_epoch_committee
417            .into_iter()
418            .map(|(name, weight)| {
419                let mut member = ValidatorCommitteeMember::default();
420                member.public_key = Some(name.0.to_vec().into());
421                member.weight = Some(weight);
422                member
423            })
424            .collect();
425        message.next_epoch_protocol_version = Some(next_epoch_protocol_version.as_u64());
426        message.epoch_commitments = epoch_commitments.into_iter().map(Into::into).collect();
427
428        message
429    }
430}
431
432//
433// CheckpointContents
434//
435
436impl From<crate::messages_checkpoint::CheckpointContents> for CheckpointContents {
437    fn from(value: crate::messages_checkpoint::CheckpointContents) -> Self {
438        Self::merge_from(value, &FieldMaskTree::new_wildcard())
439    }
440}
441
442impl Merge<crate::messages_checkpoint::CheckpointContents> for CheckpointContents {
443    fn merge(
444        &mut self,
445        source: crate::messages_checkpoint::CheckpointContents,
446        mask: &FieldMaskTree,
447    ) {
448        if mask.contains(Self::BCS_FIELD) {
449            let mut bcs = Bcs::serialize(&source).unwrap();
450            bcs.name = Some("CheckpointContents".to_owned());
451            self.bcs = Some(bcs);
452        }
453
454        if mask.contains(Self::DIGEST_FIELD) {
455            self.digest = Some(source.digest().to_string());
456        }
457
458        if mask.contains(Self::VERSION_FIELD) {
459            self.set_version(match &source {
460                crate::messages_checkpoint::CheckpointContents::V1(_) => 1,
461                crate::messages_checkpoint::CheckpointContents::V2(_) => 2,
462            });
463        }
464
465        if mask.contains(Self::TRANSACTIONS_FIELD) {
466            self.transactions = source
467                .inner()
468                .iter()
469                .map(|(digests, sigs)| {
470                    let mut info = CheckpointedTransactionInfo::default();
471                    info.transaction = Some(digests.transaction.to_string());
472                    info.effects = Some(digests.effects.to_string());
473                    let (signatures, versions) = sigs
474                        .map(|(s, v)| {
475                            (s.into(), {
476                                let mut message = AddressAliasesVersion::default();
477                                message.version = v.map(Into::into);
478                                message
479                            })
480                        })
481                        .unzip();
482                    info.signatures = signatures;
483                    info.address_aliases_versions = versions;
484                    info
485                })
486                .collect();
487        }
488    }
489}
490
491impl Merge<&crate::messages_checkpoint::CheckpointContents> for Checkpoint {
492    fn merge(
493        &mut self,
494        source: &crate::messages_checkpoint::CheckpointContents,
495        mask: &FieldMaskTree,
496    ) {
497        if let Some(submask) = mask.subtree(Self::CONTENTS_FIELD.name) {
498            self.contents = Some(CheckpointContents::merge_from(source.to_owned(), &submask));
499        }
500    }
501}
502
503//
504// Checkpoint
505//
506
507impl Merge<&crate::messages_checkpoint::CheckpointSummary> for Checkpoint {
508    fn merge(
509        &mut self,
510        source: &crate::messages_checkpoint::CheckpointSummary,
511        mask: &FieldMaskTree,
512    ) {
513        if mask.contains(Self::SEQUENCE_NUMBER_FIELD) {
514            self.sequence_number = Some(source.sequence_number);
515        }
516
517        if mask.contains(Self::DIGEST_FIELD) {
518            self.digest = Some(source.digest().to_string());
519        }
520
521        if let Some(submask) = mask.subtree(Self::SUMMARY_FIELD) {
522            self.summary = Some(CheckpointSummary::merge_from(source.clone(), &submask));
523        }
524    }
525}
526
527impl<const T: bool> Merge<crate::crypto::AuthorityQuorumSignInfo<T>> for Checkpoint {
528    fn merge(&mut self, source: crate::crypto::AuthorityQuorumSignInfo<T>, mask: &FieldMaskTree) {
529        if mask.contains(Self::SIGNATURE_FIELD) {
530            self.signature = Some(source.into());
531        }
532    }
533}
534
535impl Merge<crate::messages_checkpoint::CheckpointContents> for Checkpoint {
536    fn merge(
537        &mut self,
538        source: crate::messages_checkpoint::CheckpointContents,
539        mask: &FieldMaskTree,
540    ) {
541        if let Some(submask) = mask.subtree(Self::CONTENTS_FIELD) {
542            self.contents = Some(CheckpointContents::merge_from(source, &submask));
543        }
544    }
545}
546
547//
548// Event
549//
550
551impl From<crate::event::Event> for Event {
552    fn from(value: crate::event::Event) -> Self {
553        Self::merge_from(&value, &FieldMaskTree::new_wildcard())
554    }
555}
556
557impl Merge<&crate::event::Event> for Event {
558    fn merge(&mut self, source: &crate::event::Event, mask: &FieldMaskTree) {
559        if mask.contains(Self::PACKAGE_ID_FIELD) {
560            self.package_id = Some(source.package_id.to_canonical_string(true));
561        }
562
563        if mask.contains(Self::MODULE_FIELD) {
564            self.module = Some(source.transaction_module.to_string());
565        }
566
567        if mask.contains(Self::SENDER_FIELD) {
568            self.sender = Some(source.sender.to_string());
569        }
570
571        if mask.contains(Self::EVENT_TYPE_FIELD) {
572            self.event_type = Some(source.type_.to_canonical_string(true));
573        }
574
575        if mask.contains(Self::CONTENTS_FIELD) {
576            let mut bcs = Bcs::from(source.contents.clone());
577            bcs.name = Some(source.type_.to_canonical_string(true));
578            self.contents = Some(bcs);
579        }
580    }
581}
582
583//
584// TransactionEvents
585//
586
587impl From<crate::effects::TransactionEvents> for TransactionEvents {
588    fn from(value: crate::effects::TransactionEvents) -> Self {
589        Self::merge_from(&value, &FieldMaskTree::new_wildcard())
590    }
591}
592
593impl Merge<&crate::effects::TransactionEvents> for TransactionEvents {
594    fn merge(&mut self, source: &crate::effects::TransactionEvents, mask: &FieldMaskTree) {
595        if mask.contains(Self::BCS_FIELD) {
596            let mut bcs = Bcs::serialize(&source).unwrap();
597            bcs.name = Some("TransactionEvents".to_owned());
598            self.bcs = Some(bcs);
599        }
600
601        if mask.contains(Self::DIGEST_FIELD) {
602            self.digest = Some(source.digest().to_string());
603        }
604
605        if let Some(events_mask) = mask.subtree(Self::EVENTS_FIELD) {
606            self.events = source
607                .data
608                .iter()
609                .map(|event| Event::merge_from(event, &events_mask))
610                .collect();
611        }
612    }
613}
614
615//
616// SystemState
617//
618
619impl From<crate::sui_system_state::SuiSystemState> for SystemState {
620    fn from(value: crate::sui_system_state::SuiSystemState) -> Self {
621        match value {
622            crate::sui_system_state::SuiSystemState::V1(v1) => v1.into(),
623            crate::sui_system_state::SuiSystemState::V2(v2) => v2.into(),
624
625            #[allow(unreachable_patterns)]
626            _ => Self::default(),
627        }
628    }
629}
630
631impl From<crate::sui_system_state::sui_system_state_inner_v1::SuiSystemStateInnerV1>
632    for SystemState
633{
634    fn from(
635        crate::sui_system_state::sui_system_state_inner_v1::SuiSystemStateInnerV1 {
636            epoch,
637            protocol_version,
638            system_state_version,
639            validators,
640            storage_fund,
641            parameters,
642            reference_gas_price,
643            validator_report_records,
644            stake_subsidy,
645            safe_mode,
646            safe_mode_storage_rewards,
647            safe_mode_computation_rewards,
648            safe_mode_storage_rebates,
649            safe_mode_non_refundable_storage_fee,
650            epoch_start_timestamp_ms,
651            extra_fields,
652        }: crate::sui_system_state::sui_system_state_inner_v1::SuiSystemStateInnerV1,
653    ) -> Self {
654        let validator_report_records = validator_report_records
655            .contents
656            .into_iter()
657            .map(|entry| {
658                let mut record = ValidatorReportRecord::default();
659                record.reported = Some(entry.key.to_string());
660                record.reporters = entry
661                    .value
662                    .contents
663                    .iter()
664                    .map(ToString::to_string)
665                    .collect();
666                record
667            })
668            .collect();
669
670        let mut message = Self::default();
671
672        message.version = Some(system_state_version);
673        message.epoch = Some(epoch);
674        message.protocol_version = Some(protocol_version);
675        message.validators = Some(validators.into());
676        message.storage_fund = Some(storage_fund.into());
677        message.parameters = Some(parameters.into());
678        message.reference_gas_price = Some(reference_gas_price);
679        message.validator_report_records = validator_report_records;
680        message.stake_subsidy = Some(stake_subsidy.into());
681        message.safe_mode = Some(safe_mode);
682        message.safe_mode_storage_rewards = Some(safe_mode_storage_rewards.value());
683        message.safe_mode_computation_rewards = Some(safe_mode_computation_rewards.value());
684        message.safe_mode_storage_rebates = Some(safe_mode_storage_rebates);
685        message.safe_mode_non_refundable_storage_fee = Some(safe_mode_non_refundable_storage_fee);
686        message.epoch_start_timestamp_ms = Some(epoch_start_timestamp_ms);
687        message.extra_fields = Some(extra_fields.into());
688        message
689    }
690}
691
692impl From<crate::sui_system_state::sui_system_state_inner_v2::SuiSystemStateInnerV2>
693    for SystemState
694{
695    fn from(
696        crate::sui_system_state::sui_system_state_inner_v2::SuiSystemStateInnerV2 {
697            epoch,
698            protocol_version,
699            system_state_version,
700            validators,
701            storage_fund,
702            parameters,
703            reference_gas_price,
704            validator_report_records,
705            stake_subsidy,
706            safe_mode,
707            safe_mode_storage_rewards,
708            safe_mode_computation_rewards,
709            safe_mode_storage_rebates,
710            safe_mode_non_refundable_storage_fee,
711            epoch_start_timestamp_ms,
712            extra_fields,
713        }: crate::sui_system_state::sui_system_state_inner_v2::SuiSystemStateInnerV2,
714    ) -> Self {
715        let validator_report_records = validator_report_records
716            .contents
717            .into_iter()
718            .map(|entry| {
719                let mut record = ValidatorReportRecord::default();
720                record.reported = Some(entry.key.to_string());
721                record.reporters = entry
722                    .value
723                    .contents
724                    .iter()
725                    .map(ToString::to_string)
726                    .collect();
727                record
728            })
729            .collect();
730
731        let mut message = Self::default();
732
733        message.version = Some(system_state_version);
734        message.epoch = Some(epoch);
735        message.protocol_version = Some(protocol_version);
736        message.validators = Some(validators.into());
737        message.storage_fund = Some(storage_fund.into());
738        message.parameters = Some(parameters.into());
739        message.reference_gas_price = Some(reference_gas_price);
740        message.validator_report_records = validator_report_records;
741        message.stake_subsidy = Some(stake_subsidy.into());
742        message.safe_mode = Some(safe_mode);
743        message.safe_mode_storage_rewards = Some(safe_mode_storage_rewards.value());
744        message.safe_mode_computation_rewards = Some(safe_mode_computation_rewards.value());
745        message.safe_mode_storage_rebates = Some(safe_mode_storage_rebates);
746        message.safe_mode_non_refundable_storage_fee = Some(safe_mode_non_refundable_storage_fee);
747        message.epoch_start_timestamp_ms = Some(epoch_start_timestamp_ms);
748        message.extra_fields = Some(extra_fields.into());
749        message
750    }
751}
752
753impl From<crate::collection_types::Bag> for MoveTable {
754    fn from(crate::collection_types::Bag { id, size }: crate::collection_types::Bag) -> Self {
755        let mut message = Self::default();
756        message.id = Some(id.id.bytes.to_canonical_string(true));
757        message.size = Some(size);
758        message
759    }
760}
761
762impl From<crate::collection_types::Table> for MoveTable {
763    fn from(crate::collection_types::Table { id, size }: crate::collection_types::Table) -> Self {
764        let mut message = Self::default();
765        message.id = Some(id.to_canonical_string(true));
766        message.size = Some(size);
767        message
768    }
769}
770
771impl From<crate::collection_types::TableVec> for MoveTable {
772    fn from(value: crate::collection_types::TableVec) -> Self {
773        value.contents.into()
774    }
775}
776
777impl From<crate::sui_system_state::sui_system_state_inner_v1::StakeSubsidyV1> for StakeSubsidy {
778    fn from(
779        crate::sui_system_state::sui_system_state_inner_v1::StakeSubsidyV1 {
780            balance,
781            distribution_counter,
782            current_distribution_amount,
783            stake_subsidy_period_length,
784            stake_subsidy_decrease_rate,
785            extra_fields,
786        }: crate::sui_system_state::sui_system_state_inner_v1::StakeSubsidyV1,
787    ) -> Self {
788        let mut message = Self::default();
789        message.balance = Some(balance.value());
790        message.distribution_counter = Some(distribution_counter);
791        message.current_distribution_amount = Some(current_distribution_amount);
792        message.stake_subsidy_period_length = Some(stake_subsidy_period_length);
793        message.stake_subsidy_decrease_rate = Some(stake_subsidy_decrease_rate.into());
794        message.extra_fields = Some(extra_fields.into());
795        message
796    }
797}
798
799impl From<crate::sui_system_state::sui_system_state_inner_v1::SystemParametersV1>
800    for SystemParameters
801{
802    fn from(
803        crate::sui_system_state::sui_system_state_inner_v1::SystemParametersV1 {
804            epoch_duration_ms,
805            stake_subsidy_start_epoch,
806            max_validator_count,
807            min_validator_joining_stake,
808            validator_low_stake_threshold,
809            validator_very_low_stake_threshold,
810            validator_low_stake_grace_period,
811            extra_fields,
812        }: crate::sui_system_state::sui_system_state_inner_v1::SystemParametersV1,
813    ) -> Self {
814        let mut message = Self::default();
815        message.epoch_duration_ms = Some(epoch_duration_ms);
816        message.stake_subsidy_start_epoch = Some(stake_subsidy_start_epoch);
817        message.min_validator_count = None;
818        message.max_validator_count = Some(max_validator_count);
819        message.min_validator_joining_stake = Some(min_validator_joining_stake);
820        message.validator_low_stake_threshold = Some(validator_low_stake_threshold);
821        message.validator_very_low_stake_threshold = Some(validator_very_low_stake_threshold);
822        message.validator_low_stake_grace_period = Some(validator_low_stake_grace_period);
823        message.extra_fields = Some(extra_fields.into());
824        message
825    }
826}
827
828impl From<crate::sui_system_state::sui_system_state_inner_v2::SystemParametersV2>
829    for SystemParameters
830{
831    fn from(
832        crate::sui_system_state::sui_system_state_inner_v2::SystemParametersV2 {
833            epoch_duration_ms,
834            stake_subsidy_start_epoch,
835            min_validator_count,
836            max_validator_count,
837            min_validator_joining_stake,
838            validator_low_stake_threshold,
839            validator_very_low_stake_threshold,
840            validator_low_stake_grace_period,
841            extra_fields,
842        }: crate::sui_system_state::sui_system_state_inner_v2::SystemParametersV2,
843    ) -> Self {
844        let mut message = Self::default();
845        message.epoch_duration_ms = Some(epoch_duration_ms);
846        message.stake_subsidy_start_epoch = Some(stake_subsidy_start_epoch);
847        message.min_validator_count = Some(min_validator_count);
848        message.max_validator_count = Some(max_validator_count);
849        message.min_validator_joining_stake = Some(min_validator_joining_stake);
850        message.validator_low_stake_threshold = Some(validator_low_stake_threshold);
851        message.validator_very_low_stake_threshold = Some(validator_very_low_stake_threshold);
852        message.validator_low_stake_grace_period = Some(validator_low_stake_grace_period);
853        message.extra_fields = Some(extra_fields.into());
854        message
855    }
856}
857
858impl From<crate::sui_system_state::sui_system_state_inner_v1::StorageFundV1> for StorageFund {
859    fn from(
860        crate::sui_system_state::sui_system_state_inner_v1::StorageFundV1 {
861            total_object_storage_rebates,
862            non_refundable_balance,
863        }: crate::sui_system_state::sui_system_state_inner_v1::StorageFundV1,
864    ) -> Self {
865        let mut message = Self::default();
866        message.total_object_storage_rebates = Some(total_object_storage_rebates.value());
867        message.non_refundable_balance = Some(non_refundable_balance.value());
868        message
869    }
870}
871
872impl From<crate::sui_system_state::sui_system_state_inner_v1::ValidatorSetV1> for ValidatorSet {
873    fn from(
874        crate::sui_system_state::sui_system_state_inner_v1::ValidatorSetV1 {
875            total_stake,
876            active_validators,
877            pending_active_validators,
878            pending_removals,
879            staking_pool_mappings,
880            inactive_validators,
881            validator_candidates,
882            at_risk_validators,
883            extra_fields,
884        }: crate::sui_system_state::sui_system_state_inner_v1::ValidatorSetV1,
885    ) -> Self {
886        let at_risk_validators = at_risk_validators
887            .contents
888            .into_iter()
889            .map(|entry| (entry.key.to_string(), entry.value))
890            .collect();
891
892        let mut message = Self::default();
893        message.total_stake = Some(total_stake);
894        message.active_validators = active_validators.into_iter().map(Into::into).collect();
895        message.pending_active_validators = Some(pending_active_validators.into());
896        message.pending_removals = pending_removals;
897        message.staking_pool_mappings = Some(staking_pool_mappings.into());
898        message.inactive_validators = Some(inactive_validators.into());
899        message.validator_candidates = Some(validator_candidates.into());
900        message.at_risk_validators = at_risk_validators;
901        message.extra_fields = Some(extra_fields.into());
902        message
903    }
904}
905
906impl From<crate::sui_system_state::sui_system_state_inner_v1::StakingPoolV1> for StakingPool {
907    fn from(
908        crate::sui_system_state::sui_system_state_inner_v1::StakingPoolV1 {
909            id,
910            activation_epoch,
911            deactivation_epoch,
912            sui_balance,
913            rewards_pool,
914            pool_token_balance,
915            exchange_rates,
916            pending_stake,
917            pending_total_sui_withdraw,
918            pending_pool_token_withdraw,
919            extra_fields,
920        }: crate::sui_system_state::sui_system_state_inner_v1::StakingPoolV1,
921    ) -> Self {
922        let mut message = Self::default();
923        message.id = Some(id.to_canonical_string(true));
924        message.activation_epoch = activation_epoch;
925        message.deactivation_epoch = deactivation_epoch;
926        message.sui_balance = Some(sui_balance);
927        message.rewards_pool = Some(rewards_pool.value());
928        message.pool_token_balance = Some(pool_token_balance);
929        message.exchange_rates = Some(exchange_rates.into());
930        message.pending_stake = Some(pending_stake);
931        message.pending_total_sui_withdraw = Some(pending_total_sui_withdraw);
932        message.pending_pool_token_withdraw = Some(pending_pool_token_withdraw);
933        message.extra_fields = Some(extra_fields.into());
934        message
935    }
936}
937
938impl From<crate::sui_system_state::sui_system_state_inner_v1::ValidatorV1> for Validator {
939    fn from(
940        crate::sui_system_state::sui_system_state_inner_v1::ValidatorV1 {
941            metadata:
942                crate::sui_system_state::sui_system_state_inner_v1::ValidatorMetadataV1 {
943                    sui_address,
944                    protocol_pubkey_bytes,
945                    network_pubkey_bytes,
946                    worker_pubkey_bytes,
947                    proof_of_possession_bytes,
948                    name,
949                    description,
950                    image_url,
951                    project_url,
952                    net_address,
953                    p2p_address,
954                    primary_address,
955                    worker_address,
956                    next_epoch_protocol_pubkey_bytes,
957                    next_epoch_proof_of_possession,
958                    next_epoch_network_pubkey_bytes,
959                    next_epoch_worker_pubkey_bytes,
960                    next_epoch_net_address,
961                    next_epoch_p2p_address,
962                    next_epoch_primary_address,
963                    next_epoch_worker_address,
964                    extra_fields: metadata_extra_fields,
965                },
966            voting_power,
967            operation_cap_id,
968            gas_price,
969            staking_pool,
970            commission_rate,
971            next_epoch_stake,
972            next_epoch_gas_price,
973            next_epoch_commission_rate,
974            extra_fields,
975            ..
976        }: crate::sui_system_state::sui_system_state_inner_v1::ValidatorV1,
977    ) -> Self {
978        let mut message = Self::default();
979        message.name = Some(name);
980        message.address = Some(sui_address.to_string());
981        message.description = Some(description);
982        message.image_url = Some(image_url);
983        message.project_url = Some(project_url);
984        message.protocol_public_key = Some(protocol_pubkey_bytes.into());
985        message.proof_of_possession = Some(proof_of_possession_bytes.into());
986        message.network_public_key = Some(network_pubkey_bytes.into());
987        message.worker_public_key = Some(worker_pubkey_bytes.into());
988        message.network_address = Some(net_address);
989        message.p2p_address = Some(p2p_address);
990        message.primary_address = Some(primary_address);
991        message.worker_address = Some(worker_address);
992        message.next_epoch_protocol_public_key = next_epoch_protocol_pubkey_bytes.map(Into::into);
993        message.next_epoch_proof_of_possession = next_epoch_proof_of_possession.map(Into::into);
994        message.next_epoch_network_public_key = next_epoch_network_pubkey_bytes.map(Into::into);
995        message.next_epoch_worker_public_key = next_epoch_worker_pubkey_bytes.map(Into::into);
996        message.next_epoch_network_address = next_epoch_net_address;
997        message.next_epoch_p2p_address = next_epoch_p2p_address;
998        message.next_epoch_primary_address = next_epoch_primary_address;
999        message.next_epoch_worker_address = next_epoch_worker_address;
1000        message.metadata_extra_fields = Some(metadata_extra_fields.into());
1001        message.voting_power = Some(voting_power);
1002        message.operation_cap_id = Some(operation_cap_id.bytes.to_canonical_string(true));
1003        message.gas_price = Some(gas_price);
1004        message.staking_pool = Some(staking_pool.into());
1005        message.commission_rate = Some(commission_rate);
1006        message.next_epoch_stake = Some(next_epoch_stake);
1007        message.next_epoch_gas_price = Some(next_epoch_gas_price);
1008        message.next_epoch_commission_rate = Some(next_epoch_commission_rate);
1009        message.extra_fields = Some(extra_fields.into());
1010        message
1011    }
1012}
1013
1014impl TryFrom<&SystemState>
1015    for crate::sui_system_state::sui_system_state_summary::SuiSystemStateSummary
1016{
1017    type Error = TryFromProtoError;
1018
1019    fn try_from(s: &SystemState) -> Result<Self, Self::Error> {
1020        Ok(Self {
1021            epoch: s.epoch(),
1022            protocol_version: s.protocol_version(),
1023            system_state_version: s.version(),
1024            storage_fund_total_object_storage_rebates: s
1025                .storage_fund()
1026                .total_object_storage_rebates(),
1027            storage_fund_non_refundable_balance: s.storage_fund().non_refundable_balance(),
1028            reference_gas_price: s.reference_gas_price(),
1029            safe_mode: s.safe_mode(),
1030            safe_mode_storage_rewards: s.safe_mode_storage_rewards(),
1031            safe_mode_computation_rewards: s.safe_mode_computation_rewards(),
1032            safe_mode_storage_rebates: s.safe_mode_storage_rebates(),
1033            safe_mode_non_refundable_storage_fee: s.safe_mode_non_refundable_storage_fee(),
1034            epoch_start_timestamp_ms: s.epoch_start_timestamp_ms(),
1035            epoch_duration_ms: s.parameters().epoch_duration_ms(),
1036            stake_subsidy_start_epoch: s.parameters().stake_subsidy_start_epoch(),
1037            max_validator_count: s.parameters().max_validator_count(),
1038            min_validator_joining_stake: s.parameters().min_validator_joining_stake(),
1039            validator_low_stake_threshold: s.parameters().validator_low_stake_threshold(),
1040            validator_very_low_stake_threshold: s.parameters().validator_very_low_stake_threshold(),
1041            validator_low_stake_grace_period: s.parameters().validator_low_stake_grace_period(),
1042            stake_subsidy_balance: s.stake_subsidy().balance(),
1043            stake_subsidy_distribution_counter: s.stake_subsidy().distribution_counter(),
1044            stake_subsidy_current_distribution_amount: s
1045                .stake_subsidy()
1046                .current_distribution_amount(),
1047            stake_subsidy_period_length: s.stake_subsidy().stake_subsidy_period_length(),
1048            stake_subsidy_decrease_rate: s.stake_subsidy().stake_subsidy_decrease_rate() as u16,
1049            total_stake: s.validators().total_stake(),
1050            active_validators: s
1051                .validators()
1052                .active_validators()
1053                .iter()
1054                .map(TryInto::try_into)
1055                .collect::<Result<_, _>>()?,
1056            pending_active_validators_id: s
1057                .validators()
1058                .pending_active_validators()
1059                .id()
1060                .parse()
1061                .map_err(|e| {
1062                TryFromProtoError::invalid("pending_active_validators_id", e)
1063            })?,
1064            pending_active_validators_size: s.validators().pending_active_validators().size(),
1065            pending_removals: s.validators().pending_removals().to_vec(),
1066            staking_pool_mappings_id: s
1067                .validators()
1068                .staking_pool_mappings()
1069                .id()
1070                .parse()
1071                .map_err(|e| TryFromProtoError::invalid("staking_pool_mappings_id", e))?,
1072            staking_pool_mappings_size: s.validators().staking_pool_mappings().size(),
1073            inactive_pools_id: s
1074                .validators()
1075                .inactive_validators()
1076                .id()
1077                .parse()
1078                .map_err(|e| TryFromProtoError::invalid("inactive_pools_id", e))?,
1079            inactive_pools_size: s.validators().inactive_validators().size(),
1080            validator_candidates_id: s
1081                .validators()
1082                .validator_candidates()
1083                .id()
1084                .parse()
1085                .map_err(|e| TryFromProtoError::invalid("validator_candidates", e))?,
1086            validator_candidates_size: s.validators().validator_candidates().size(),
1087            at_risk_validators: s
1088                .validators()
1089                .at_risk_validators()
1090                .iter()
1091                .map(|(address, epoch)| {
1092                    address
1093                        .parse()
1094                        .map(|address| (address, *epoch))
1095                        .map_err(|e| TryFromProtoError::invalid("at_risk_validators", e))
1096                })
1097                .collect::<Result<_, _>>()?,
1098            validator_report_records: s
1099                .validator_report_records()
1100                .iter()
1101                .map(|record| {
1102                    let reported = record.reported().parse()?;
1103                    let reporters = record
1104                        .reporters()
1105                        .iter()
1106                        .map(|address| address.parse())
1107                        .collect::<Result<Vec<_>, _>>()?;
1108                    Ok((reported, reporters))
1109                })
1110                .collect::<Result<_, anyhow::Error>>()
1111                .map_err(|e| TryFromProtoError::invalid("validator_report_records", e))?,
1112        })
1113    }
1114}
1115
1116impl TryFrom<&Validator>
1117    for crate::sui_system_state::sui_system_state_summary::SuiValidatorSummary
1118{
1119    type Error = TryFromProtoError;
1120
1121    fn try_from(v: &Validator) -> Result<Self, Self::Error> {
1122        Ok(Self {
1123            sui_address: v
1124                .address()
1125                .parse()
1126                .map_err(|e| TryFromProtoError::invalid("address", e))?,
1127            protocol_pubkey_bytes: v.protocol_public_key().into(),
1128            network_pubkey_bytes: v.network_public_key().into(),
1129            worker_pubkey_bytes: v.worker_public_key().into(),
1130            proof_of_possession_bytes: v.proof_of_possession().into(),
1131            name: v.name().into(),
1132            description: v.description().into(),
1133            image_url: v.image_url().into(),
1134            project_url: v.project_url().into(),
1135            net_address: v.network_address().into(),
1136            p2p_address: v.p2p_address().into(),
1137            primary_address: v.primary_address().into(),
1138            worker_address: v.worker_address().into(),
1139            next_epoch_protocol_pubkey_bytes: v
1140                .next_epoch_protocol_public_key_opt()
1141                .map(Into::into),
1142            next_epoch_proof_of_possession: v.next_epoch_proof_of_possession_opt().map(Into::into),
1143            next_epoch_network_pubkey_bytes: v.next_epoch_network_public_key_opt().map(Into::into),
1144            next_epoch_worker_pubkey_bytes: v.next_epoch_worker_public_key_opt().map(Into::into),
1145            next_epoch_net_address: v.next_epoch_network_address_opt().map(Into::into),
1146            next_epoch_p2p_address: v.next_epoch_p2p_address_opt().map(Into::into),
1147            next_epoch_primary_address: v.next_epoch_primary_address_opt().map(Into::into),
1148            next_epoch_worker_address: v.next_epoch_worker_address_opt().map(Into::into),
1149            voting_power: v.voting_power(),
1150            operation_cap_id: v
1151                .operation_cap_id()
1152                .parse()
1153                .map_err(|e| TryFromProtoError::invalid("operation_cap_id", e))?,
1154            gas_price: v.gas_price(),
1155            commission_rate: v.commission_rate(),
1156            next_epoch_stake: v.next_epoch_stake(),
1157            next_epoch_gas_price: v.next_epoch_gas_price(),
1158            next_epoch_commission_rate: v.next_epoch_commission_rate(),
1159            staking_pool_id: v
1160                .staking_pool()
1161                .id()
1162                .parse()
1163                .map_err(|e| TryFromProtoError::invalid("staking_pool_id", e))?,
1164            staking_pool_activation_epoch: v.staking_pool().activation_epoch_opt(),
1165            staking_pool_deactivation_epoch: v.staking_pool().deactivation_epoch_opt(),
1166            staking_pool_sui_balance: v.staking_pool().sui_balance(),
1167            rewards_pool: v.staking_pool().rewards_pool(),
1168            pool_token_balance: v.staking_pool().pool_token_balance(),
1169            pending_stake: v.staking_pool().pending_stake(),
1170            pending_total_sui_withdraw: v.staking_pool().pending_total_sui_withdraw(),
1171            pending_pool_token_withdraw: v.staking_pool().pending_pool_token_withdraw(),
1172            exchange_rates_id: v
1173                .staking_pool()
1174                .exchange_rates()
1175                .id()
1176                .parse()
1177                .map_err(|e| TryFromProtoError::invalid("exchange_rates_id", e))?,
1178            exchange_rates_size: v.staking_pool().exchange_rates().size(),
1179        })
1180    }
1181}
1182
1183//
1184// ExecutionStatus
1185//
1186
1187impl From<crate::execution_status::ExecutionStatus> for ExecutionStatus {
1188    fn from(value: crate::execution_status::ExecutionStatus) -> Self {
1189        let mut message = Self::default();
1190        match value {
1191            crate::execution_status::ExecutionStatus::Success => {
1192                message.success = Some(true);
1193            }
1194            crate::execution_status::ExecutionStatus::Failure(
1195                crate::execution_status::ExecutionFailure { error, command },
1196            ) => {
1197                let description = if let Some(command) = command {
1198                    format!("{error:?} in command {command}")
1199                } else {
1200                    format!("{error:?}")
1201                };
1202                let mut error_message = ExecutionError::from(error);
1203                error_message.command = command.map(|i| i as u64);
1204                error_message.description = Some(description);
1205
1206                message.success = Some(false);
1207                message.error = Some(error_message);
1208            }
1209        }
1210
1211        message
1212    }
1213}
1214
1215//
1216// ExecutionError
1217//
1218
1219fn size_error(size: u64, max_size: u64) -> SizeError {
1220    let mut message = SizeError::default();
1221    message.size = Some(size);
1222    message.max_size = Some(max_size);
1223    message
1224}
1225
1226fn index_error(index: u32, secondary_idx: Option<u32>) -> IndexError {
1227    let mut message = IndexError::default();
1228    message.index = Some(index);
1229    message.subresult = secondary_idx;
1230    message
1231}
1232
1233impl From<crate::execution_status::ExecutionErrorKind> for ExecutionError {
1234    fn from(value: crate::execution_status::ExecutionErrorKind) -> Self {
1235        use crate::execution_status::ExecutionErrorKind as E;
1236        use execution_error::ErrorDetails;
1237        use execution_error::ExecutionErrorKind;
1238
1239        let mut message = Self::default();
1240
1241        let kind = match value {
1242            E::InsufficientGas => ExecutionErrorKind::InsufficientGas,
1243            E::InvalidGasObject => ExecutionErrorKind::InvalidGasObject,
1244            E::InvariantViolation => ExecutionErrorKind::InvariantViolation,
1245            E::FeatureNotYetSupported => ExecutionErrorKind::FeatureNotYetSupported,
1246            E::MoveObjectTooBig {
1247                object_size,
1248                max_object_size,
1249            } => {
1250                message.error_details = Some(ErrorDetails::SizeError(size_error(
1251                    object_size,
1252                    max_object_size,
1253                )));
1254                ExecutionErrorKind::ObjectTooBig
1255            }
1256            E::MovePackageTooBig {
1257                object_size,
1258                max_object_size,
1259            } => {
1260                message.error_details = Some(ErrorDetails::SizeError(size_error(
1261                    object_size,
1262                    max_object_size,
1263                )));
1264                ExecutionErrorKind::PackageTooBig
1265            }
1266            E::CircularObjectOwnership { object } => {
1267                message.error_details =
1268                    Some(ErrorDetails::ObjectId(object.to_canonical_string(true)));
1269                ExecutionErrorKind::CircularObjectOwnership
1270            }
1271            E::InsufficientCoinBalance => ExecutionErrorKind::InsufficientCoinBalance,
1272            E::CoinBalanceOverflow => ExecutionErrorKind::CoinBalanceOverflow,
1273            E::PublishErrorNonZeroAddress => ExecutionErrorKind::PublishErrorNonZeroAddress,
1274            E::SuiMoveVerificationError => ExecutionErrorKind::SuiMoveVerificationError,
1275            E::MovePrimitiveRuntimeError(location) => {
1276                message.error_details = location.0.map(|l| {
1277                    let mut abort = MoveAbort::default();
1278                    abort.location = Some(l.into());
1279                    ErrorDetails::Abort(abort)
1280                });
1281                ExecutionErrorKind::MovePrimitiveRuntimeError
1282            }
1283            E::MoveAbort(location, code) => {
1284                let mut abort = MoveAbort::default();
1285                abort.abort_code = Some(code);
1286                abort.location = Some(location.into());
1287                message.error_details = Some(ErrorDetails::Abort(abort));
1288                ExecutionErrorKind::MoveAbort
1289            }
1290            E::VMVerificationOrDeserializationError => {
1291                ExecutionErrorKind::VmVerificationOrDeserializationError
1292            }
1293            E::VMInvariantViolation => ExecutionErrorKind::VmInvariantViolation,
1294            E::FunctionNotFound => ExecutionErrorKind::FunctionNotFound,
1295            E::ArityMismatch => ExecutionErrorKind::ArityMismatch,
1296            E::TypeArityMismatch => ExecutionErrorKind::TypeArityMismatch,
1297            E::NonEntryFunctionInvoked => ExecutionErrorKind::NonEntryFunctionInvoked,
1298            E::CommandArgumentError { arg_idx, kind } => {
1299                let mut command_argument_error = CommandArgumentError::from(kind);
1300                command_argument_error.argument = Some(arg_idx.into());
1301                message.error_details =
1302                    Some(ErrorDetails::CommandArgumentError(command_argument_error));
1303                ExecutionErrorKind::CommandArgumentError
1304            }
1305            E::TypeArgumentError { argument_idx, kind } => {
1306                let mut type_argument_error = TypeArgumentError::default();
1307                type_argument_error.type_argument = Some(argument_idx.into());
1308                type_argument_error.kind =
1309                    Some(type_argument_error::TypeArgumentErrorKind::from(kind).into());
1310                message.error_details = Some(ErrorDetails::TypeArgumentError(type_argument_error));
1311                ExecutionErrorKind::TypeArgumentError
1312            }
1313            E::UnusedValueWithoutDrop {
1314                result_idx,
1315                secondary_idx,
1316            } => {
1317                message.error_details = Some(ErrorDetails::IndexError(index_error(
1318                    result_idx.into(),
1319                    Some(secondary_idx.into()),
1320                )));
1321                ExecutionErrorKind::UnusedValueWithoutDrop
1322            }
1323            E::InvalidPublicFunctionReturnType { idx } => {
1324                message.error_details =
1325                    Some(ErrorDetails::IndexError(index_error(idx.into(), None)));
1326                ExecutionErrorKind::InvalidPublicFunctionReturnType
1327            }
1328            E::InvalidTransferObject => ExecutionErrorKind::InvalidTransferObject,
1329            E::EffectsTooLarge {
1330                current_size,
1331                max_size,
1332            } => {
1333                message.error_details =
1334                    Some(ErrorDetails::SizeError(size_error(current_size, max_size)));
1335                ExecutionErrorKind::EffectsTooLarge
1336            }
1337            E::PublishUpgradeMissingDependency => {
1338                ExecutionErrorKind::PublishUpgradeMissingDependency
1339            }
1340            E::PublishUpgradeDependencyDowngrade => {
1341                ExecutionErrorKind::PublishUpgradeDependencyDowngrade
1342            }
1343            E::PackageUpgradeError { upgrade_error } => {
1344                message.error_details =
1345                    Some(ErrorDetails::PackageUpgradeError(upgrade_error.into()));
1346                ExecutionErrorKind::PackageUpgradeError
1347            }
1348            E::WrittenObjectsTooLarge {
1349                current_size,
1350                max_size,
1351            } => {
1352                message.error_details =
1353                    Some(ErrorDetails::SizeError(size_error(current_size, max_size)));
1354
1355                ExecutionErrorKind::WrittenObjectsTooLarge
1356            }
1357            E::CertificateDenied => ExecutionErrorKind::CertificateDenied,
1358            E::SuiMoveVerificationTimedout => ExecutionErrorKind::SuiMoveVerificationTimedout,
1359            E::SharedObjectOperationNotAllowed => {
1360                ExecutionErrorKind::ConsensusObjectOperationNotAllowed
1361            }
1362            E::InputObjectDeleted => ExecutionErrorKind::InputObjectDeleted,
1363            E::ExecutionCancelledDueToSharedObjectCongestion { congested_objects } => {
1364                message.error_details = Some(ErrorDetails::CongestedObjects({
1365                    let mut message = CongestedObjects::default();
1366                    message.objects = congested_objects
1367                        .0
1368                        .iter()
1369                        .map(|o| o.to_canonical_string(true))
1370                        .collect();
1371                    message
1372                }));
1373
1374                ExecutionErrorKind::ExecutionCanceledDueToConsensusObjectCongestion
1375            }
1376            E::AddressDeniedForCoin { address, coin_type } => {
1377                message.error_details = Some(ErrorDetails::CoinDenyListError({
1378                    let mut message = CoinDenyListError::default();
1379                    message.address = Some(address.to_string());
1380                    message.coin_type = Some(coin_type);
1381                    message
1382                }));
1383                ExecutionErrorKind::AddressDeniedForCoin
1384            }
1385            E::CoinTypeGlobalPause { coin_type } => {
1386                message.error_details = Some(ErrorDetails::CoinDenyListError({
1387                    let mut message = CoinDenyListError::default();
1388                    message.coin_type = Some(coin_type);
1389                    message
1390                }));
1391                ExecutionErrorKind::CoinTypeGlobalPause
1392            }
1393            E::ExecutionCancelledDueToRandomnessUnavailable => {
1394                ExecutionErrorKind::ExecutionCanceledDueToRandomnessUnavailable
1395            }
1396            E::MoveVectorElemTooBig {
1397                value_size,
1398                max_scaled_size,
1399            } => {
1400                message.error_details = Some(ErrorDetails::SizeError(size_error(
1401                    value_size,
1402                    max_scaled_size,
1403                )));
1404
1405                ExecutionErrorKind::MoveVectorElemTooBig
1406            }
1407            E::MoveRawValueTooBig {
1408                value_size,
1409                max_scaled_size,
1410            } => {
1411                message.error_details = Some(ErrorDetails::SizeError(size_error(
1412                    value_size,
1413                    max_scaled_size,
1414                )));
1415                ExecutionErrorKind::MoveRawValueTooBig
1416            }
1417            E::InvalidLinkage => ExecutionErrorKind::InvalidLinkage,
1418            E::InsufficientFundsForWithdraw => ExecutionErrorKind::InsufficientFundsForWithdraw,
1419            E::NonExclusiveWriteInputObjectModified { id } => {
1420                message.set_object_id(id.to_canonical_string(true));
1421                ExecutionErrorKind::NonExclusiveWriteInputObjectModified
1422            }
1423        };
1424
1425        message.set_kind(kind);
1426        message
1427    }
1428}
1429
1430//
1431// CommandArgumentError
1432//
1433
1434impl From<crate::execution_status::CommandArgumentError> for CommandArgumentError {
1435    fn from(value: crate::execution_status::CommandArgumentError) -> Self {
1436        use crate::execution_status::CommandArgumentError as E;
1437        use command_argument_error::CommandArgumentErrorKind;
1438
1439        let mut message = Self::default();
1440
1441        let kind = match value {
1442            E::TypeMismatch => CommandArgumentErrorKind::TypeMismatch,
1443            E::InvalidBCSBytes => CommandArgumentErrorKind::InvalidBcsBytes,
1444            E::InvalidUsageOfPureArg => CommandArgumentErrorKind::InvalidUsageOfPureArgument,
1445            E::InvalidArgumentToPrivateEntryFunction => {
1446                CommandArgumentErrorKind::InvalidArgumentToPrivateEntryFunction
1447            }
1448            E::IndexOutOfBounds { idx } => {
1449                message.index_error = Some(index_error(idx.into(), None));
1450                CommandArgumentErrorKind::IndexOutOfBounds
1451            }
1452            E::SecondaryIndexOutOfBounds {
1453                result_idx,
1454                secondary_idx,
1455            } => {
1456                message.index_error =
1457                    Some(index_error(result_idx.into(), Some(secondary_idx.into())));
1458                CommandArgumentErrorKind::SecondaryIndexOutOfBounds
1459            }
1460            E::InvalidResultArity { result_idx } => {
1461                message.index_error = Some(index_error(result_idx.into(), None));
1462                CommandArgumentErrorKind::InvalidResultArity
1463            }
1464            E::InvalidGasCoinUsage => CommandArgumentErrorKind::InvalidGasCoinUsage,
1465            E::InvalidValueUsage => CommandArgumentErrorKind::InvalidValueUsage,
1466            E::InvalidObjectByValue => CommandArgumentErrorKind::InvalidObjectByValue,
1467            E::InvalidObjectByMutRef => CommandArgumentErrorKind::InvalidObjectByMutRef,
1468            E::SharedObjectOperationNotAllowed => {
1469                CommandArgumentErrorKind::ConsensusObjectOperationNotAllowed
1470            }
1471            E::InvalidArgumentArity => CommandArgumentErrorKind::InvalidArgumentArity,
1472
1473            E::InvalidTransferObject => CommandArgumentErrorKind::InvalidTransferObject,
1474            E::InvalidMakeMoveVecNonObjectArgument => {
1475                CommandArgumentErrorKind::InvalidMakeMoveVecNonObjectArgument
1476            }
1477            E::ArgumentWithoutValue => CommandArgumentErrorKind::ArgumentWithoutValue,
1478            E::CannotMoveBorrowedValue => CommandArgumentErrorKind::CannotMoveBorrowedValue,
1479            E::CannotWriteToExtendedReference => {
1480                CommandArgumentErrorKind::CannotWriteToExtendedReference
1481            }
1482            E::InvalidReferenceArgument => CommandArgumentErrorKind::InvalidReferenceArgument,
1483            E::InvalidTxContext => CommandArgumentErrorKind::InvalidTxContext,
1484        };
1485
1486        message.set_kind(kind);
1487        message
1488    }
1489}
1490
1491//
1492// TypeArgumentError
1493//
1494
1495impl From<crate::execution_status::TypeArgumentError>
1496    for type_argument_error::TypeArgumentErrorKind
1497{
1498    fn from(value: crate::execution_status::TypeArgumentError) -> Self {
1499        use crate::execution_status::TypeArgumentError::*;
1500
1501        match value {
1502            TypeNotFound => Self::TypeNotFound,
1503            ConstraintNotSatisfied => Self::ConstraintNotSatisfied,
1504        }
1505    }
1506}
1507
1508//
1509// PackageUpgradeError
1510//
1511
1512impl From<crate::execution_status::PackageUpgradeError> for PackageUpgradeError {
1513    fn from(value: crate::execution_status::PackageUpgradeError) -> Self {
1514        use crate::execution_status::PackageUpgradeError as E;
1515        use package_upgrade_error::PackageUpgradeErrorKind;
1516
1517        let mut message = Self::default();
1518
1519        let kind = match value {
1520            E::UnableToFetchPackage { package_id } => {
1521                message.package_id = Some(package_id.to_canonical_string(true));
1522                PackageUpgradeErrorKind::UnableToFetchPackage
1523            }
1524            E::NotAPackage { object_id } => {
1525                message.package_id = Some(object_id.to_canonical_string(true));
1526                PackageUpgradeErrorKind::NotAPackage
1527            }
1528            E::IncompatibleUpgrade => PackageUpgradeErrorKind::IncompatibleUpgrade,
1529            E::DigestDoesNotMatch { digest } => {
1530                message.digest = crate::digests::Digest::try_from(digest)
1531                    .ok()
1532                    .map(|d| d.to_string());
1533                PackageUpgradeErrorKind::DigestDoesNotMatch
1534            }
1535            E::UnknownUpgradePolicy { policy } => {
1536                message.policy = Some(policy.into());
1537                PackageUpgradeErrorKind::UnknownUpgradePolicy
1538            }
1539            E::PackageIDDoesNotMatch {
1540                package_id,
1541                ticket_id,
1542            } => {
1543                message.package_id = Some(package_id.to_canonical_string(true));
1544                message.ticket_id = Some(ticket_id.to_canonical_string(true));
1545                PackageUpgradeErrorKind::PackageIdDoesNotMatch
1546            }
1547        };
1548
1549        message.set_kind(kind);
1550        message
1551    }
1552}
1553
1554//
1555// MoveLocation
1556//
1557
1558impl From<crate::execution_status::MoveLocation> for MoveLocation {
1559    fn from(value: crate::execution_status::MoveLocation) -> Self {
1560        let mut message = Self::default();
1561        message.package = Some(value.module.address().to_canonical_string(true));
1562        message.module = Some(value.module.name().to_string());
1563        message.function = Some(value.function.into());
1564        message.instruction = Some(value.instruction.into());
1565        message.function_name = value.function_name.map(|name| name.to_string());
1566        message
1567    }
1568}
1569
1570//
1571// AuthorityQuorumSignInfo aka ValidatorAggregatedSignature
1572//
1573
1574impl<const T: bool> From<crate::crypto::AuthorityQuorumSignInfo<T>>
1575    for ValidatorAggregatedSignature
1576{
1577    fn from(value: crate::crypto::AuthorityQuorumSignInfo<T>) -> Self {
1578        let mut bitmap = Vec::new();
1579        value.signers_map.serialize_into(&mut bitmap).unwrap();
1580
1581        Self::default()
1582            .with_epoch(value.epoch)
1583            .with_signature(value.signature.as_ref().to_vec())
1584            .with_bitmap(bitmap)
1585    }
1586}
1587
1588impl<const T: bool> TryFrom<&ValidatorAggregatedSignature>
1589    for crate::crypto::AuthorityQuorumSignInfo<T>
1590{
1591    type Error = TryFromProtoError;
1592
1593    fn try_from(value: &ValidatorAggregatedSignature) -> Result<Self, Self::Error> {
1594        Ok(Self {
1595            epoch: value.epoch(),
1596            signature: crate::crypto::AggregateAuthoritySignature::from_bytes(value.signature())
1597                .map_err(|e| TryFromProtoError::invalid("signature", e))?,
1598            signers_map: crate::sui_serde::deserialize_sui_bitmap(value.bitmap())
1599                .map_err(|e| TryFromProtoError::invalid("bitmap", e))?,
1600        })
1601    }
1602}
1603
1604//
1605// ValidatorCommittee
1606//
1607
1608impl From<crate::committee::Committee> for ValidatorCommittee {
1609    fn from(value: crate::committee::Committee) -> Self {
1610        let mut message = Self::default();
1611        message.epoch = Some(value.epoch);
1612        message.members = value
1613            .voting_rights
1614            .into_iter()
1615            .map(|(name, weight)| {
1616                let mut member = ValidatorCommitteeMember::default();
1617                member.public_key = Some(name.0.to_vec().into());
1618                member.weight = Some(weight);
1619                member
1620            })
1621            .collect();
1622        message
1623    }
1624}
1625
1626impl TryFrom<&ValidatorCommittee> for crate::committee::Committee {
1627    type Error = TryFromProtoError;
1628
1629    fn try_from(s: &ValidatorCommittee) -> Result<Self, Self::Error> {
1630        let members = s
1631            .members()
1632            .iter()
1633            .map(|member| {
1634                let public_key =
1635                    crate::crypto::AuthorityPublicKeyBytes::from_bytes(member.public_key())
1636                        .map_err(|e| TryFromProtoError::invalid("public_key", e))?;
1637                Ok((public_key, member.weight()))
1638            })
1639            .collect::<Result<_, _>>()?;
1640        Ok(Self::new(s.epoch(), members))
1641    }
1642}
1643
1644//
1645// ZkLoginAuthenticator
1646//
1647
1648impl From<&crate::zk_login_authenticator::ZkLoginAuthenticator> for ZkLoginAuthenticator {
1649    fn from(value: &crate::zk_login_authenticator::ZkLoginAuthenticator) -> Self {
1650        //TODO implement this without going through the sdk type
1651        let mut inputs = ZkLoginInputs::default();
1652        inputs.address_seed = Some(value.inputs.get_address_seed().to_string());
1653        let mut message = Self::default();
1654        message.inputs = Some(inputs);
1655        message.max_epoch = Some(value.get_max_epoch());
1656        message.signature = Some(value.user_signature.clone().into());
1657
1658        sui_sdk_types::ZkLoginAuthenticator::try_from(value.clone())
1659            .map(Into::into)
1660            .ok()
1661            .unwrap_or(message)
1662    }
1663}
1664
1665//
1666// ZkLoginPublicIdentifier
1667//
1668
1669impl From<&crate::crypto::ZkLoginPublicIdentifier> for ZkLoginPublicIdentifier {
1670    fn from(value: &crate::crypto::ZkLoginPublicIdentifier) -> Self {
1671        //TODO implement this without going through the sdk type
1672        sui_sdk_types::ZkLoginPublicIdentifier::try_from(value.to_owned())
1673            .map(|id| (&id).into())
1674            .ok()
1675            .unwrap_or_default()
1676    }
1677}
1678
1679//
1680// SignatureScheme
1681//
1682
1683impl From<crate::crypto::SignatureScheme> for SignatureScheme {
1684    fn from(value: crate::crypto::SignatureScheme) -> Self {
1685        use crate::crypto::SignatureScheme as S;
1686
1687        match value {
1688            S::ED25519 => Self::Ed25519,
1689            S::Secp256k1 => Self::Secp256k1,
1690            S::Secp256r1 => Self::Secp256r1,
1691            S::BLS12381 => Self::Bls12381,
1692            S::MultiSig => Self::Multisig,
1693            S::ZkLoginAuthenticator => Self::Zklogin,
1694            S::PasskeyAuthenticator => Self::Passkey,
1695            S::MLDSA65 => Self::Mldsa65,
1696        }
1697    }
1698}
1699
1700//
1701// SimpleSignature
1702//
1703
1704impl From<crate::crypto::Signature> for SimpleSignature {
1705    fn from(value: crate::crypto::Signature) -> Self {
1706        Self::from(&value)
1707    }
1708}
1709
1710impl From<&crate::crypto::Signature> for SimpleSignature {
1711    fn from(value: &crate::crypto::Signature) -> Self {
1712        let signature = value.signature_bytes();
1713        let public_key = value.public_key_bytes();
1714
1715        let mut message = Self::default();
1716        message.set_scheme(value.scheme().into());
1717        message.signature = Some(signature.to_vec().into());
1718        message.public_key = Some(public_key.to_vec().into());
1719        message
1720    }
1721}
1722
1723//
1724// PasskeyAuthenticator
1725//
1726
1727impl From<&crate::passkey_authenticator::PasskeyAuthenticator> for PasskeyAuthenticator {
1728    fn from(value: &crate::passkey_authenticator::PasskeyAuthenticator) -> Self {
1729        let mut message = Self::default();
1730        message.authenticator_data = Some(value.authenticator_data().to_vec().into());
1731        message.client_data_json = Some(value.client_data_json().to_owned());
1732        message.signature = Some(value.signature().into());
1733        message
1734    }
1735}
1736
1737//
1738// MultisigMemberPublicKey
1739//
1740
1741impl From<&crate::crypto::PublicKey> for MultisigMemberPublicKey {
1742    fn from(value: &crate::crypto::PublicKey) -> Self {
1743        let mut message = Self::default();
1744
1745        match value {
1746            crate::crypto::PublicKey::Ed25519(_)
1747            | crate::crypto::PublicKey::Secp256k1(_)
1748            | crate::crypto::PublicKey::Secp256r1(_)
1749            | crate::crypto::PublicKey::Passkey(_)
1750            | crate::crypto::PublicKey::MLDSA65(_) => {
1751                message.public_key = Some(value.as_ref().to_vec().into());
1752            }
1753            crate::crypto::PublicKey::ZkLogin(z) => {
1754                message.zklogin = Some(z.into());
1755            }
1756        }
1757
1758        message.set_scheme(value.scheme().into());
1759        message
1760    }
1761}
1762
1763//
1764// MultisigCommittee
1765//
1766
1767impl From<&crate::multisig::MultiSigPublicKey> for MultisigCommittee {
1768    fn from(value: &crate::multisig::MultiSigPublicKey) -> Self {
1769        let mut message = Self::default();
1770        message.members = value
1771            .pubkeys()
1772            .iter()
1773            .map(|(pk, weight)| {
1774                let mut member = MultisigMember::default();
1775                member.public_key = Some(pk.into());
1776                member.weight = Some((*weight).into());
1777                member
1778            })
1779            .collect();
1780        message.threshold = Some((*value.threshold()).into());
1781        message
1782    }
1783}
1784
1785impl From<&crate::multisig_legacy::MultiSigPublicKeyLegacy> for MultisigCommittee {
1786    fn from(value: &crate::multisig_legacy::MultiSigPublicKeyLegacy) -> Self {
1787        let mut message = Self::default();
1788        message.members = value
1789            .pubkeys()
1790            .iter()
1791            .map(|(pk, weight)| {
1792                let mut member = MultisigMember::default();
1793                member.public_key = Some(pk.into());
1794                member.weight = Some((*weight).into());
1795                member
1796            })
1797            .collect();
1798        message.threshold = Some((*value.threshold()).into());
1799        message
1800    }
1801}
1802
1803//
1804// MultisigMemberSignature
1805//
1806
1807impl From<&crate::crypto::CompressedSignature> for MultisigMemberSignature {
1808    fn from(value: &crate::crypto::CompressedSignature) -> Self {
1809        let mut message = Self::default();
1810
1811        let scheme = match value {
1812            crate::crypto::CompressedSignature::Ed25519(b) => {
1813                message.signature = Some(b.0.to_vec().into());
1814                Some(SignatureScheme::Ed25519)
1815            }
1816            crate::crypto::CompressedSignature::Secp256k1(b) => {
1817                message.signature = Some(b.0.to_vec().into());
1818                Some(SignatureScheme::Secp256k1)
1819            }
1820            crate::crypto::CompressedSignature::Secp256r1(b) => {
1821                message.signature = Some(b.0.to_vec().into());
1822                Some(SignatureScheme::Secp256r1)
1823            }
1824            crate::crypto::CompressedSignature::ZkLogin(_z) => {
1825                //TODO
1826                Some(SignatureScheme::Zklogin)
1827            }
1828            crate::crypto::CompressedSignature::Passkey(_p) => {
1829                //TODO
1830                Some(SignatureScheme::Passkey)
1831            }
1832            crate::crypto::CompressedSignature::MLDSA65(b) => {
1833                message.signature = Some(b.0.to_vec().into());
1834                Some(SignatureScheme::Mldsa65)
1835            }
1836        };
1837
1838        if let Some(scheme) = scheme {
1839            message.set_scheme(scheme);
1840        }
1841        message
1842    }
1843}
1844
1845//
1846// MultisigAggregatedSignature
1847//
1848
1849impl From<&crate::multisig_legacy::MultiSigLegacy> for MultisigAggregatedSignature {
1850    fn from(value: &crate::multisig_legacy::MultiSigLegacy) -> Self {
1851        let mut legacy_bitmap = Vec::new();
1852        value
1853            .get_bitmap()
1854            .serialize_into(&mut legacy_bitmap)
1855            .unwrap();
1856
1857        Self::default()
1858            .with_signatures(value.get_sigs().iter().map(Into::into).collect())
1859            .with_legacy_bitmap(legacy_bitmap)
1860            .with_committee(value.get_pk())
1861    }
1862}
1863
1864impl From<&crate::multisig::MultiSig> for MultisigAggregatedSignature {
1865    fn from(value: &crate::multisig::MultiSig) -> Self {
1866        let mut message = Self::default();
1867        message.signatures = value.get_sigs().iter().map(Into::into).collect();
1868        message.bitmap = Some(value.get_bitmap().into());
1869        message.committee = Some(value.get_pk().into());
1870        message
1871    }
1872}
1873
1874//
1875// UserSignature
1876//
1877
1878impl From<&crate::signature::GenericSignature> for UserSignature {
1879    fn from(value: &crate::signature::GenericSignature) -> Self {
1880        Self::merge_from(value, &FieldMaskTree::new_wildcard())
1881    }
1882}
1883
1884impl Merge<&crate::signature::GenericSignature> for UserSignature {
1885    fn merge(&mut self, source: &crate::signature::GenericSignature, mask: &FieldMaskTree) {
1886        use user_signature::Signature;
1887
1888        if mask.contains(Self::BCS_FIELD) {
1889            let mut bcs = Bcs::from(source.as_ref().to_vec());
1890            bcs.name = Some("UserSignatureBytes".to_owned());
1891            self.bcs = Some(bcs);
1892        }
1893
1894        let scheme = match source {
1895            crate::signature::GenericSignature::MultiSig(multi_sig) => {
1896                if mask.contains(Self::MULTISIG_FIELD) {
1897                    self.signature = Some(Signature::Multisig(multi_sig.into()));
1898                }
1899                Some(SignatureScheme::Multisig)
1900            }
1901            crate::signature::GenericSignature::MultiSigLegacy(multi_sig_legacy) => {
1902                if mask.contains(Self::MULTISIG_FIELD) {
1903                    self.signature = Some(Signature::Multisig(multi_sig_legacy.into()));
1904                }
1905                Some(SignatureScheme::Multisig)
1906            }
1907            crate::signature::GenericSignature::Signature(signature) => {
1908                let scheme = Some(SignatureScheme::from(signature.scheme()));
1909                if mask.contains(Self::SIMPLE_FIELD) {
1910                    self.signature = Some(Signature::Simple(signature.into()));
1911                }
1912                scheme
1913            }
1914            crate::signature::GenericSignature::ZkLoginAuthenticator(z) => {
1915                if mask.contains(Self::ZKLOGIN_FIELD) {
1916                    self.signature = Some(Signature::Zklogin(z.into()));
1917                }
1918                Some(SignatureScheme::Zklogin)
1919            }
1920            crate::signature::GenericSignature::PasskeyAuthenticator(p) => {
1921                if mask.contains(Self::PASSKEY_FIELD) {
1922                    self.signature = Some(Signature::Passkey(p.into()));
1923                }
1924                Some(SignatureScheme::Passkey)
1925            }
1926        };
1927
1928        if mask.contains(Self::SCHEME_FIELD)
1929            && let Some(scheme) = scheme
1930        {
1931            self.set_scheme(scheme);
1932        }
1933    }
1934}
1935
1936//
1937// BalanceChange
1938//
1939
1940impl From<crate::balance_change::BalanceChange> for BalanceChange {
1941    fn from(value: crate::balance_change::BalanceChange) -> Self {
1942        let mut message = Self::default();
1943        message.address = Some(value.address.to_string());
1944        message.coin_type = Some(value.coin_type.to_canonical_string(true));
1945        message.amount = Some(value.amount.to_string());
1946        message
1947    }
1948}
1949
1950impl TryFrom<&BalanceChange> for crate::balance_change::BalanceChange {
1951    type Error = TryFromProtoError;
1952
1953    fn try_from(value: &BalanceChange) -> Result<Self, Self::Error> {
1954        Ok(Self {
1955            address: value
1956                .address()
1957                .parse()
1958                .map_err(|e| TryFromProtoError::invalid(BalanceChange::ADDRESS_FIELD, e))?,
1959            coin_type: value
1960                .coin_type()
1961                .parse()
1962                .map_err(|e| TryFromProtoError::invalid(BalanceChange::COIN_TYPE_FIELD, e))?,
1963            amount: value
1964                .amount()
1965                .parse()
1966                .map_err(|e| TryFromProtoError::invalid(BalanceChange::AMOUNT_FIELD, e))?,
1967        })
1968    }
1969}
1970
1971//
1972// Object
1973//
1974
1975pub const PACKAGE_TYPE: &str = "package";
1976
1977impl From<crate::object::Object> for Object {
1978    fn from(value: crate::object::Object) -> Self {
1979        Self::merge_from(&value, &FieldMaskTree::new_wildcard())
1980    }
1981}
1982
1983impl Merge<&crate::object::Object> for Object {
1984    fn merge(&mut self, source: &crate::object::Object, mask: &FieldMaskTree) {
1985        if mask.contains(Self::BCS_FIELD.name) {
1986            let mut bcs = Bcs::serialize(&source).unwrap();
1987            bcs.name = Some("Object".to_owned());
1988            self.bcs = Some(bcs);
1989        }
1990
1991        if mask.contains(Self::DIGEST_FIELD.name) {
1992            self.digest = Some(source.digest().to_string());
1993        }
1994
1995        if mask.contains(Self::OBJECT_ID_FIELD.name) {
1996            self.object_id = Some(source.id().to_canonical_string(true));
1997        }
1998
1999        if mask.contains(Self::VERSION_FIELD.name) {
2000            self.version = Some(source.version().value());
2001        }
2002
2003        if mask.contains(Self::OWNER_FIELD.name) {
2004            self.owner = Some(source.owner().to_owned().into());
2005        }
2006
2007        if mask.contains(Self::PREVIOUS_TRANSACTION_FIELD.name) {
2008            self.previous_transaction = Some(source.previous_transaction.to_string());
2009        }
2010
2011        if mask.contains(Self::STORAGE_REBATE_FIELD.name) {
2012            self.storage_rebate = Some(source.storage_rebate);
2013        }
2014
2015        if mask.contains(Self::BALANCE_FIELD) {
2016            self.balance = source.as_coin_maybe().map(|coin| coin.balance.value());
2017        }
2018
2019        self.merge(&source.data, mask);
2020    }
2021}
2022
2023impl Merge<&crate::object::MoveObject> for Object {
2024    fn merge(&mut self, source: &crate::object::MoveObject, mask: &FieldMaskTree) {
2025        self.object_id = Some(source.id().to_canonical_string(true));
2026        self.version = Some(source.version().value());
2027
2028        if mask.contains(Self::OBJECT_TYPE_FIELD.name) {
2029            self.object_type = Some(source.type_().to_canonical_string(true));
2030        }
2031
2032        if mask.contains(Self::HAS_PUBLIC_TRANSFER_FIELD.name) {
2033            self.has_public_transfer = Some(source.has_public_transfer());
2034        }
2035
2036        if mask.contains(Self::CONTENTS_FIELD.name) {
2037            let mut bcs = Bcs::from(source.contents().to_vec());
2038            bcs.name = Some(source.type_().to_canonical_string(true));
2039            self.contents = Some(bcs);
2040        }
2041    }
2042}
2043
2044impl Merge<&crate::move_package::MovePackage> for Object {
2045    fn merge(&mut self, source: &crate::move_package::MovePackage, mask: &FieldMaskTree) {
2046        self.object_id = Some(source.id().to_canonical_string(true));
2047        self.version = Some(source.version().value());
2048
2049        if mask.contains(Self::OBJECT_TYPE_FIELD.name) {
2050            self.object_type = Some(PACKAGE_TYPE.to_owned());
2051        }
2052
2053        if mask.contains(Self::PACKAGE_FIELD.name) {
2054            let mut package = Package::default();
2055            package.modules = source
2056                .serialized_module_map()
2057                .iter()
2058                .map(|(name, contents)| {
2059                    let mut module = Module::default();
2060                    module.name = Some(name.to_string());
2061                    module.contents = Some(contents.clone().into());
2062                    module
2063                })
2064                .collect();
2065            package.type_origins = source
2066                .type_origin_table()
2067                .clone()
2068                .into_iter()
2069                .map(Into::into)
2070                .collect();
2071            package.linkage = source
2072                .linkage_table()
2073                .iter()
2074                .map(
2075                    |(
2076                        original_id,
2077                        crate::move_package::UpgradeInfo {
2078                            upgraded_id,
2079                            upgraded_version,
2080                        },
2081                    )| {
2082                        let mut linkage = Linkage::default();
2083                        linkage.original_id = Some(original_id.to_canonical_string(true));
2084                        linkage.upgraded_id = Some(upgraded_id.to_canonical_string(true));
2085                        linkage.upgraded_version = Some(upgraded_version.value());
2086                        linkage
2087                    },
2088                )
2089                .collect();
2090
2091            self.package = Some(package);
2092        }
2093    }
2094}
2095
2096impl Merge<&crate::object::Data> for Object {
2097    fn merge(&mut self, source: &crate::object::Data, mask: &FieldMaskTree) {
2098        match source {
2099            crate::object::Data::Move(object) => self.merge(object, mask),
2100            crate::object::Data::Package(package) => self.merge(package, mask),
2101        }
2102    }
2103}
2104
2105//
2106// TypeOrigin
2107//
2108
2109impl From<crate::move_package::TypeOrigin> for TypeOrigin {
2110    fn from(value: crate::move_package::TypeOrigin) -> Self {
2111        let mut message = Self::default();
2112        message.module_name = Some(value.module_name.to_string());
2113        message.datatype_name = Some(value.datatype_name.to_string());
2114        message.package_id = Some(value.package.to_canonical_string(true));
2115        message
2116    }
2117}
2118
2119//
2120// GenesisObject
2121//
2122
2123impl From<crate::transaction::GenesisObject> for Object {
2124    fn from(value: crate::transaction::GenesisObject) -> Self {
2125        let crate::transaction::GenesisObject::RawObject { data, owner } = value;
2126        let mut message = Self::default();
2127        message.owner = Some(owner.into());
2128
2129        message.merge(&data, &FieldMaskTree::new_wildcard());
2130
2131        message
2132    }
2133}
2134
2135//
2136// ObjectReference
2137//
2138
2139pub trait ObjectRefExt {
2140    fn to_proto(self) -> ObjectReference;
2141}
2142
2143pub trait ObjectReferenceExt {
2144    fn try_to_object_ref(&self) -> Result<crate::base_types::ObjectRef, anyhow::Error>;
2145}
2146
2147impl ObjectRefExt for crate::base_types::ObjectRef {
2148    fn to_proto(self) -> ObjectReference {
2149        let (object_id, version, digest) = self;
2150        let mut message = ObjectReference::default();
2151        message.object_id = Some(object_id.to_canonical_string(true));
2152        message.version = Some(version.value());
2153        message.digest = Some(digest.to_string());
2154        message
2155    }
2156}
2157
2158impl ObjectReferenceExt for ObjectReference {
2159    fn try_to_object_ref(&self) -> Result<crate::base_types::ObjectRef, anyhow::Error> {
2160        use anyhow::Context;
2161
2162        let object_id = self
2163            .object_id_opt()
2164            .ok_or_else(|| anyhow::anyhow!("missing object_id"))?;
2165        let object_id = crate::base_types::ObjectID::from_hex_literal(object_id)
2166            .with_context(|| format!("Failed to parse object_id: {}", object_id))?;
2167
2168        let version = self
2169            .version_opt()
2170            .ok_or_else(|| anyhow::anyhow!("missing version"))?;
2171        let version = crate::base_types::SequenceNumber::from(version);
2172
2173        let digest = self
2174            .digest_opt()
2175            .ok_or_else(|| anyhow::anyhow!("missing digest"))?;
2176        let digest = digest
2177            .parse::<crate::digests::ObjectDigest>()
2178            .with_context(|| format!("Failed to parse digest: {}", digest))?;
2179
2180        Ok((object_id, version, digest))
2181    }
2182}
2183
2184impl From<&crate::storage::ObjectKey> for ObjectReference {
2185    fn from(value: &crate::storage::ObjectKey) -> Self {
2186        Self::default()
2187            .with_object_id(value.0.to_canonical_string(true))
2188            .with_version(value.1.value())
2189    }
2190}
2191
2192//
2193// Owner
2194//
2195
2196impl From<crate::object::Owner> for Owner {
2197    fn from(value: crate::object::Owner) -> Self {
2198        use crate::object::Owner as O;
2199        use owner::OwnerKind;
2200
2201        let mut message = Self::default();
2202
2203        let kind = match value {
2204            O::AddressOwner(address) => {
2205                message.address = Some(address.to_string());
2206                OwnerKind::Address
2207            }
2208            O::ObjectOwner(address) => {
2209                message.address = Some(address.to_string());
2210                OwnerKind::Object
2211            }
2212            O::Shared {
2213                initial_shared_version,
2214            } => {
2215                message.version = Some(initial_shared_version.value());
2216                OwnerKind::Shared
2217            }
2218            O::Immutable => OwnerKind::Immutable,
2219            O::ConsensusAddressOwner {
2220                start_version,
2221                owner,
2222            } => {
2223                message.version = Some(start_version.value());
2224                message.address = Some(owner.to_string());
2225                OwnerKind::ConsensusAddress
2226            }
2227            // TODO(Party WIP)
2228            O::Party { .. } => todo!("Party WIP"),
2229        };
2230
2231        message.set_kind(kind);
2232        message
2233    }
2234}
2235
2236//
2237// Transaction
2238//
2239
2240impl From<crate::transaction::TransactionData> for Transaction {
2241    fn from(value: crate::transaction::TransactionData) -> Self {
2242        Self::merge_from(&value, &FieldMaskTree::new_wildcard())
2243    }
2244}
2245
2246impl Merge<&crate::transaction::TransactionData> for Transaction {
2247    fn merge(&mut self, source: &crate::transaction::TransactionData, mask: &FieldMaskTree) {
2248        merge_transaction_data(self, source, None, mask);
2249    }
2250}
2251
2252fn merge_transaction_data(
2253    message: &mut Transaction,
2254    source: &crate::transaction::TransactionData,
2255    precomputed_digest_string: Option<String>,
2256    mask: &FieldMaskTree,
2257) {
2258    if mask.contains(Transaction::BCS_FIELD.name) {
2259        let mut bcs = Bcs::serialize(&source).unwrap();
2260        bcs.name = Some("TransactionData".to_owned());
2261        message.bcs = Some(bcs);
2262    }
2263
2264    if mask.contains(Transaction::DIGEST_FIELD.name) {
2265        message.digest =
2266            Some(precomputed_digest_string.unwrap_or_else(|| source.digest().base58_encode()));
2267    }
2268
2269    if mask.contains(Transaction::VERSION_FIELD.name) {
2270        message.version = Some(1);
2271    }
2272
2273    let crate::transaction::TransactionData::V1(source) = source;
2274
2275    if mask.contains(Transaction::KIND_FIELD.name) {
2276        message.kind = Some(source.kind.clone().into());
2277    }
2278
2279    if mask.contains(Transaction::SENDER_FIELD.name) {
2280        message.sender = Some(source.sender.to_string());
2281    }
2282
2283    if mask.contains(Transaction::GAS_PAYMENT_FIELD.name) {
2284        message.gas_payment = Some((&source.gas_data).into());
2285    }
2286
2287    if mask.contains(Transaction::EXPIRATION_FIELD.name) {
2288        message.expiration = Some(source.expiration.clone().into());
2289    }
2290}
2291
2292//
2293// GasPayment
2294//
2295
2296impl From<&crate::transaction::GasData> for GasPayment {
2297    fn from(value: &crate::transaction::GasData) -> Self {
2298        let mut message = Self::default();
2299        message.objects = value
2300            .payment
2301            .iter()
2302            .map(|obj_ref| obj_ref.to_proto())
2303            .collect();
2304        message.owner = Some(value.owner.to_string());
2305        message.price = Some(value.price);
2306        message.budget = Some(value.budget);
2307        message
2308    }
2309}
2310
2311//
2312// TransactionExpiration
2313//
2314
2315impl From<crate::transaction::TransactionExpiration> for TransactionExpiration {
2316    fn from(value: crate::transaction::TransactionExpiration) -> Self {
2317        use crate::transaction::TransactionExpiration as E;
2318        use transaction_expiration::TransactionExpirationKind;
2319
2320        let mut message = Self::default();
2321
2322        let kind = match value {
2323            E::None => TransactionExpirationKind::None,
2324            E::Epoch(epoch) => {
2325                message.epoch = Some(epoch);
2326                TransactionExpirationKind::Epoch
2327            }
2328            E::ValidDuring {
2329                min_epoch,
2330                max_epoch,
2331                min_timestamp,
2332                max_timestamp,
2333                chain,
2334                nonce,
2335            } => {
2336                message.epoch = max_epoch;
2337                message.min_epoch = min_epoch;
2338                message.min_timestamp = min_timestamp.map(ms_to_timestamp);
2339                message.max_timestamp = max_timestamp.map(ms_to_timestamp);
2340                message.set_chain(sui_sdk_types::Digest::new(*chain.as_bytes()));
2341                message.set_nonce(nonce);
2342
2343                TransactionExpirationKind::ValidDuring
2344            }
2345            E::Validity {
2346                min_epoch,
2347                max_epoch,
2348                min_timestamp,
2349                max_timestamp,
2350                chain,
2351                nonce,
2352                allowed_proposers,
2353            } => {
2354                message.epoch = max_epoch;
2355                message.min_epoch = min_epoch;
2356                message.min_timestamp = min_timestamp.map(ms_to_timestamp);
2357                message.max_timestamp = max_timestamp.map(ms_to_timestamp);
2358                message.set_chain(sui_sdk_types::Digest::new(*chain.as_bytes()));
2359                message.set_nonce(nonce);
2360                if let Some(allowed) = allowed_proposers {
2361                    let mut proposers = AllowedProposers::default();
2362                    proposers.set_epoch(allowed.epoch);
2363                    proposers.proposers = allowed.proposers.into();
2364                    message.set_allowed_proposers(proposers);
2365                }
2366
2367                TransactionExpirationKind::Validity
2368            }
2369        };
2370
2371        message.set_kind(kind);
2372        message
2373    }
2374}
2375
2376impl TryFrom<&TransactionExpiration> for crate::transaction::TransactionExpiration {
2377    type Error = &'static str;
2378
2379    fn try_from(value: &TransactionExpiration) -> Result<Self, Self::Error> {
2380        use transaction_expiration::TransactionExpirationKind;
2381
2382        Ok(match value.kind() {
2383            TransactionExpirationKind::None => Self::None,
2384            TransactionExpirationKind::Epoch => Self::Epoch(value.epoch()),
2385            kind @ (TransactionExpirationKind::ValidDuring
2386            | TransactionExpirationKind::Validity) => {
2387                let chain_str = value
2388                    .chain
2389                    .as_deref()
2390                    .ok_or("ValidDuring expiration is missing chain")?;
2391                let chain_digest: sui_sdk_types::Digest = chain_str
2392                    .parse()
2393                    .map_err(|_| "ValidDuring expiration has invalid chain digest")?;
2394                let chain = crate::digests::ChainIdentifier::from(
2395                    crate::digests::CheckpointDigest::new(chain_digest.into_inner()),
2396                );
2397                let nonce = value
2398                    .nonce
2399                    .ok_or("ValidDuring expiration is missing nonce")?;
2400                let min_timestamp = value
2401                    .min_timestamp
2402                    .as_ref()
2403                    .map(timestamp_to_ms)
2404                    .transpose()?;
2405                let max_timestamp = value
2406                    .max_timestamp
2407                    .as_ref()
2408                    .map(timestamp_to_ms)
2409                    .transpose()?;
2410                let min_epoch = value.min_epoch;
2411                let max_epoch = value.epoch;
2412
2413                if kind == TransactionExpirationKind::ValidDuring {
2414                    Self::ValidDuring {
2415                        min_epoch,
2416                        max_epoch,
2417                        min_timestamp,
2418                        max_timestamp,
2419                        chain,
2420                        nonce,
2421                    }
2422                } else {
2423                    let allowed_proposers = value
2424                        .allowed_proposers
2425                        .as_ref()
2426                        .map(|allowed| -> Result<_, Self::Error> {
2427                            Ok(crate::transaction::AllowedProposers {
2428                                epoch: allowed.epoch(),
2429                                proposers: NonEmpty::from_vec(allowed.proposers.clone())
2430                                    .ok_or("allowed_proposers must not be empty")?,
2431                            })
2432                        })
2433                        .transpose()?;
2434                    Self::Validity {
2435                        min_epoch,
2436                        max_epoch,
2437                        min_timestamp,
2438                        max_timestamp,
2439                        chain,
2440                        nonce,
2441                        allowed_proposers,
2442                    }
2443                }
2444            }
2445            TransactionExpirationKind::Unknown | _ => {
2446                return Err("unknown TransactionExpirationKind");
2447            }
2448        })
2449    }
2450}
2451
2452//
2453// TransactionKind
2454//
2455
2456impl From<crate::transaction::TransactionKind> for TransactionKind {
2457    fn from(value: crate::transaction::TransactionKind) -> Self {
2458        use crate::transaction::TransactionKind as K;
2459        use transaction_kind::Kind;
2460
2461        let message = Self::default();
2462
2463        match value {
2464            K::ProgrammableTransaction(ptb) => message
2465                .with_programmable_transaction(ptb)
2466                .with_kind(Kind::ProgrammableTransaction),
2467            K::ChangeEpoch(change_epoch) => message
2468                .with_change_epoch(change_epoch)
2469                .with_kind(Kind::ChangeEpoch),
2470            K::Genesis(genesis) => message.with_genesis(genesis).with_kind(Kind::Genesis),
2471            K::ConsensusCommitPrologue(prologue) => message
2472                .with_consensus_commit_prologue(prologue)
2473                .with_kind(Kind::ConsensusCommitPrologueV1),
2474            K::AuthenticatorStateUpdate(update) => message
2475                .with_authenticator_state_update(update)
2476                .with_kind(Kind::AuthenticatorStateUpdate),
2477            K::EndOfEpochTransaction(transactions) => message
2478                .with_end_of_epoch({
2479                    EndOfEpochTransaction::default()
2480                        .with_transactions(transactions.into_iter().map(Into::into).collect())
2481                })
2482                .with_kind(Kind::EndOfEpoch),
2483            K::RandomnessStateUpdate(update) => message
2484                .with_randomness_state_update(update)
2485                .with_kind(Kind::RandomnessStateUpdate),
2486            K::ConsensusCommitPrologueV2(prologue) => message
2487                .with_consensus_commit_prologue(prologue)
2488                .with_kind(Kind::ConsensusCommitPrologueV2),
2489            K::ConsensusCommitPrologueV3(prologue) => message
2490                .with_consensus_commit_prologue(prologue)
2491                .with_kind(Kind::ConsensusCommitPrologueV3),
2492            K::ConsensusCommitPrologueV4(prologue) => message
2493                .with_consensus_commit_prologue(prologue)
2494                .with_kind(Kind::ConsensusCommitPrologueV4),
2495            K::ProgrammableSystemTransaction(ptb) => message
2496                .with_programmable_transaction(ptb)
2497                .with_kind(Kind::ProgrammableSystemTransaction),
2498        }
2499    }
2500}
2501
2502//
2503// ConsensusCommitPrologue
2504//
2505
2506impl From<crate::messages_consensus::ConsensusCommitPrologue> for ConsensusCommitPrologue {
2507    fn from(value: crate::messages_consensus::ConsensusCommitPrologue) -> Self {
2508        let mut message = Self::default();
2509        message.epoch = Some(value.epoch);
2510        message.round = Some(value.round);
2511        message.commit_timestamp = Some(sui_rpc::proto::timestamp_ms_to_proto(
2512            value.commit_timestamp_ms,
2513        ));
2514        message
2515    }
2516}
2517
2518impl From<crate::messages_consensus::ConsensusCommitPrologueV2> for ConsensusCommitPrologue {
2519    fn from(value: crate::messages_consensus::ConsensusCommitPrologueV2) -> Self {
2520        let mut message = Self::default();
2521        message.epoch = Some(value.epoch);
2522        message.round = Some(value.round);
2523        message.commit_timestamp = Some(sui_rpc::proto::timestamp_ms_to_proto(
2524            value.commit_timestamp_ms,
2525        ));
2526        message.consensus_commit_digest = Some(value.consensus_commit_digest.to_string());
2527        message
2528    }
2529}
2530
2531impl From<crate::messages_consensus::ConsensusCommitPrologueV3> for ConsensusCommitPrologue {
2532    fn from(value: crate::messages_consensus::ConsensusCommitPrologueV3) -> Self {
2533        let mut message = Self::default();
2534        message.epoch = Some(value.epoch);
2535        message.round = Some(value.round);
2536        message.commit_timestamp = Some(sui_rpc::proto::timestamp_ms_to_proto(
2537            value.commit_timestamp_ms,
2538        ));
2539        message.consensus_commit_digest = Some(value.consensus_commit_digest.to_string());
2540        message.sub_dag_index = value.sub_dag_index;
2541        message.consensus_determined_version_assignments =
2542            Some(value.consensus_determined_version_assignments.into());
2543        message
2544    }
2545}
2546
2547impl From<crate::messages_consensus::ConsensusCommitPrologueV4> for ConsensusCommitPrologue {
2548    fn from(
2549        crate::messages_consensus::ConsensusCommitPrologueV4 {
2550            epoch,
2551            round,
2552            sub_dag_index,
2553            commit_timestamp_ms,
2554            consensus_commit_digest,
2555            consensus_determined_version_assignments,
2556            additional_state_digest,
2557        }: crate::messages_consensus::ConsensusCommitPrologueV4,
2558    ) -> Self {
2559        let mut message = Self::default();
2560        message.epoch = Some(epoch);
2561        message.round = Some(round);
2562        message.commit_timestamp = Some(sui_rpc::proto::timestamp_ms_to_proto(commit_timestamp_ms));
2563        message.consensus_commit_digest = Some(consensus_commit_digest.to_string());
2564        message.sub_dag_index = sub_dag_index;
2565        message.consensus_determined_version_assignments =
2566            Some(consensus_determined_version_assignments.into());
2567        message.additional_state_digest = Some(additional_state_digest.to_string());
2568        message
2569    }
2570}
2571
2572//
2573// ConsensusDeterminedVersionAssignments
2574//
2575
2576impl From<crate::messages_consensus::ConsensusDeterminedVersionAssignments>
2577    for ConsensusDeterminedVersionAssignments
2578{
2579    fn from(value: crate::messages_consensus::ConsensusDeterminedVersionAssignments) -> Self {
2580        use crate::messages_consensus::ConsensusDeterminedVersionAssignments as A;
2581
2582        let mut message = Self::default();
2583
2584        let version = match value {
2585            A::CancelledTransactions(canceled_transactions) => {
2586                message.canceled_transactions = canceled_transactions
2587                    .into_iter()
2588                    .map(|(tx_digest, assignments)| {
2589                        let mut message = CanceledTransaction::default();
2590                        message.digest = Some(tx_digest.to_string());
2591                        message.version_assignments = assignments
2592                            .into_iter()
2593                            .map(|(id, version)| {
2594                                let mut message = VersionAssignment::default();
2595                                message.object_id = Some(id.to_canonical_string(true));
2596                                message.version = Some(version.value());
2597                                message
2598                            })
2599                            .collect();
2600                        message
2601                    })
2602                    .collect();
2603                1
2604            }
2605            A::CancelledTransactionsV2(canceled_transactions) => {
2606                message.canceled_transactions = canceled_transactions
2607                    .into_iter()
2608                    .map(|(tx_digest, assignments)| {
2609                        let mut message = CanceledTransaction::default();
2610                        message.digest = Some(tx_digest.to_string());
2611                        message.version_assignments = assignments
2612                            .into_iter()
2613                            .map(|((id, start_version), version)| {
2614                                let mut message = VersionAssignment::default();
2615                                message.object_id = Some(id.to_canonical_string(true));
2616                                message.start_version = Some(start_version.value());
2617                                message.version = Some(version.value());
2618                                message
2619                            })
2620                            .collect();
2621                        message
2622                    })
2623                    .collect();
2624                2
2625            }
2626        };
2627
2628        message.version = Some(version);
2629        message
2630    }
2631}
2632
2633//
2634// GenesisTransaction
2635//
2636
2637impl From<crate::transaction::GenesisTransaction> for GenesisTransaction {
2638    fn from(value: crate::transaction::GenesisTransaction) -> Self {
2639        let mut message = Self::default();
2640        message.objects = value.objects.into_iter().map(Into::into).collect();
2641        message
2642    }
2643}
2644
2645//
2646// RandomnessStateUpdate
2647//
2648
2649impl From<crate::transaction::RandomnessStateUpdate> for RandomnessStateUpdate {
2650    fn from(value: crate::transaction::RandomnessStateUpdate) -> Self {
2651        let mut message = Self::default();
2652        message.epoch = Some(value.epoch);
2653        message.randomness_round = Some(value.randomness_round.0);
2654        message.random_bytes = Some(value.random_bytes.into());
2655        message.randomness_object_initial_shared_version =
2656            Some(value.randomness_obj_initial_shared_version.value());
2657        message
2658    }
2659}
2660
2661//
2662// AuthenticatorStateUpdate
2663//
2664
2665impl From<crate::transaction::AuthenticatorStateUpdate> for AuthenticatorStateUpdate {
2666    fn from(value: crate::transaction::AuthenticatorStateUpdate) -> Self {
2667        let mut message = Self::default();
2668        message.epoch = Some(value.epoch);
2669        message.round = Some(value.round);
2670        message.new_active_jwks = value.new_active_jwks.into_iter().map(Into::into).collect();
2671        message.authenticator_object_initial_shared_version =
2672            Some(value.authenticator_obj_initial_shared_version.value());
2673        message
2674    }
2675}
2676
2677//
2678// ActiveJwk
2679//
2680
2681impl From<crate::authenticator_state::ActiveJwk> for ActiveJwk {
2682    fn from(value: crate::authenticator_state::ActiveJwk) -> Self {
2683        let mut jwk_id = JwkId::default();
2684        jwk_id.iss = Some(value.jwk_id.iss);
2685        jwk_id.kid = Some(value.jwk_id.kid);
2686
2687        let mut jwk = Jwk::default();
2688        jwk.kty = Some(value.jwk.kty);
2689        jwk.e = Some(value.jwk.e);
2690        jwk.n = Some(value.jwk.n);
2691        jwk.alg = Some(value.jwk.alg);
2692
2693        let mut message = Self::default();
2694        message.id = Some(jwk_id);
2695        message.jwk = Some(jwk);
2696        message.epoch = Some(value.epoch);
2697        message
2698    }
2699}
2700
2701//
2702// ChangeEpoch
2703//
2704
2705impl From<crate::transaction::ChangeEpoch> for ChangeEpoch {
2706    fn from(value: crate::transaction::ChangeEpoch) -> Self {
2707        let mut message = Self::default();
2708        message.epoch = Some(value.epoch);
2709        message.protocol_version = Some(value.protocol_version.as_u64());
2710        message.storage_charge = Some(value.storage_charge);
2711        message.computation_charge = Some(value.computation_charge);
2712        message.storage_rebate = Some(value.storage_rebate);
2713        message.non_refundable_storage_fee = Some(value.non_refundable_storage_fee);
2714        message.epoch_start_timestamp = Some(sui_rpc::proto::timestamp_ms_to_proto(
2715            value.epoch_start_timestamp_ms,
2716        ));
2717        message.system_packages = value
2718            .system_packages
2719            .into_iter()
2720            .map(|(version, modules, dependencies)| {
2721                let mut message = SystemPackage::default();
2722                message.version = Some(version.value());
2723                message.modules = modules.into_iter().map(Into::into).collect();
2724                message.dependencies = dependencies
2725                    .iter()
2726                    .map(|d| d.to_canonical_string(true))
2727                    .collect();
2728                message
2729            })
2730            .collect();
2731        message
2732    }
2733}
2734
2735//
2736// EndOfEpochTransactionkind
2737//
2738
2739impl From<crate::transaction::EndOfEpochTransactionKind> for EndOfEpochTransactionKind {
2740    fn from(value: crate::transaction::EndOfEpochTransactionKind) -> Self {
2741        use crate::transaction::EndOfEpochTransactionKind as K;
2742        use end_of_epoch_transaction_kind::Kind;
2743
2744        let message = Self::default();
2745
2746        match value {
2747            K::ChangeEpoch(change_epoch) => message
2748                .with_change_epoch(change_epoch)
2749                .with_kind(Kind::ChangeEpoch),
2750            K::AuthenticatorStateCreate => message.with_kind(Kind::AuthenticatorStateCreate),
2751            K::AuthenticatorStateExpire(expire) => message
2752                .with_authenticator_state_expire(expire)
2753                .with_kind(Kind::AuthenticatorStateExpire),
2754            K::RandomnessStateCreate => message.with_kind(Kind::RandomnessStateCreate),
2755            K::DenyListStateCreate => message.with_kind(Kind::DenyListStateCreate),
2756            K::BridgeStateCreate(chain_id) => message
2757                .with_bridge_chain_id(chain_id.to_string())
2758                .with_kind(Kind::BridgeStateCreate),
2759            K::BridgeCommitteeInit(bridge_object_version) => message
2760                .with_bridge_object_version(bridge_object_version.into())
2761                .with_kind(Kind::BridgeCommitteeInit),
2762            K::StoreExecutionTimeObservations(observations) => message
2763                .with_execution_time_observations(observations)
2764                .with_kind(Kind::StoreExecutionTimeObservations),
2765            K::AccumulatorRootCreate => message.with_kind(Kind::AccumulatorRootCreate),
2766            K::CoinRegistryCreate => message.with_kind(Kind::CoinRegistryCreate),
2767            K::DisplayRegistryCreate => message.with_kind(Kind::DisplayRegistryCreate),
2768            K::AddressAliasStateCreate => message.with_kind(Kind::AddressAliasStateCreate),
2769            K::ForwardingAddressRegistryCreate => {
2770                message.with_kind(Kind::ForwardingAddressRegistryCreate)
2771            }
2772            K::WriteAccumulatorStorageCost(storage_cost) => message
2773                .with_kind(Kind::WriteAccumulatorStorageCost)
2774                .with_storage_cost(storage_cost.storage_cost),
2775        }
2776    }
2777}
2778
2779//
2780// AuthenticatorStateExpire
2781//
2782
2783impl From<crate::transaction::AuthenticatorStateExpire> for AuthenticatorStateExpire {
2784    fn from(value: crate::transaction::AuthenticatorStateExpire) -> Self {
2785        let mut message = Self::default();
2786        message.min_epoch = Some(value.min_epoch);
2787        message.authenticator_object_initial_shared_version =
2788            Some(value.authenticator_obj_initial_shared_version.value());
2789        message
2790    }
2791}
2792
2793// ExecutionTimeObservations
2794
2795impl From<crate::transaction::StoredExecutionTimeObservations> for ExecutionTimeObservations {
2796    fn from(value: crate::transaction::StoredExecutionTimeObservations) -> Self {
2797        let mut message = Self::default();
2798        match value {
2799            crate::transaction::StoredExecutionTimeObservations::V1(vec) => {
2800                message.version = Some(1);
2801                message.observations = vec
2802                    .into_iter()
2803                    .map(|(key, observation)| {
2804                        use crate::execution::ExecutionTimeObservationKey as K;
2805                        use execution_time_observation::ExecutionTimeObservationKind;
2806
2807                        let mut message = ExecutionTimeObservation::default();
2808
2809                        let kind = match key {
2810                            K::MoveEntryPoint {
2811                                package,
2812                                module,
2813                                function,
2814                                type_arguments,
2815                            } => {
2816                                message.move_entry_point = Some({
2817                                    let mut message = MoveCall::default();
2818                                    message.package = Some(package.to_canonical_string(true));
2819                                    message.module = Some(module);
2820                                    message.function = Some(function);
2821                                    message.type_arguments = type_arguments
2822                                        .into_iter()
2823                                        .map(|ty| ty.to_canonical_string(true))
2824                                        .collect();
2825                                    message
2826                                });
2827                                ExecutionTimeObservationKind::MoveEntryPoint
2828                            }
2829                            K::TransferObjects => ExecutionTimeObservationKind::TransferObjects,
2830                            K::SplitCoins => ExecutionTimeObservationKind::SplitCoins,
2831                            K::MergeCoins => ExecutionTimeObservationKind::MergeCoins,
2832                            K::Publish => ExecutionTimeObservationKind::Publish,
2833                            K::MakeMoveVec => ExecutionTimeObservationKind::MakeMoveVector,
2834                            K::Upgrade => ExecutionTimeObservationKind::Upgrade,
2835                        };
2836
2837                        message.validator_observations = observation
2838                            .into_iter()
2839                            .map(|(name, duration)| {
2840                                let mut message = ValidatorExecutionTimeObservation::default();
2841                                message.validator = Some(name.0.to_vec().into());
2842                                message.duration = Some(prost_types::Duration {
2843                                    seconds: duration.as_secs() as i64,
2844                                    nanos: duration.subsec_nanos() as i32,
2845                                });
2846                                message
2847                            })
2848                            .collect();
2849
2850                        message.set_kind(kind);
2851                        message
2852                    })
2853                    .collect();
2854            }
2855        }
2856
2857        message
2858    }
2859}
2860
2861//
2862// ProgrammableTransaction
2863//
2864
2865impl From<crate::transaction::ProgrammableTransaction> for ProgrammableTransaction {
2866    fn from(value: crate::transaction::ProgrammableTransaction) -> Self {
2867        let mut message = Self::default();
2868        message.inputs = value.inputs.into_iter().map(Into::into).collect();
2869        message.commands = value.commands.into_iter().map(Into::into).collect();
2870        message
2871    }
2872}
2873
2874//
2875// Input
2876//
2877
2878impl From<crate::transaction::CallArg> for Input {
2879    fn from(value: crate::transaction::CallArg) -> Self {
2880        use crate::transaction::CallArg as I;
2881        use crate::transaction::ObjectArg as O;
2882        use input::InputKind;
2883        use input::Mutability;
2884
2885        let mut message = Self::default();
2886
2887        let kind = match value {
2888            I::Pure(value) => {
2889                message.pure = Some(value.into());
2890                InputKind::Pure
2891            }
2892            I::Object(o) => match o {
2893                O::ImmOrOwnedObject((id, version, digest)) => {
2894                    message.object_id = Some(id.to_canonical_string(true));
2895                    message.version = Some(version.value());
2896                    message.digest = Some(digest.to_string());
2897                    InputKind::ImmutableOrOwned
2898                }
2899                O::SharedObject {
2900                    id,
2901                    initial_shared_version,
2902                    mutability,
2903                } => {
2904                    message.object_id = Some(id.to_canonical_string(true));
2905                    message.version = Some(initial_shared_version.value());
2906                    message.mutable = Some(mutability.is_exclusive());
2907                    message.set_mutability(match mutability {
2908                        crate::transaction::SharedObjectMutability::Immutable => {
2909                            Mutability::Immutable
2910                        }
2911                        crate::transaction::SharedObjectMutability::Mutable => Mutability::Mutable,
2912                        crate::transaction::SharedObjectMutability::NonExclusiveWrite => {
2913                            Mutability::NonExclusiveWrite
2914                        }
2915                    });
2916                    InputKind::Shared
2917                }
2918                O::Receiving((id, version, digest)) => {
2919                    message.object_id = Some(id.to_canonical_string(true));
2920                    message.version = Some(version.value());
2921                    message.digest = Some(digest.to_string());
2922                    InputKind::Receiving
2923                }
2924            },
2925            I::FundsWithdrawal(withdrawal) => {
2926                message.set_funds_withdrawal(withdrawal);
2927                InputKind::FundsWithdrawal
2928            }
2929        };
2930
2931        message.set_kind(kind);
2932        message
2933    }
2934}
2935
2936impl From<crate::transaction::FundsWithdrawalArg> for FundsWithdrawal {
2937    fn from(value: crate::transaction::FundsWithdrawalArg) -> Self {
2938        use funds_withdrawal::Source;
2939
2940        let mut message = Self::default();
2941
2942        message.amount = match value.reservation {
2943            crate::transaction::Reservation::MaxAmountU64(amount) => Some(amount),
2944        };
2945        let crate::transaction::WithdrawalTypeArg::Balance(coin_type) = value.type_arg;
2946        message.coin_type = Some(coin_type.to_canonical_string(true));
2947        let source = match value.withdraw_from {
2948            crate::transaction::WithdrawFrom::Sender => Source::Sender,
2949            crate::transaction::WithdrawFrom::Sponsor => Source::Sponsor,
2950            crate::transaction::WithdrawFrom::SenderAllowance { funder, allowance } => {
2951                message.funder = Some(funder.to_string());
2952                message.allowance = Some(allowance.to_string());
2953                Source::SenderAllowance
2954            }
2955        };
2956        message.set_source(source);
2957
2958        message
2959    }
2960}
2961
2962//
2963// Argument
2964//
2965
2966impl From<crate::transaction::Argument> for Argument {
2967    fn from(value: crate::transaction::Argument) -> Self {
2968        use crate::transaction::Argument as A;
2969        use argument::ArgumentKind;
2970
2971        let mut message = Self::default();
2972
2973        let kind = match value {
2974            A::GasCoin => ArgumentKind::Gas,
2975            A::Input(input) => {
2976                message.input = Some(input.into());
2977                ArgumentKind::Input
2978            }
2979            A::Result(result) => {
2980                message.result = Some(result.into());
2981                ArgumentKind::Result
2982            }
2983            A::NestedResult(result, subresult) => {
2984                message.result = Some(result.into());
2985                message.subresult = Some(subresult.into());
2986                ArgumentKind::Result
2987            }
2988        };
2989
2990        message.set_kind(kind);
2991        message
2992    }
2993}
2994
2995//
2996// Command
2997//
2998
2999impl From<crate::transaction::Command> for Command {
3000    fn from(value: crate::transaction::Command) -> Self {
3001        use crate::transaction::Command as C;
3002        use command::Command;
3003
3004        let command = match value {
3005            C::MoveCall(move_call) => Command::MoveCall((*move_call).into()),
3006            C::TransferObjects(objects, address) => Command::TransferObjects({
3007                let mut message = TransferObjects::default();
3008                message.objects = objects.into_iter().map(Into::into).collect();
3009                message.address = Some(address.into());
3010                message
3011            }),
3012            C::SplitCoins(coin, amounts) => Command::SplitCoins({
3013                let mut message = SplitCoins::default();
3014                message.coin = Some(coin.into());
3015                message.amounts = amounts.into_iter().map(Into::into).collect();
3016                message
3017            }),
3018            C::MergeCoins(coin, coins_to_merge) => Command::MergeCoins({
3019                let mut message = MergeCoins::default();
3020                message.coin = Some(coin.into());
3021                message.coins_to_merge = coins_to_merge.into_iter().map(Into::into).collect();
3022                message
3023            }),
3024            C::Publish(modules, dependencies) => Command::Publish({
3025                let mut message = Publish::default();
3026                message.modules = modules.into_iter().map(Into::into).collect();
3027                message.dependencies = dependencies
3028                    .iter()
3029                    .map(|d| d.to_canonical_string(true))
3030                    .collect();
3031                message
3032            }),
3033            C::MakeMoveVec(element_type, elements) => Command::MakeMoveVector({
3034                let mut message = MakeMoveVector::default();
3035                message.element_type = element_type.map(|t| t.to_canonical_string(true));
3036                message.elements = elements.into_iter().map(Into::into).collect();
3037                message
3038            }),
3039            C::Upgrade(modules, dependencies, package, ticket) => Command::Upgrade({
3040                let mut message = Upgrade::default();
3041                message.modules = modules.into_iter().map(Into::into).collect();
3042                message.dependencies = dependencies
3043                    .iter()
3044                    .map(|d| d.to_canonical_string(true))
3045                    .collect();
3046                message.package = Some(package.to_canonical_string(true));
3047                message.ticket = Some(ticket.into());
3048                message
3049            }),
3050        };
3051
3052        let mut message = Self::default();
3053        message.command = Some(command);
3054        message
3055    }
3056}
3057
3058//
3059// MoveCall
3060//
3061
3062impl From<crate::transaction::ProgrammableMoveCall> for MoveCall {
3063    fn from(value: crate::transaction::ProgrammableMoveCall) -> Self {
3064        let mut message = Self::default();
3065        message.package = Some(value.package.to_canonical_string(true));
3066        message.module = Some(value.module.to_string());
3067        message.function = Some(value.function.to_string());
3068        message.type_arguments = value
3069            .type_arguments
3070            .iter()
3071            .map(|t| t.to_canonical_string(true))
3072            .collect();
3073        message.arguments = value.arguments.into_iter().map(Into::into).collect();
3074        message
3075    }
3076}
3077
3078//
3079// TransactionEffects
3080//
3081
3082impl From<crate::effects::TransactionEffects> for TransactionEffects {
3083    fn from(value: crate::effects::TransactionEffects) -> Self {
3084        Self::merge_from(&value, &FieldMaskTree::new_wildcard())
3085    }
3086}
3087
3088impl Merge<&crate::effects::TransactionEffects> for TransactionEffects {
3089    fn merge(&mut self, source: &crate::effects::TransactionEffects, mask: &FieldMaskTree) {
3090        if mask.contains(Self::BCS_FIELD.name) {
3091            let mut bcs = Bcs::serialize(&source).unwrap();
3092            bcs.name = Some("TransactionEffects".to_owned());
3093            self.bcs = Some(bcs);
3094        }
3095
3096        if mask.contains(Self::DIGEST_FIELD.name) {
3097            self.digest = Some(source.digest().to_string());
3098        }
3099
3100        match source {
3101            crate::effects::TransactionEffects::V1(v1) => self.merge(v1, mask),
3102            crate::effects::TransactionEffects::V2(v2) => self.merge(v2, mask),
3103        }
3104    }
3105}
3106
3107//
3108// TransactionEffectsV1
3109//
3110
3111impl Merge<&crate::effects::TransactionEffectsV1> for TransactionEffects {
3112    fn merge(&mut self, value: &crate::effects::TransactionEffectsV1, mask: &FieldMaskTree) {
3113        use crate::effects::TransactionEffectsAPI;
3114
3115        if mask.contains(Self::VERSION_FIELD.name) {
3116            self.version = Some(1);
3117        }
3118
3119        if mask.contains(Self::STATUS_FIELD.name) {
3120            self.status = Some(value.status().clone().into());
3121        }
3122
3123        if mask.contains(Self::EPOCH_FIELD.name) {
3124            self.epoch = Some(value.executed_epoch());
3125        }
3126
3127        if mask.contains(Self::GAS_USED_FIELD.name) {
3128            self.gas_used = Some(value.gas_cost_summary().clone().into());
3129        }
3130
3131        if mask.contains(Self::TRANSACTION_DIGEST_FIELD.name) {
3132            self.transaction_digest = Some(value.transaction_digest().to_string());
3133        }
3134
3135        if mask.contains(Self::EVENTS_DIGEST_FIELD.name) {
3136            self.events_digest = value.events_digest().map(|d| d.to_string());
3137        }
3138
3139        if mask.contains(Self::DEPENDENCIES_FIELD.name) {
3140            self.dependencies = value
3141                .dependencies()
3142                .iter()
3143                .map(ToString::to_string)
3144                .collect();
3145        }
3146
3147        if mask.contains(Self::LAMPORT_VERSION_FIELD.name) {
3148            self.lamport_version = Some(value.lamport_version().value());
3149        }
3150
3151        if mask.contains(Self::CHANGED_OBJECTS_FIELD.name)
3152            || mask.contains(Self::UNCHANGED_CONSENSUS_OBJECTS_FIELD.name)
3153            || mask.contains(Self::GAS_OBJECT_FIELD.name)
3154        {
3155            let mut changed_objects = Vec::new();
3156            let mut unchanged_consensus_objects = Vec::new();
3157
3158            for ((id, version, digest), owner) in value.created() {
3159                let mut change = ChangedObject::default();
3160                change.object_id = Some(id.to_canonical_string(true));
3161                change.input_state = Some(changed_object::InputObjectState::DoesNotExist.into());
3162                change.output_state = Some(changed_object::OutputObjectState::ObjectWrite.into());
3163                change.output_version = Some(version.value());
3164                change.output_digest = Some(digest.to_string());
3165                change.output_owner = Some(owner.clone().into());
3166                change.id_operation = Some(changed_object::IdOperation::Created.into());
3167
3168                changed_objects.push(change);
3169            }
3170
3171            for ((id, version, digest), owner) in value.mutated() {
3172                let mut change = ChangedObject::default();
3173                change.object_id = Some(id.to_canonical_string(true));
3174                change.input_state = Some(changed_object::InputObjectState::Exists.into());
3175                change.output_state = Some(changed_object::OutputObjectState::ObjectWrite.into());
3176                change.output_version = Some(version.value());
3177                change.output_digest = Some(digest.to_string());
3178                change.output_owner = Some(owner.clone().into());
3179                change.id_operation = Some(changed_object::IdOperation::None.into());
3180
3181                changed_objects.push(change);
3182            }
3183
3184            for ((id, version, digest), owner) in value.unwrapped() {
3185                let mut change = ChangedObject::default();
3186                change.object_id = Some(id.to_canonical_string(true));
3187                change.input_state = Some(changed_object::InputObjectState::DoesNotExist.into());
3188                change.output_state = Some(changed_object::OutputObjectState::ObjectWrite.into());
3189                change.output_version = Some(version.value());
3190                change.output_digest = Some(digest.to_string());
3191                change.output_owner = Some(owner.clone().into());
3192                change.id_operation = Some(changed_object::IdOperation::None.into());
3193
3194                changed_objects.push(change);
3195            }
3196
3197            for (id, version, digest) in value.deleted() {
3198                let mut change = ChangedObject::default();
3199                change.object_id = Some(id.to_canonical_string(true));
3200                change.input_state = Some(changed_object::InputObjectState::Exists.into());
3201                change.output_state = Some(changed_object::OutputObjectState::DoesNotExist.into());
3202                change.output_version = Some(version.value());
3203                change.output_digest = Some(digest.to_string());
3204                change.id_operation = Some(changed_object::IdOperation::Deleted.into());
3205
3206                changed_objects.push(change);
3207            }
3208
3209            for (id, version, digest) in value.unwrapped_then_deleted() {
3210                let mut change = ChangedObject::default();
3211                change.object_id = Some(id.to_canonical_string(true));
3212                change.input_state = Some(changed_object::InputObjectState::DoesNotExist.into());
3213                change.output_state = Some(changed_object::OutputObjectState::DoesNotExist.into());
3214                change.output_version = Some(version.value());
3215                change.output_digest = Some(digest.to_string());
3216                change.id_operation = Some(changed_object::IdOperation::Deleted.into());
3217
3218                changed_objects.push(change);
3219            }
3220
3221            for (id, version, digest) in value.wrapped() {
3222                let mut change = ChangedObject::default();
3223                change.object_id = Some(id.to_canonical_string(true));
3224                change.input_state = Some(changed_object::InputObjectState::Exists.into());
3225                change.output_state = Some(changed_object::OutputObjectState::DoesNotExist.into());
3226                change.output_version = Some(version.value());
3227                change.output_digest = Some(digest.to_string());
3228                change.id_operation = Some(changed_object::IdOperation::Deleted.into());
3229
3230                changed_objects.push(change);
3231            }
3232
3233            for (object_id, version) in value.modified_at_versions() {
3234                let object_id = object_id.to_canonical_string(true);
3235                let version = version.value();
3236                if let Some(changed_object) = changed_objects
3237                    .iter_mut()
3238                    .find(|object| object.object_id() == object_id)
3239                {
3240                    changed_object.input_version = Some(version);
3241                }
3242            }
3243
3244            for (id, version, digest) in value.shared_objects() {
3245                let object_id = id.to_canonical_string(true);
3246                let version = version.value();
3247                let digest = digest.to_string();
3248
3249                if let Some(changed_object) = changed_objects
3250                    .iter_mut()
3251                    .find(|object| object.object_id() == object_id)
3252                {
3253                    changed_object.input_version = Some(version);
3254                    changed_object.input_digest = Some(digest);
3255                } else {
3256                    let mut unchanged_consensus_object = UnchangedConsensusObject::default();
3257                    unchanged_consensus_object.kind = Some(
3258                        unchanged_consensus_object::UnchangedConsensusObjectKind::ReadOnlyRoot
3259                            .into(),
3260                    );
3261                    unchanged_consensus_object.object_id = Some(object_id);
3262                    unchanged_consensus_object.version = Some(version);
3263                    unchanged_consensus_object.digest = Some(digest);
3264
3265                    unchanged_consensus_objects.push(unchanged_consensus_object);
3266                }
3267            }
3268
3269            if mask.contains(Self::GAS_OBJECT_FIELD.name)
3270                && let Some(((gas_id, _, _), _)) = value.gas_object()
3271            {
3272                let gas_object_id = gas_id.to_canonical_string(true);
3273                self.gas_object = changed_objects
3274                    .iter()
3275                    .find(|object| object.object_id() == gas_object_id)
3276                    .cloned();
3277            }
3278
3279            if mask.contains(Self::CHANGED_OBJECTS_FIELD.name) {
3280                self.changed_objects = changed_objects;
3281            }
3282
3283            if mask.contains(Self::UNCHANGED_CONSENSUS_OBJECTS_FIELD.name) {
3284                self.unchanged_consensus_objects = unchanged_consensus_objects;
3285            }
3286        }
3287    }
3288}
3289
3290//
3291// TransactionEffectsV2
3292//
3293
3294impl Merge<&crate::effects::TransactionEffectsV2> for TransactionEffects {
3295    fn merge(
3296        &mut self,
3297        crate::effects::TransactionEffectsV2 {
3298            status,
3299            executed_epoch,
3300            gas_used,
3301            transaction_digest,
3302            gas_object_index,
3303            events_digest,
3304            dependencies,
3305            lamport_version,
3306            changed_objects,
3307            unchanged_consensus_objects,
3308            aux_data_digest,
3309        }: &crate::effects::TransactionEffectsV2,
3310        mask: &FieldMaskTree,
3311    ) {
3312        if mask.contains(Self::VERSION_FIELD.name) {
3313            self.version = Some(2);
3314        }
3315
3316        if mask.contains(Self::STATUS_FIELD.name) {
3317            self.status = Some(status.clone().into());
3318        }
3319
3320        if mask.contains(Self::EPOCH_FIELD.name) {
3321            self.epoch = Some(*executed_epoch);
3322        }
3323
3324        if mask.contains(Self::GAS_USED_FIELD.name) {
3325            self.gas_used = Some(gas_used.clone().into());
3326        }
3327
3328        if mask.contains(Self::TRANSACTION_DIGEST_FIELD.name) {
3329            self.transaction_digest = Some(transaction_digest.to_string());
3330        }
3331
3332        if mask.contains(Self::GAS_OBJECT_FIELD.name) {
3333            self.gas_object = gas_object_index
3334                .map(|index| {
3335                    changed_objects
3336                        .get(index as usize)
3337                        .cloned()
3338                        .map(|(id, change)| {
3339                            let mut message = ChangedObject::from(change);
3340                            message.object_id = Some(id.to_canonical_string(true));
3341                            message
3342                        })
3343                })
3344                .flatten();
3345        }
3346
3347        if mask.contains(Self::EVENTS_DIGEST_FIELD.name) {
3348            self.events_digest = events_digest.map(|d| d.to_string());
3349        }
3350
3351        if mask.contains(Self::DEPENDENCIES_FIELD.name) {
3352            self.dependencies = dependencies.iter().map(ToString::to_string).collect();
3353        }
3354
3355        if mask.contains(Self::LAMPORT_VERSION_FIELD.name) {
3356            self.lamport_version = Some(lamport_version.value());
3357        }
3358
3359        if mask.contains(Self::CHANGED_OBJECTS_FIELD.name) {
3360            self.changed_objects = changed_objects
3361                .clone()
3362                .into_iter()
3363                .map(|(id, change)| {
3364                    let mut message = ChangedObject::from(change);
3365                    message.object_id = Some(id.to_canonical_string(true));
3366                    message
3367                })
3368                .collect();
3369        }
3370
3371        for object in self.changed_objects.iter_mut().chain(&mut self.gas_object) {
3372            if object.output_digest.is_some() && object.output_version.is_none() {
3373                object.output_version = Some(lamport_version.value());
3374            }
3375        }
3376
3377        if mask.contains(Self::UNCHANGED_CONSENSUS_OBJECTS_FIELD.name) {
3378            self.unchanged_consensus_objects = unchanged_consensus_objects
3379                .clone()
3380                .into_iter()
3381                .map(|(id, unchanged)| {
3382                    let mut message = UnchangedConsensusObject::from(unchanged);
3383                    message.object_id = Some(id.to_canonical_string(true));
3384                    message
3385                })
3386                .collect();
3387        }
3388
3389        if mask.contains(Self::AUXILIARY_DATA_DIGEST_FIELD.name) {
3390            self.auxiliary_data_digest = aux_data_digest.map(|d| d.to_string());
3391        }
3392    }
3393}
3394
3395//
3396// ChangedObject
3397//
3398
3399impl From<crate::effects::EffectsObjectChange> for ChangedObject {
3400    fn from(value: crate::effects::EffectsObjectChange) -> Self {
3401        use crate::effects::ObjectIn;
3402        use crate::effects::ObjectOut;
3403        use changed_object::InputObjectState;
3404        use changed_object::OutputObjectState;
3405
3406        let mut message = Self::default();
3407
3408        // Input State
3409        let input_state = match value.input_state {
3410            ObjectIn::NotExist => InputObjectState::DoesNotExist,
3411            ObjectIn::Exist(((version, digest), owner)) => {
3412                message.input_version = Some(version.value());
3413                message.input_digest = Some(digest.to_string());
3414                message.input_owner = Some(owner.into());
3415                InputObjectState::Exists
3416            }
3417        };
3418        message.set_input_state(input_state);
3419
3420        // Output State
3421        let output_state = match value.output_state {
3422            ObjectOut::NotExist => OutputObjectState::DoesNotExist,
3423            ObjectOut::ObjectWrite((digest, owner)) => {
3424                message.output_digest = Some(digest.to_string());
3425                message.output_owner = Some(owner.into());
3426                OutputObjectState::ObjectWrite
3427            }
3428            ObjectOut::PackageWrite((version, digest)) => {
3429                message.output_version = Some(version.value());
3430                message.output_digest = Some(digest.to_string());
3431                OutputObjectState::PackageWrite
3432            }
3433            ObjectOut::AccumulatorWriteV1(accumulator_write) => {
3434                message.set_accumulator_write(accumulator_write);
3435                OutputObjectState::AccumulatorWrite
3436            }
3437        };
3438        message.set_output_state(output_state);
3439
3440        message.set_id_operation(value.id_operation.into());
3441        message
3442    }
3443}
3444
3445impl From<crate::effects::AccumulatorWriteV1> for AccumulatorWrite {
3446    fn from(value: crate::effects::AccumulatorWriteV1) -> Self {
3447        use accumulator_write::AccumulatorOperation;
3448
3449        let mut message = Self::default();
3450
3451        message.set_address(value.address.address.to_string());
3452        message.set_accumulator_type(value.address.ty.to_canonical_string(true));
3453        message.set_operation(match value.operation {
3454            crate::effects::AccumulatorOperation::Merge => AccumulatorOperation::Merge,
3455            crate::effects::AccumulatorOperation::Split => AccumulatorOperation::Split,
3456        });
3457        match value.value {
3458            crate::effects::AccumulatorValue::Integer(value) => message.set_integer_value(value),
3459            //TODO unsupported value types
3460            crate::effects::AccumulatorValue::IntegerTuple(_, _)
3461            | crate::effects::AccumulatorValue::EventDigest(_) => {}
3462        }
3463
3464        message
3465    }
3466}
3467
3468//
3469// IdOperation
3470//
3471
3472impl From<crate::effects::IDOperation> for changed_object::IdOperation {
3473    fn from(value: crate::effects::IDOperation) -> Self {
3474        use crate::effects::IDOperation as I;
3475
3476        match value {
3477            I::None => Self::None,
3478            I::Created => Self::Created,
3479            I::Deleted => Self::Deleted,
3480        }
3481    }
3482}
3483
3484//
3485// UnchangedConsensusObject
3486//
3487
3488impl From<crate::effects::UnchangedConsensusKind> for UnchangedConsensusObject {
3489    fn from(value: crate::effects::UnchangedConsensusKind) -> Self {
3490        use crate::effects::UnchangedConsensusKind as K;
3491        use unchanged_consensus_object::UnchangedConsensusObjectKind;
3492
3493        let mut message = Self::default();
3494
3495        let kind = match value {
3496            K::ReadOnlyRoot((version, digest)) => {
3497                message.version = Some(version.value());
3498                message.digest = Some(digest.to_string());
3499                UnchangedConsensusObjectKind::ReadOnlyRoot
3500            }
3501            K::MutateConsensusStreamEnded(version) => {
3502                message.version = Some(version.value());
3503                UnchangedConsensusObjectKind::MutateConsensusStreamEnded
3504            }
3505            K::ReadConsensusStreamEnded(version) => {
3506                message.version = Some(version.value());
3507                UnchangedConsensusObjectKind::ReadConsensusStreamEnded
3508            }
3509            K::Cancelled(version) => {
3510                message.version = Some(version.value());
3511                UnchangedConsensusObjectKind::Canceled
3512            }
3513            K::PerEpochConfig => UnchangedConsensusObjectKind::PerEpochConfig,
3514            // PerEpochConfigWithSequenceNumber { version } => {
3515            //     message.version = Some(version);
3516            //     UnchangedSharedObjectKind::PerEpochConfig
3517            // }
3518        };
3519
3520        message.set_kind(kind);
3521        message
3522    }
3523}
3524
3525//
3526// TransactionChecks
3527//
3528
3529impl From<simulate_transaction_request::TransactionChecks>
3530    for crate::transaction_executor::TransactionChecks
3531{
3532    fn from(value: simulate_transaction_request::TransactionChecks) -> Self {
3533        match value {
3534            simulate_transaction_request::TransactionChecks::Enabled => Self::Enabled,
3535            simulate_transaction_request::TransactionChecks::Disabled => Self::Disabled,
3536            // Default to enabled
3537            _ => Self::Enabled,
3538        }
3539    }
3540}
3541
3542//
3543// Coin-related conversions
3544//
3545
3546impl From<crate::coin_registry::MetadataCapState> for coin_metadata::MetadataCapState {
3547    fn from(value: crate::coin_registry::MetadataCapState) -> Self {
3548        match value {
3549            crate::coin_registry::MetadataCapState::Claimed(_) => {
3550                coin_metadata::MetadataCapState::Claimed
3551            }
3552            crate::coin_registry::MetadataCapState::Unclaimed => {
3553                coin_metadata::MetadataCapState::Unclaimed
3554            }
3555            crate::coin_registry::MetadataCapState::Deleted => {
3556                coin_metadata::MetadataCapState::Deleted
3557            }
3558        }
3559    }
3560}
3561
3562impl From<&crate::coin_registry::Currency> for CoinMetadata {
3563    fn from(value: &crate::coin_registry::Currency) -> Self {
3564        let mut metadata = CoinMetadata::default();
3565        metadata.id = Some(sui_sdk_types::Address::from(value.id.into_bytes()).to_string());
3566        metadata.decimals = Some(value.decimals.into());
3567        metadata.name = Some(value.name.clone());
3568        metadata.symbol = Some(value.symbol.clone());
3569        metadata.description = Some(value.description.clone());
3570        metadata.icon_url = Some(value.icon_url.clone());
3571
3572        match &value.metadata_cap_id {
3573            crate::coin_registry::MetadataCapState::Claimed(id) => {
3574                metadata.metadata_cap_state = Some(coin_metadata::MetadataCapState::Claimed as i32);
3575                metadata.metadata_cap_id = Some(sui_sdk_types::Address::from(*id).to_string());
3576            }
3577            crate::coin_registry::MetadataCapState::Unclaimed => {
3578                metadata.metadata_cap_state =
3579                    Some(coin_metadata::MetadataCapState::Unclaimed as i32);
3580            }
3581            crate::coin_registry::MetadataCapState::Deleted => {
3582                metadata.metadata_cap_state = Some(coin_metadata::MetadataCapState::Deleted as i32);
3583            }
3584        }
3585
3586        metadata
3587    }
3588}
3589
3590impl From<crate::coin::CoinMetadata> for CoinMetadata {
3591    fn from(value: crate::coin::CoinMetadata) -> Self {
3592        let mut metadata = CoinMetadata::default();
3593        metadata.id = Some(sui_sdk_types::Address::from(value.id.id.bytes).to_string());
3594        metadata.decimals = Some(value.decimals.into());
3595        metadata.name = Some(value.name);
3596        metadata.symbol = Some(value.symbol);
3597        metadata.description = Some(value.description);
3598        metadata.icon_url = value.icon_url;
3599        metadata
3600    }
3601}
3602
3603impl From<crate::coin_registry::SupplyState> for coin_treasury::SupplyState {
3604    fn from(value: crate::coin_registry::SupplyState) -> Self {
3605        match value {
3606            crate::coin_registry::SupplyState::Fixed(_) => coin_treasury::SupplyState::Fixed,
3607            crate::coin_registry::SupplyState::BurnOnly(_) => coin_treasury::SupplyState::BurnOnly,
3608            crate::coin_registry::SupplyState::Unknown => coin_treasury::SupplyState::Unknown,
3609        }
3610    }
3611}
3612
3613impl From<crate::coin::TreasuryCap> for CoinTreasury {
3614    fn from(value: crate::coin::TreasuryCap) -> Self {
3615        let mut treasury = CoinTreasury::default();
3616        treasury.id = Some(sui_sdk_types::Address::from(value.id.id.bytes).to_string());
3617        treasury.total_supply = Some(value.total_supply.value);
3618        treasury
3619    }
3620}
3621
3622impl From<&crate::coin_registry::RegulatedState> for RegulatedCoinMetadata {
3623    fn from(value: &crate::coin_registry::RegulatedState) -> Self {
3624        let mut regulated = RegulatedCoinMetadata::default();
3625
3626        match value {
3627            crate::coin_registry::RegulatedState::Regulated {
3628                cap,
3629                allow_global_pause,
3630                variant,
3631            } => {
3632                regulated.deny_cap_object = Some(sui_sdk_types::Address::from(*cap).to_string());
3633                regulated.allow_global_pause = *allow_global_pause;
3634                regulated.variant = Some(*variant as u32);
3635                regulated.coin_regulated_state =
3636                    Some(regulated_coin_metadata::CoinRegulatedState::Regulated as i32);
3637            }
3638            crate::coin_registry::RegulatedState::Unregulated => {
3639                regulated.coin_regulated_state =
3640                    Some(regulated_coin_metadata::CoinRegulatedState::Unregulated as i32);
3641            }
3642            crate::coin_registry::RegulatedState::Unknown => {
3643                regulated.coin_regulated_state =
3644                    Some(regulated_coin_metadata::CoinRegulatedState::Unknown as i32);
3645            }
3646        }
3647
3648        regulated
3649    }
3650}
3651
3652impl From<crate::coin_registry::RegulatedState> for RegulatedCoinMetadata {
3653    fn from(value: crate::coin_registry::RegulatedState) -> Self {
3654        (&value).into()
3655    }
3656}
3657
3658impl From<crate::coin::RegulatedCoinMetadata> for RegulatedCoinMetadata {
3659    fn from(value: crate::coin::RegulatedCoinMetadata) -> Self {
3660        let mut message = RegulatedCoinMetadata::default();
3661        message.id = Some(sui_sdk_types::Address::from(value.id.id.bytes).to_string());
3662        message.coin_metadata_object =
3663            Some(sui_sdk_types::Address::from(value.coin_metadata_object.bytes).to_string());
3664        message.deny_cap_object =
3665            Some(sui_sdk_types::Address::from(value.deny_cap_object.bytes).to_string());
3666        message.coin_regulated_state =
3667            Some(regulated_coin_metadata::CoinRegulatedState::Regulated as i32);
3668        message
3669    }
3670}
3671
3672impl TryFrom<&ObjectSet> for crate::full_checkpoint_content::ObjectSet {
3673    type Error = TryFromProtoError;
3674
3675    fn try_from(value: &ObjectSet) -> Result<Self, Self::Error> {
3676        let mut objects = Self::default();
3677
3678        for o in value.objects() {
3679            objects.insert(
3680                o.bcs()
3681                    .deserialize()
3682                    .map_err(|e| TryFromProtoError::invalid("object.bcs", e))?,
3683            );
3684        }
3685
3686        Ok(objects)
3687    }
3688}
3689
3690#[cfg(test)]
3691mod tests {
3692    use crate::effects::TransactionEffectsAPI;
3693
3694    #[test]
3695    fn transaction_effects_v1_proto_includes_lamport_version() {
3696        let effects = crate::effects::TransactionEffectsV1::default();
3697        let lamport_version = effects.lamport_version().value();
3698        let proto: sui_rpc::proto::sui::rpc::v2::TransactionEffects =
3699            crate::effects::TransactionEffects::V1(effects).into();
3700
3701        assert_eq!(proto.lamport_version, Some(lamport_version));
3702    }
3703}