1use iota_json_rpc_types::{
6 IotaTransactionBlockResponse, IotaTransactionBlockResponseOptions, IotaTransactionKind,
7 ObjectChange,
8};
9use iota_types::{
10 base_types::{IotaAddress, ObjectDigest, ObjectID, SequenceNumber},
11 crypto::AggregateAuthoritySignature,
12 digests::TransactionDigest,
13 dynamic_field::DynamicFieldType,
14 effects::TransactionEffects,
15 event::{SystemEpochInfoEvent, SystemEpochInfoEventV1, SystemEpochInfoEventV2},
16 iota_serde::IotaStructTag,
17 iota_system_state::iota_system_state_summary::{IotaSystemStateSummary, IotaValidatorSummary},
18 messages_checkpoint::{
19 CertifiedCheckpointSummary, CheckpointCommitment, CheckpointDigest,
20 CheckpointSequenceNumber, EndOfEpochData,
21 },
22 move_package::MovePackage,
23 object::{Object, Owner},
24 transaction::SenderSignedData,
25};
26use move_core_types::language_storage::StructTag;
27use serde::{Deserialize, Serialize};
28use serde_with::serde_as;
29
30use crate::errors::IndexerError;
31
32pub type IndexerResult<T> = Result<T, IndexerError>;
33
34#[derive(Debug)]
35pub struct IndexedCheckpoint {
36 pub sequence_number: u64,
37 pub checkpoint_digest: CheckpointDigest,
38 pub epoch: u64,
39 pub tx_digests: Vec<TransactionDigest>,
40 pub network_total_transactions: u64,
41 pub previous_checkpoint_digest: Option<CheckpointDigest>,
42 pub timestamp_ms: u64,
43 pub total_gas_cost: i64, pub computation_cost: u64,
45 pub computation_cost_burned: u64,
46 pub storage_cost: u64,
47 pub storage_rebate: u64,
48 pub non_refundable_storage_fee: u64,
49 pub checkpoint_commitments: Vec<CheckpointCommitment>,
50 pub validator_signature: AggregateAuthoritySignature,
51 pub successful_tx_num: usize,
52 pub end_of_epoch_data: Option<EndOfEpochData>,
53 pub end_of_epoch: bool,
54 pub min_tx_sequence_number: u64,
55 pub max_tx_sequence_number: u64,
56}
57
58impl IndexedCheckpoint {
59 pub fn from_iota_checkpoint(
60 checkpoint: &iota_types::messages_checkpoint::CertifiedCheckpointSummary,
61 contents: &iota_types::messages_checkpoint::CheckpointContents,
62 successful_tx_num: usize,
63 ) -> Self {
64 let total_gas_cost = checkpoint.epoch_rolling_gas_cost_summary.computation_cost as i64
65 + checkpoint.epoch_rolling_gas_cost_summary.storage_cost as i64
66 - checkpoint.epoch_rolling_gas_cost_summary.storage_rebate as i64;
67 let tx_digests = contents.iter().map(|t| t.transaction).collect::<Vec<_>>();
68 let max_tx_sequence_number = checkpoint.network_total_transactions - 1;
69 let min_tx_sequence_number = max_tx_sequence_number + 1u64 - tx_digests.len() as u64;
71 let auth_sig = &checkpoint.auth_sig().signature;
72 Self {
73 sequence_number: checkpoint.sequence_number,
74 checkpoint_digest: *checkpoint.digest(),
75 epoch: checkpoint.epoch,
76 tx_digests,
77 previous_checkpoint_digest: checkpoint.previous_digest,
78 end_of_epoch_data: checkpoint.end_of_epoch_data.clone(),
79 end_of_epoch: checkpoint.end_of_epoch_data.clone().is_some(),
80 total_gas_cost,
81 computation_cost: checkpoint.epoch_rolling_gas_cost_summary.computation_cost,
82 computation_cost_burned: checkpoint
83 .epoch_rolling_gas_cost_summary
84 .computation_cost_burned,
85 storage_cost: checkpoint.epoch_rolling_gas_cost_summary.storage_cost,
86 storage_rebate: checkpoint.epoch_rolling_gas_cost_summary.storage_rebate,
87 non_refundable_storage_fee: checkpoint
88 .epoch_rolling_gas_cost_summary
89 .non_refundable_storage_fee,
90 successful_tx_num,
91 network_total_transactions: checkpoint.network_total_transactions,
92 timestamp_ms: checkpoint.timestamp_ms,
93 validator_signature: auth_sig.clone(),
94 checkpoint_commitments: checkpoint.checkpoint_commitments.clone(),
95 min_tx_sequence_number,
96 max_tx_sequence_number,
97 }
98 }
99}
100
101#[derive(Clone, Debug, Default)]
105pub struct IndexedEpochInfo {
106 pub epoch: u64,
107 pub first_checkpoint_id: u64,
108 pub epoch_start_timestamp: u64,
109 pub reference_gas_price: u64,
110 pub protocol_version: u64,
111 pub total_stake: u64,
112 pub storage_fund_balance: u64,
113 pub system_state: Vec<u8>,
114 pub epoch_total_transactions: Option<u64>,
115 pub last_checkpoint_id: Option<u64>,
116 pub epoch_end_timestamp: Option<u64>,
117 pub storage_charge: Option<u64>,
118 pub storage_rebate: Option<u64>,
119 pub total_gas_fees: Option<u64>,
120 pub total_stake_rewards_distributed: Option<u64>,
121 pub epoch_commitments: Option<Vec<CheckpointCommitment>>,
122 pub burnt_tokens_amount: Option<u64>,
123 pub minted_tokens_amount: Option<u64>,
124 pub tips_amount: Option<u64>,
125}
126
127pub(crate) trait IotaSystemStateSummaryView {
132 fn epoch(&self) -> u64;
133 fn epoch_start_timestamp_ms(&self) -> u64;
134 fn reference_gas_price(&self) -> u64;
135 fn protocol_version(&self) -> u64;
136 fn iota_total_supply(&self) -> u64;
137 fn active_validators(&self) -> &[IotaValidatorSummary];
138 fn inactive_pools_id(&self) -> ObjectID;
139 fn inactive_pools_size(&self) -> u64;
140 fn validator_candidates_id(&self) -> ObjectID;
141 fn validator_candidates_size(&self) -> u64;
142 fn to_committee_members(&self) -> Vec<u64>;
143}
144
145macro_rules! state_summary_get {
153 ($enum:expr, $field:ident) => {{
154 match $enum {
155 IotaSystemStateSummary::V1(ref inner) => &inner.$field,
156 IotaSystemStateSummary::V2(ref inner) => &inner.$field,
157 _ => unimplemented!(),
158 }
159 }};
160}
161
162impl IotaSystemStateSummaryView for IotaSystemStateSummary {
163 fn epoch(&self) -> u64 {
164 *state_summary_get!(self, epoch)
165 }
166
167 fn epoch_start_timestamp_ms(&self) -> u64 {
168 *state_summary_get!(self, epoch_start_timestamp_ms)
169 }
170
171 fn reference_gas_price(&self) -> u64 {
172 *state_summary_get!(self, reference_gas_price)
173 }
174
175 fn protocol_version(&self) -> u64 {
176 *state_summary_get!(self, protocol_version)
177 }
178
179 fn iota_total_supply(&self) -> u64 {
180 *state_summary_get!(self, iota_total_supply)
181 }
182
183 fn active_validators(&self) -> &[IotaValidatorSummary] {
184 state_summary_get!(self, active_validators)
185 }
186
187 fn inactive_pools_id(&self) -> ObjectID {
188 *state_summary_get!(self, inactive_pools_id)
189 }
190
191 fn inactive_pools_size(&self) -> u64 {
192 *state_summary_get!(self, inactive_pools_size)
193 }
194
195 fn validator_candidates_id(&self) -> ObjectID {
196 *state_summary_get!(self, validator_candidates_id)
197 }
198
199 fn validator_candidates_size(&self) -> u64 {
200 *state_summary_get!(self, validator_candidates_size)
201 }
202
203 fn to_committee_members(&self) -> Vec<u64> {
204 match self {
205 IotaSystemStateSummary::V1(inner) => (0..inner.active_validators.len())
206 .map(|i| i as u64)
207 .collect(),
208 IotaSystemStateSummary::V2(inner) => inner.committee_members.clone(),
209 _ => unimplemented!(),
210 }
211 }
212}
213
214impl IndexedEpochInfo {
215 pub fn from_new_system_state_summary(
216 new_system_state_summary: &IotaSystemStateSummary,
217 first_checkpoint_id: u64,
218 event: Option<&SystemEpochInfoEvent>,
219 ) -> IndexedEpochInfo {
220 let (total_stake, storage_fund_balance) = match event {
224 Some(SystemEpochInfoEvent::V1(e)) => (e.total_stake, e.storage_fund_balance),
225 Some(SystemEpochInfoEvent::V2(e)) => (e.total_stake, e.storage_fund_balance),
226 None => (0, 0),
227 };
228 Self {
229 epoch: new_system_state_summary.epoch(),
230 first_checkpoint_id,
231 epoch_start_timestamp: new_system_state_summary.epoch_start_timestamp_ms(),
232 reference_gas_price: new_system_state_summary.reference_gas_price(),
233 protocol_version: new_system_state_summary.protocol_version(),
234 total_stake,
235 storage_fund_balance,
236 system_state: bcs::to_bytes(new_system_state_summary).unwrap(),
237 ..Default::default()
238 }
239 }
240
241 pub fn from_end_of_epoch_data(
245 system_state_summary: &IotaSystemStateSummary,
246 last_checkpoint_summary: &CertifiedCheckpointSummary,
247 event: &SystemEpochInfoEvent,
248 network_total_tx_num_at_last_epoch_end: u64,
249 ) -> IndexedEpochInfo {
250 let event = IndexedEpochInfoEvent::from(event);
251 Self {
252 epoch: last_checkpoint_summary.epoch(),
253 epoch_total_transactions: Some(
254 last_checkpoint_summary.network_total_transactions
255 - network_total_tx_num_at_last_epoch_end,
256 ),
257 last_checkpoint_id: Some(*last_checkpoint_summary.sequence_number()),
258 epoch_end_timestamp: Some(last_checkpoint_summary.timestamp_ms),
259 storage_charge: Some(event.storage_charge),
260 storage_rebate: Some(event.storage_rebate),
261 total_gas_fees: Some(event.total_gas_fees),
262 total_stake_rewards_distributed: Some(event.total_stake_rewards_distributed),
263 epoch_commitments: last_checkpoint_summary
264 .end_of_epoch_data
265 .as_ref()
266 .map(|e| e.epoch_commitments.clone()),
267 system_state: bcs::to_bytes(system_state_summary).unwrap(),
268 first_checkpoint_id: 0,
271 epoch_start_timestamp: 0,
272 reference_gas_price: 0,
273 protocol_version: 0,
274 total_stake: 0,
275 storage_fund_balance: 0,
276 burnt_tokens_amount: Some(event.burnt_tokens_amount),
277 minted_tokens_amount: Some(event.minted_tokens_amount),
278 tips_amount: Some(event.tips_amount),
279 }
280 }
281}
282
283#[derive(Debug, Clone, Default)]
284pub(crate) struct IndexedEpochInfoEvent {
285 pub storage_charge: u64,
286 pub storage_rebate: u64,
287 pub total_gas_fees: u64,
288 pub total_stake_rewards_distributed: u64,
289 pub burnt_tokens_amount: u64,
290 pub minted_tokens_amount: u64,
291 pub tips_amount: u64,
292}
293
294impl From<&SystemEpochInfoEventV1> for IndexedEpochInfoEvent {
295 fn from(event: &SystemEpochInfoEventV1) -> Self {
296 Self {
297 storage_charge: event.storage_charge,
298 storage_rebate: event.storage_rebate,
299 total_gas_fees: event.total_gas_fees,
300 total_stake_rewards_distributed: event.total_stake_rewards_distributed,
301 burnt_tokens_amount: event.burnt_tokens_amount,
302 minted_tokens_amount: event.minted_tokens_amount,
303 tips_amount: 0,
304 }
305 }
306}
307
308impl From<&SystemEpochInfoEventV2> for IndexedEpochInfoEvent {
309 fn from(event: &SystemEpochInfoEventV2) -> Self {
310 Self {
311 storage_charge: event.storage_charge,
312 storage_rebate: event.storage_rebate,
313 total_gas_fees: event.total_gas_fees,
314 total_stake_rewards_distributed: event.total_stake_rewards_distributed,
315 burnt_tokens_amount: event.burnt_tokens_amount,
316 minted_tokens_amount: event.minted_tokens_amount,
317 tips_amount: event.tips_amount,
318 }
319 }
320}
321
322impl From<&SystemEpochInfoEvent> for IndexedEpochInfoEvent {
323 fn from(event: &SystemEpochInfoEvent) -> Self {
324 match event {
325 SystemEpochInfoEvent::V1(inner) => inner.into(),
326 SystemEpochInfoEvent::V2(inner) => inner.into(),
327 }
328 }
329}
330
331#[derive(Debug, Clone)]
332pub struct IndexedEvent {
333 pub tx_sequence_number: u64,
334 pub event_sequence_number: u64,
335 pub checkpoint_sequence_number: u64,
336 pub transaction_digest: TransactionDigest,
337 pub senders: Vec<IotaAddress>,
338 pub package: ObjectID,
339 pub module: String,
340 pub event_type: String,
341 pub event_type_package: ObjectID,
342 pub event_type_module: String,
343 pub event_type_name: String,
345 pub bcs: Vec<u8>,
346 pub timestamp_ms: u64,
347}
348
349impl IndexedEvent {
350 pub fn from_event(
351 tx_sequence_number: u64,
352 event_sequence_number: u64,
353 checkpoint_sequence_number: u64,
354 transaction_digest: TransactionDigest,
355 event: &iota_types::event::Event,
356 timestamp_ms: u64,
357 ) -> Self {
358 Self {
359 tx_sequence_number,
360 event_sequence_number,
361 checkpoint_sequence_number,
362 transaction_digest,
363 senders: vec![event.sender],
364 package: event.package_id,
365 module: event.transaction_module.to_string(),
366 event_type: event.type_.to_canonical_string(true),
367 event_type_package: event.type_.address.into(),
368 event_type_module: event.type_.module.to_string(),
369 event_type_name: event.type_.name.to_string(),
370 bcs: event.contents.clone(),
371 timestamp_ms,
372 }
373 }
374}
375
376#[derive(Debug, Clone)]
377pub struct EventIndex {
378 pub tx_sequence_number: u64,
379 pub event_sequence_number: u64,
380 pub sender: IotaAddress,
381 pub emit_package: ObjectID,
382 pub emit_module: String,
383 pub type_package: ObjectID,
384 pub type_module: String,
385 pub type_name: String,
387 pub type_instantiation: String,
390}
391
392impl EventIndex {
393 pub fn from_event(
394 tx_sequence_number: u64,
395 event_sequence_number: u64,
396 event: &iota_types::event::Event,
397 ) -> Self {
398 let type_instantiation = event
399 .type_
400 .to_canonical_string(true)
401 .splitn(3, "::")
402 .collect::<Vec<_>>()[2]
403 .to_string();
404 Self {
405 tx_sequence_number,
406 event_sequence_number,
407 sender: event.sender,
408 emit_package: event.package_id,
409 emit_module: event.transaction_module.to_string(),
410 type_package: event.type_.address.into(),
411 type_module: event.type_.module.to_string(),
412 type_name: event.type_.name.to_string(),
413 type_instantiation,
414 }
415 }
416}
417
418#[derive(Debug, Copy, Clone)]
419pub enum OwnerType {
420 Immutable = 0,
421 Address = 1,
422 Object = 2,
423 Shared = 3,
424}
425
426pub enum ObjectStatus {
427 Active = 0,
428 WrappedOrDeleted = 1,
429}
430
431impl TryFrom<i16> for ObjectStatus {
432 type Error = IndexerError;
433
434 fn try_from(value: i16) -> Result<Self, Self::Error> {
435 Ok(match value {
436 0 => ObjectStatus::Active,
437 1 => ObjectStatus::WrappedOrDeleted,
438 value => {
439 return Err(IndexerError::PersistentStorageDataCorruption(format!(
440 "{value} as ObjectStatus"
441 )));
442 }
443 })
444 }
445}
446
447impl TryFrom<i16> for OwnerType {
448 type Error = IndexerError;
449
450 fn try_from(value: i16) -> Result<Self, Self::Error> {
451 Ok(match value {
452 0 => OwnerType::Immutable,
453 1 => OwnerType::Address,
454 2 => OwnerType::Object,
455 3 => OwnerType::Shared,
456 value => {
457 return Err(IndexerError::PersistentStorageDataCorruption(format!(
458 "{value} as OwnerType"
459 )));
460 }
461 })
462 }
463}
464
465pub fn owner_to_owner_info(owner: &Owner) -> (OwnerType, Option<IotaAddress>) {
467 match owner {
468 Owner::AddressOwner(address) => (OwnerType::Address, Some(*address)),
469 Owner::ObjectOwner(address) => (OwnerType::Object, Some(*address)),
470 Owner::Shared { .. } => (OwnerType::Shared, None),
471 Owner::Immutable => (OwnerType::Immutable, None),
472 }
473}
474
475#[derive(Debug, Copy, Clone)]
476pub enum DynamicFieldKind {
477 DynamicField = 0,
478 DynamicObject = 1,
479}
480
481#[derive(Clone, Debug)]
482pub struct IndexedObject {
483 pub checkpoint_sequence_number: CheckpointSequenceNumber,
484 pub object: Object,
485 pub df_kind: Option<DynamicFieldType>,
486}
487
488impl IndexedObject {
489 pub fn from_object(
490 checkpoint_sequence_number: CheckpointSequenceNumber,
491 object: Object,
492 df_kind: Option<DynamicFieldType>,
493 ) -> Self {
494 Self {
495 checkpoint_sequence_number,
496 object,
497 df_kind,
498 }
499 }
500}
501
502#[derive(Clone, Debug)]
503pub struct IndexedDeletedObject {
504 pub object_id: ObjectID,
505 pub object_version: u64,
506 pub checkpoint_sequence_number: u64,
507}
508
509#[derive(Debug)]
510pub struct IndexedPackage {
511 pub package_id: ObjectID,
512 pub move_package: MovePackage,
513 pub checkpoint_sequence_number: u64,
514}
515
516#[derive(Debug, Clone)]
517pub struct IndexedTransaction {
518 pub tx_sequence_number: u64,
519 pub tx_digest: TransactionDigest,
520 pub sender_signed_data: SenderSignedData,
521 pub effects: TransactionEffects,
522 pub checkpoint_sequence_number: u64,
523 pub timestamp_ms: u64,
524 pub object_changes: Vec<IndexedObjectChange>,
525 pub balance_change: Vec<iota_json_rpc_types::BalanceChange>,
526 pub events: Vec<iota_types::event::Event>,
527 pub transaction_kind: IotaTransactionKind,
528 pub successful_tx_num: u64,
529}
530
531#[derive(Debug, Clone)]
532pub struct TxIndex {
533 pub tx_sequence_number: u64,
534 pub tx_kind: IotaTransactionKind,
535 pub transaction_digest: TransactionDigest,
536 pub checkpoint_sequence_number: u64,
537 pub input_objects: Vec<ObjectID>,
538 pub changed_objects: Vec<ObjectID>,
539 pub payers: Vec<IotaAddress>,
540 pub sender: IotaAddress,
541 pub recipients: Vec<IotaAddress>,
542 pub move_calls: Vec<(ObjectID, String, String)>,
543}
544
545#[serde_as]
547#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
548pub enum IndexedObjectChange {
549 Published {
550 package_id: ObjectID,
551 version: SequenceNumber,
552 digest: ObjectDigest,
553 modules: Vec<String>,
554 },
555 Transferred {
556 sender: IotaAddress,
557 recipient: Owner,
558 #[serde_as(as = "IotaStructTag")]
559 object_type: StructTag,
560 object_id: ObjectID,
561 version: SequenceNumber,
562 digest: ObjectDigest,
563 },
564 Mutated {
566 sender: IotaAddress,
567 owner: Owner,
568 #[serde_as(as = "IotaStructTag")]
569 object_type: StructTag,
570 object_id: ObjectID,
571 version: SequenceNumber,
572 previous_version: SequenceNumber,
573 digest: ObjectDigest,
574 },
575 Deleted {
577 sender: IotaAddress,
578 #[serde_as(as = "IotaStructTag")]
579 object_type: StructTag,
580 object_id: ObjectID,
581 version: SequenceNumber,
582 },
583 Wrapped {
585 sender: IotaAddress,
586 #[serde_as(as = "IotaStructTag")]
587 object_type: StructTag,
588 object_id: ObjectID,
589 version: SequenceNumber,
590 },
591 Created {
593 sender: IotaAddress,
594 owner: Owner,
595 #[serde_as(as = "IotaStructTag")]
596 object_type: StructTag,
597 object_id: ObjectID,
598 version: SequenceNumber,
599 digest: ObjectDigest,
600 },
601}
602
603impl From<ObjectChange> for IndexedObjectChange {
604 fn from(oc: ObjectChange) -> Self {
605 match oc {
606 ObjectChange::Published {
607 package_id,
608 version,
609 digest,
610 modules,
611 } => Self::Published {
612 package_id,
613 version,
614 digest,
615 modules,
616 },
617 ObjectChange::Transferred {
618 sender,
619 recipient,
620 object_type,
621 object_id,
622 version,
623 digest,
624 } => Self::Transferred {
625 sender,
626 recipient,
627 object_type,
628 object_id,
629 version,
630 digest,
631 },
632 ObjectChange::Mutated {
633 sender,
634 owner,
635 object_type,
636 object_id,
637 version,
638 previous_version,
639 digest,
640 } => Self::Mutated {
641 sender,
642 owner,
643 object_type,
644 object_id,
645 version,
646 previous_version,
647 digest,
648 },
649 ObjectChange::Deleted {
650 sender,
651 object_type,
652 object_id,
653 version,
654 } => Self::Deleted {
655 sender,
656 object_type,
657 object_id,
658 version,
659 },
660 ObjectChange::Wrapped {
661 sender,
662 object_type,
663 object_id,
664 version,
665 } => Self::Wrapped {
666 sender,
667 object_type,
668 object_id,
669 version,
670 },
671 ObjectChange::Created {
672 sender,
673 owner,
674 object_type,
675 object_id,
676 version,
677 digest,
678 } => Self::Created {
679 sender,
680 owner,
681 object_type,
682 object_id,
683 version,
684 digest,
685 },
686 }
687 }
688}
689
690impl From<IndexedObjectChange> for ObjectChange {
691 fn from(val: IndexedObjectChange) -> Self {
692 match val {
693 IndexedObjectChange::Published {
694 package_id,
695 version,
696 digest,
697 modules,
698 } => ObjectChange::Published {
699 package_id,
700 version,
701 digest,
702 modules,
703 },
704 IndexedObjectChange::Transferred {
705 sender,
706 recipient,
707 object_type,
708 object_id,
709 version,
710 digest,
711 } => ObjectChange::Transferred {
712 sender,
713 recipient,
714 object_type,
715 object_id,
716 version,
717 digest,
718 },
719 IndexedObjectChange::Mutated {
720 sender,
721 owner,
722 object_type,
723 object_id,
724 version,
725 previous_version,
726 digest,
727 } => ObjectChange::Mutated {
728 sender,
729 owner,
730 object_type,
731 object_id,
732 version,
733 previous_version,
734 digest,
735 },
736 IndexedObjectChange::Deleted {
737 sender,
738 object_type,
739 object_id,
740 version,
741 } => ObjectChange::Deleted {
742 sender,
743 object_type,
744 object_id,
745 version,
746 },
747 IndexedObjectChange::Wrapped {
748 sender,
749 object_type,
750 object_id,
751 version,
752 } => ObjectChange::Wrapped {
753 sender,
754 object_type,
755 object_id,
756 version,
757 },
758 IndexedObjectChange::Created {
759 sender,
760 owner,
761 object_type,
762 object_id,
763 version,
764 digest,
765 } => ObjectChange::Created {
766 sender,
767 owner,
768 object_type,
769 object_id,
770 version,
771 digest,
772 },
773 }
774 }
775}
776
777pub struct IotaTransactionBlockResponseWithOptions {
779 pub response: IotaTransactionBlockResponse,
780 pub options: IotaTransactionBlockResponseOptions,
781}
782
783impl From<IotaTransactionBlockResponseWithOptions> for IotaTransactionBlockResponse {
784 fn from(value: IotaTransactionBlockResponseWithOptions) -> Self {
785 let IotaTransactionBlockResponseWithOptions { response, options } = value;
786
787 IotaTransactionBlockResponse {
788 digest: response.digest,
789 transaction: options.show_input.then_some(response.transaction).flatten(),
790 raw_transaction: options
791 .show_raw_input
792 .then_some(response.raw_transaction)
793 .unwrap_or_default(),
794 effects: options.show_effects.then_some(response.effects).flatten(),
795 events: options.show_events.then_some(response.events).flatten(),
796 object_changes: options
797 .show_object_changes
798 .then_some(response.object_changes)
799 .flatten(),
800 balance_changes: options
801 .show_balance_changes
802 .then_some(response.balance_changes)
803 .flatten(),
804 timestamp_ms: response.timestamp_ms,
805 confirmed_local_execution: response.confirmed_local_execution,
806 checkpoint: response.checkpoint,
807 errors: vec![],
808 raw_effects: options
809 .show_raw_effects
810 .then_some(response.raw_effects)
811 .unwrap_or_default(),
812 }
813 }
814}