1use serde::{Deserialize, Deserializer, Serialize, Serializer};
6use serde_with::{DeserializeAs, SerializeAs};
7
8use super::Argument;
9use crate::{ObjectId, ObjectReference};
10
11mod transaction_kind {
12 use super::*;
13 use crate::transaction::{
14 AuthenticatorStateUpdateV1, ConsensusCommitPrologueV1, EndOfEpochTransactionKind,
15 GenesisTransaction, ProgrammableTransaction, RandomnessStateUpdate, TransactionKind,
16 };
17
18 #[derive(serde::Serialize)]
19 #[serde(tag = "kind", rename_all = "snake_case")]
20 enum ReadableTransactionKindRef<'a> {
21 ProgrammableTransaction(&'a ProgrammableTransaction),
22 Genesis(&'a GenesisTransaction),
23 ConsensusCommitPrologueV1(&'a ConsensusCommitPrologueV1),
24 AuthenticatorStateUpdateV1(&'a AuthenticatorStateUpdateV1),
25 EndOfEpoch {
26 commands: &'a Vec<EndOfEpochTransactionKind>,
27 },
28 RandomnessStateUpdate(&'a RandomnessStateUpdate),
29 }
30
31 #[derive(serde::Deserialize)]
32 #[serde(tag = "kind", rename_all = "snake_case")]
33 #[serde(rename = "TransactionKind")]
34 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
35 enum ReadableTransactionKind {
36 ProgrammableTransaction(ProgrammableTransaction),
37 Genesis(GenesisTransaction),
38 ConsensusCommitPrologueV1(ConsensusCommitPrologueV1),
39 AuthenticatorStateUpdateV1(AuthenticatorStateUpdateV1),
40 EndOfEpoch {
41 commands: Vec<EndOfEpochTransactionKind>,
42 },
43 RandomnessStateUpdate(RandomnessStateUpdate),
44 }
45
46 #[cfg(feature = "schemars")]
47 impl schemars::JsonSchema for TransactionKind {
48 fn schema_name() -> String {
49 ReadableTransactionKind::schema_name()
50 }
51
52 fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
53 ReadableTransactionKind::json_schema(gen)
54 }
55 }
56
57 #[derive(serde::Serialize)]
58 enum BinaryTransactionKindRef<'a> {
59 ProgrammableTransaction(&'a ProgrammableTransaction),
60 Genesis(&'a GenesisTransaction),
61 ConsensusCommitPrologueV1(&'a ConsensusCommitPrologueV1),
62 AuthenticatorStateUpdateV1(&'a AuthenticatorStateUpdateV1),
63 EndOfEpoch(&'a Vec<EndOfEpochTransactionKind>),
64 RandomnessStateUpdate(&'a RandomnessStateUpdate),
65 }
66 #[derive(serde::Deserialize)]
67 enum BinaryTransactionKind {
68 ProgrammableTransaction(ProgrammableTransaction),
69 Genesis(GenesisTransaction),
70 ConsensusCommitPrologueV1(ConsensusCommitPrologueV1),
71 AuthenticatorStateUpdateV1(AuthenticatorStateUpdateV1),
72 EndOfEpoch(Vec<EndOfEpochTransactionKind>),
73 RandomnessStateUpdate(RandomnessStateUpdate),
74 }
75
76 impl Serialize for TransactionKind {
77 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
78 where
79 S: Serializer,
80 {
81 if serializer.is_human_readable() {
82 let readable = match self {
83 Self::ProgrammableTransaction(k) => {
84 ReadableTransactionKindRef::ProgrammableTransaction(k)
85 }
86 Self::Genesis(k) => ReadableTransactionKindRef::Genesis(k),
87 Self::ConsensusCommitPrologueV1(k) => {
88 ReadableTransactionKindRef::ConsensusCommitPrologueV1(k)
89 }
90 Self::AuthenticatorStateUpdateV1(k) => {
91 ReadableTransactionKindRef::AuthenticatorStateUpdateV1(k)
92 }
93 Self::EndOfEpoch(commands) => {
94 ReadableTransactionKindRef::EndOfEpoch { commands }
95 }
96 Self::RandomnessStateUpdate(k) => {
97 ReadableTransactionKindRef::RandomnessStateUpdate(k)
98 }
99 };
100 readable.serialize(serializer)
101 } else {
102 let binary = match self {
103 Self::ProgrammableTransaction(k) => {
104 BinaryTransactionKindRef::ProgrammableTransaction(k)
105 }
106 Self::Genesis(k) => BinaryTransactionKindRef::Genesis(k),
107 Self::ConsensusCommitPrologueV1(k) => {
108 BinaryTransactionKindRef::ConsensusCommitPrologueV1(k)
109 }
110 Self::AuthenticatorStateUpdateV1(k) => {
111 BinaryTransactionKindRef::AuthenticatorStateUpdateV1(k)
112 }
113 Self::EndOfEpoch(k) => BinaryTransactionKindRef::EndOfEpoch(k),
114 Self::RandomnessStateUpdate(k) => {
115 BinaryTransactionKindRef::RandomnessStateUpdate(k)
116 }
117 };
118 binary.serialize(serializer)
119 }
120 }
121 }
122
123 impl<'de> Deserialize<'de> for TransactionKind {
124 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
125 where
126 D: Deserializer<'de>,
127 {
128 if deserializer.is_human_readable() {
129 ReadableTransactionKind::deserialize(deserializer).map(|readable| match readable {
130 ReadableTransactionKind::ProgrammableTransaction(k) => {
131 Self::ProgrammableTransaction(k)
132 }
133 ReadableTransactionKind::Genesis(k) => Self::Genesis(k),
134 ReadableTransactionKind::ConsensusCommitPrologueV1(k) => {
135 Self::ConsensusCommitPrologueV1(k)
136 }
137 ReadableTransactionKind::AuthenticatorStateUpdateV1(k) => {
138 Self::AuthenticatorStateUpdateV1(k)
139 }
140 ReadableTransactionKind::EndOfEpoch { commands } => Self::EndOfEpoch(commands),
141 ReadableTransactionKind::RandomnessStateUpdate(k) => {
142 Self::RandomnessStateUpdate(k)
143 }
144 })
145 } else {
146 BinaryTransactionKind::deserialize(deserializer).map(|binary| match binary {
147 BinaryTransactionKind::ProgrammableTransaction(k) => {
148 Self::ProgrammableTransaction(k)
149 }
150 BinaryTransactionKind::Genesis(k) => Self::Genesis(k),
151 BinaryTransactionKind::ConsensusCommitPrologueV1(k) => {
152 Self::ConsensusCommitPrologueV1(k)
153 }
154 BinaryTransactionKind::AuthenticatorStateUpdateV1(k) => {
155 Self::AuthenticatorStateUpdateV1(k)
156 }
157 BinaryTransactionKind::EndOfEpoch(k) => Self::EndOfEpoch(k),
158 BinaryTransactionKind::RandomnessStateUpdate(k) => {
159 Self::RandomnessStateUpdate(k)
160 }
161 })
162 }
163 }
164 }
165}
166
167mod end_of_epoch {
168 use super::*;
169 use crate::transaction::{
170 AuthenticatorStateExpire, ChangeEpoch, ChangeEpochV2, ChangeEpochV3,
171 EndOfEpochTransactionKind,
172 };
173
174 #[derive(serde::Serialize)]
175 #[serde(tag = "kind", rename_all = "snake_case")]
176 enum ReadableEndOfEpochTransactionKindRef<'a> {
177 ChangeEpoch(&'a ChangeEpoch),
178 ChangeEpochV2(&'a ChangeEpochV2),
179 ChangeEpochV3(&'a ChangeEpochV3),
180 AuthenticatorStateCreate,
181 AuthenticatorStateExpire(&'a AuthenticatorStateExpire),
182 }
183
184 #[derive(serde::Deserialize)]
185 #[serde(tag = "kind", rename_all = "snake_case")]
186 enum ReadableEndOfEpochTransactionKind {
187 ChangeEpoch(ChangeEpoch),
188 ChangeEpochV2(ChangeEpochV2),
189 ChangeEpochV3(ChangeEpochV3),
190 AuthenticatorStateCreate,
191 AuthenticatorStateExpire(AuthenticatorStateExpire),
192 }
193
194 #[derive(serde::Serialize)]
195 enum BinaryEndOfEpochTransactionKindRef<'a> {
196 ChangeEpoch(&'a ChangeEpoch),
197 ChangeEpochV2(&'a ChangeEpochV2),
198 ChangeEpochV3(&'a ChangeEpochV3),
199 AuthenticatorStateCreate,
200 AuthenticatorStateExpire(&'a AuthenticatorStateExpire),
201 }
202
203 #[derive(serde::Deserialize)]
204 enum BinaryEndOfEpochTransactionKind {
205 ChangeEpoch(ChangeEpoch),
206 ChangeEpochV2(ChangeEpochV2),
207 ChangeEpochV3(ChangeEpochV3),
208 AuthenticatorStateCreate,
209 AuthenticatorStateExpire(AuthenticatorStateExpire),
210 }
211
212 impl Serialize for EndOfEpochTransactionKind {
213 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
214 where
215 S: Serializer,
216 {
217 if serializer.is_human_readable() {
218 let readable = match self {
219 Self::ChangeEpoch(k) => ReadableEndOfEpochTransactionKindRef::ChangeEpoch(k),
220 Self::ChangeEpochV2(k) => {
221 ReadableEndOfEpochTransactionKindRef::ChangeEpochV2(k)
222 }
223 Self::ChangeEpochV3(k) => {
224 ReadableEndOfEpochTransactionKindRef::ChangeEpochV3(k)
225 }
226 Self::AuthenticatorStateCreate => {
227 ReadableEndOfEpochTransactionKindRef::AuthenticatorStateCreate
228 }
229 Self::AuthenticatorStateExpire(k) => {
230 ReadableEndOfEpochTransactionKindRef::AuthenticatorStateExpire(k)
231 }
232 };
233 readable.serialize(serializer)
234 } else {
235 let binary = match self {
236 Self::ChangeEpoch(k) => BinaryEndOfEpochTransactionKindRef::ChangeEpoch(k),
237 Self::ChangeEpochV2(k) => BinaryEndOfEpochTransactionKindRef::ChangeEpochV2(k),
238 Self::ChangeEpochV3(k) => BinaryEndOfEpochTransactionKindRef::ChangeEpochV3(k),
239
240 Self::AuthenticatorStateCreate => {
241 BinaryEndOfEpochTransactionKindRef::AuthenticatorStateCreate
242 }
243 Self::AuthenticatorStateExpire(k) => {
244 BinaryEndOfEpochTransactionKindRef::AuthenticatorStateExpire(k)
245 }
246 };
247 binary.serialize(serializer)
248 }
249 }
250 }
251
252 impl<'de> Deserialize<'de> for EndOfEpochTransactionKind {
253 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
254 where
255 D: Deserializer<'de>,
256 {
257 if deserializer.is_human_readable() {
258 ReadableEndOfEpochTransactionKind::deserialize(deserializer).map(|readable| {
259 match readable {
260 ReadableEndOfEpochTransactionKind::ChangeEpoch(k) => Self::ChangeEpoch(k),
261 ReadableEndOfEpochTransactionKind::ChangeEpochV2(k) => {
262 Self::ChangeEpochV2(k)
263 }
264 ReadableEndOfEpochTransactionKind::ChangeEpochV3(k) => {
265 Self::ChangeEpochV3(k)
266 }
267 ReadableEndOfEpochTransactionKind::AuthenticatorStateCreate => {
268 Self::AuthenticatorStateCreate
269 }
270 ReadableEndOfEpochTransactionKind::AuthenticatorStateExpire(k) => {
271 Self::AuthenticatorStateExpire(k)
272 }
273 }
274 })
275 } else {
276 BinaryEndOfEpochTransactionKind::deserialize(deserializer).map(
277 |binary| match binary {
278 BinaryEndOfEpochTransactionKind::ChangeEpoch(k) => Self::ChangeEpoch(k),
279 BinaryEndOfEpochTransactionKind::ChangeEpochV2(k) => Self::ChangeEpochV2(k),
280 BinaryEndOfEpochTransactionKind::ChangeEpochV3(k) => Self::ChangeEpochV3(k),
281
282 BinaryEndOfEpochTransactionKind::AuthenticatorStateCreate => {
283 Self::AuthenticatorStateCreate
284 }
285 BinaryEndOfEpochTransactionKind::AuthenticatorStateExpire(k) => {
286 Self::AuthenticatorStateExpire(k)
287 }
288 },
289 )
290 }
291 }
292 }
293}
294
295mod version_assignments {
296 use super::*;
297 use crate::transaction::{CancelledTransaction, ConsensusDeterminedVersionAssignments};
298
299 #[derive(serde::Serialize)]
300 #[serde(tag = "kind", rename_all = "snake_case")]
301 enum ReadableConsensusDeterminedVersionAssignmentsRef<'a> {
302 CancelledTransactions {
303 cancelled_transactions: &'a Vec<CancelledTransaction>,
304 },
305 }
306
307 #[derive(serde::Deserialize)]
308 #[serde(tag = "kind", rename_all = "snake_case")]
309 enum ReadableConsensusDeterminedVersionAssignments {
310 CancelledTransactions {
311 cancelled_transactions: Vec<CancelledTransaction>,
312 },
313 }
314
315 #[derive(serde::Serialize)]
316 enum BinaryConsensusDeterminedVersionAssignmentsRef<'a> {
317 CancelledTransactions {
318 cancelled_transactions: &'a Vec<CancelledTransaction>,
319 },
320 }
321
322 #[derive(serde::Deserialize)]
323 enum BinaryConsensusDeterminedVersionAssignments {
324 CancelledTransactions {
325 cancelled_transactions: Vec<CancelledTransaction>,
326 },
327 }
328
329 impl Serialize for ConsensusDeterminedVersionAssignments {
330 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
331 where
332 S: Serializer,
333 {
334 if serializer.is_human_readable() {
335 let readable = match self {
336 Self::CancelledTransactions {
337 cancelled_transactions,
338 } => ReadableConsensusDeterminedVersionAssignmentsRef::CancelledTransactions {
339 cancelled_transactions,
340 },
341 };
342 readable.serialize(serializer)
343 } else {
344 let binary = match self {
345 Self::CancelledTransactions {
346 cancelled_transactions,
347 } => BinaryConsensusDeterminedVersionAssignmentsRef::CancelledTransactions {
348 cancelled_transactions,
349 },
350 };
351 binary.serialize(serializer)
352 }
353 }
354 }
355
356 impl<'de> Deserialize<'de> for ConsensusDeterminedVersionAssignments {
357 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
358 where
359 D: Deserializer<'de>,
360 {
361 if deserializer.is_human_readable() {
362 ReadableConsensusDeterminedVersionAssignments::deserialize(deserializer).map(
363 |readable| match readable {
364 ReadableConsensusDeterminedVersionAssignments::CancelledTransactions {
365 cancelled_transactions,
366 } => Self::CancelledTransactions {
367 cancelled_transactions,
368 },
369 },
370 )
371 } else {
372 BinaryConsensusDeterminedVersionAssignments::deserialize(deserializer).map(
373 |binary| match binary {
374 BinaryConsensusDeterminedVersionAssignments::CancelledTransactions {
375 cancelled_transactions,
376 } => Self::CancelledTransactions {
377 cancelled_transactions,
378 },
379 },
380 )
381 }
382 }
383 }
384}
385
386mod input_argument {
387 use super::*;
388 use crate::transaction::Input;
389
390 #[derive(serde::Serialize, serde::Deserialize)]
391 #[serde(tag = "type", rename_all = "snake_case")]
392 enum ReadableInput {
393 Pure {
394 #[serde(with = "::serde_with::As::<crate::_serde::Base64Encoded>")]
395 value: Vec<u8>,
396 },
397 ImmutableOrOwned(ObjectReference),
398 Shared {
399 object_id: ObjectId,
400 #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
401 initial_shared_version: u64,
402 mutable: bool,
403 },
404 Receiving(ObjectReference),
405 }
406
407 #[derive(serde::Serialize, serde::Deserialize)]
408 enum CallArg {
409 Pure(#[serde(with = "::serde_with::As::<::serde_with::Bytes>")] Vec<u8>),
410 Object(ObjectArg),
411 }
412
413 #[derive(serde::Serialize, serde::Deserialize)]
414 enum ObjectArg {
415 ImmutableOrOwned(ObjectReference),
416 Shared {
417 object_id: ObjectId,
418 initial_shared_version: u64,
419 mutable: bool,
420 },
421 Receiving(ObjectReference),
422 }
423
424 impl Serialize for Input {
425 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
426 where
427 S: Serializer,
428 {
429 if serializer.is_human_readable() {
430 let readable = match self.clone() {
431 Input::Pure { value } => ReadableInput::Pure { value },
432 Input::ImmutableOrOwned(object_ref) => {
433 ReadableInput::ImmutableOrOwned(object_ref)
434 }
435 Input::Shared {
436 object_id,
437 initial_shared_version,
438 mutable,
439 } => ReadableInput::Shared {
440 object_id,
441 initial_shared_version,
442 mutable,
443 },
444 Input::Receiving(object_ref) => ReadableInput::Receiving(object_ref),
445 };
446 readable.serialize(serializer)
447 } else {
448 let binary = match self.clone() {
449 Input::Pure { value } => CallArg::Pure(value),
450 Input::ImmutableOrOwned(object_ref) => {
451 CallArg::Object(ObjectArg::ImmutableOrOwned(object_ref))
452 }
453 Input::Shared {
454 object_id,
455 initial_shared_version,
456 mutable,
457 } => CallArg::Object(ObjectArg::Shared {
458 object_id,
459 initial_shared_version,
460 mutable,
461 }),
462 Input::Receiving(object_ref) => {
463 CallArg::Object(ObjectArg::Receiving(object_ref))
464 }
465 };
466 binary.serialize(serializer)
467 }
468 }
469 }
470
471 impl<'de> Deserialize<'de> for Input {
472 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
473 where
474 D: Deserializer<'de>,
475 {
476 if deserializer.is_human_readable() {
477 ReadableInput::deserialize(deserializer).map(|readable| match readable {
478 ReadableInput::Pure { value } => Input::Pure { value },
479 ReadableInput::ImmutableOrOwned(object_ref) => {
480 Input::ImmutableOrOwned(object_ref)
481 }
482 ReadableInput::Shared {
483 object_id,
484 initial_shared_version,
485 mutable,
486 } => Input::Shared {
487 object_id,
488 initial_shared_version,
489 mutable,
490 },
491 ReadableInput::Receiving(object_ref) => Input::Receiving(object_ref),
492 })
493 } else {
494 CallArg::deserialize(deserializer).map(|binary| match binary {
495 CallArg::Pure(value) => Input::Pure { value },
496 CallArg::Object(ObjectArg::ImmutableOrOwned(object_ref)) => {
497 Input::ImmutableOrOwned(object_ref)
498 }
499 CallArg::Object(ObjectArg::Shared {
500 object_id,
501 initial_shared_version,
502 mutable,
503 }) => Input::Shared {
504 object_id,
505 initial_shared_version,
506 mutable,
507 },
508 CallArg::Object(ObjectArg::Receiving(object_ref)) => {
509 Input::Receiving(object_ref)
510 }
511 })
512 }
513 }
514 }
515}
516
517mod argument {
518 use super::*;
519
520 #[derive(serde::Serialize, serde::Deserialize)]
521 #[serde(rename = "Argument", untagged, rename_all = "lowercase")]
522 #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
523 enum ReadableArgument {
524 Gas(Gas),
526 Input { input: u16 },
528 Result { result: u16 },
530 NestedResult { result: (u16, u16) },
532 }
533
534 #[derive(serde::Serialize, serde::Deserialize)]
535 #[serde(rename_all = "lowercase")]
536 enum Gas {
537 Gas,
538 }
539
540 #[cfg(feature = "schemars")]
541 impl schemars::JsonSchema for Gas {
542 fn schema_name() -> std::string::String {
543 "GasArgument".to_owned()
544 }
545
546 fn json_schema(_gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
547 schemars::schema::Schema::Object(schemars::schema::SchemaObject {
548 instance_type: Some(schemars::schema::InstanceType::String.into()),
549 enum_values: Some(vec!["gas".into()]),
550 ..Default::default()
551 })
552 }
553
554 fn is_referenceable() -> bool {
555 false
556 }
557 }
558
559 #[cfg(feature = "schemars")]
560 impl schemars::JsonSchema for Argument {
561 fn schema_name() -> String {
562 ReadableArgument::schema_name()
563 }
564
565 fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
566 ReadableArgument::json_schema(gen)
567 }
568 }
569
570 #[derive(serde::Serialize, serde::Deserialize)]
571 enum BinaryArgument {
572 Gas,
573 Input(u16),
574 Result(u16),
575 NestedResult(u16, u16),
576 }
577
578 impl Serialize for Argument {
579 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
580 where
581 S: Serializer,
582 {
583 if serializer.is_human_readable() {
584 let readable = match *self {
585 Argument::Gas => ReadableArgument::Gas(Gas::Gas),
586 Argument::Input(input) => ReadableArgument::Input { input },
587 Argument::Result(result) => ReadableArgument::Result { result },
588 Argument::NestedResult(result, subresult) => ReadableArgument::NestedResult {
589 result: (result, subresult),
590 },
591 };
592 readable.serialize(serializer)
593 } else {
594 let binary = match *self {
595 Argument::Gas => BinaryArgument::Gas,
596 Argument::Input(input) => BinaryArgument::Input(input),
597 Argument::Result(result) => BinaryArgument::Result(result),
598 Argument::NestedResult(result, subresult) => {
599 BinaryArgument::NestedResult(result, subresult)
600 }
601 };
602 binary.serialize(serializer)
603 }
604 }
605 }
606
607 impl<'de> Deserialize<'de> for Argument {
608 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
609 where
610 D: Deserializer<'de>,
611 {
612 if deserializer.is_human_readable() {
613 ReadableArgument::deserialize(deserializer).map(|readable| match readable {
614 ReadableArgument::Gas(_) => Argument::Gas,
615 ReadableArgument::Input { input } => Argument::Input(input),
616 ReadableArgument::Result { result } => Argument::Result(result),
617 ReadableArgument::NestedResult {
618 result: (result, subresult),
619 } => Argument::NestedResult(result, subresult),
620 })
621 } else {
622 BinaryArgument::deserialize(deserializer).map(|binary| match binary {
623 BinaryArgument::Gas => Argument::Gas,
624 BinaryArgument::Input(input) => Argument::Input(input),
625 BinaryArgument::Result(result) => Argument::Result(result),
626 BinaryArgument::NestedResult(result, subresult) => {
627 Argument::NestedResult(result, subresult)
628 }
629 })
630 }
631 }
632 }
633}
634
635mod command {
636 use super::*;
637 use crate::transaction::{
638 Command, MakeMoveVector, MergeCoins, MoveCall, Publish, SplitCoins, TransferObjects,
639 Upgrade,
640 };
641
642 #[derive(serde::Serialize)]
643 #[serde(tag = "command", rename_all = "snake_case")]
644 enum ReadableCommandRef<'a> {
645 MoveCall(&'a MoveCall),
646 TransferObjects(&'a TransferObjects),
647 SplitCoins(&'a SplitCoins),
648 MergeCoins(&'a MergeCoins),
649 Publish(&'a Publish),
650 MakeMoveVector(&'a MakeMoveVector),
651 Upgrade(&'a Upgrade),
652 }
653
654 #[derive(serde::Deserialize)]
655 #[serde(tag = "command", rename_all = "snake_case")]
656 enum ReadableCommand {
657 MoveCall(MoveCall),
658 TransferObjects(TransferObjects),
659 SplitCoins(SplitCoins),
660 MergeCoins(MergeCoins),
661 Publish(Publish),
662 MakeMoveVector(MakeMoveVector),
663 Upgrade(Upgrade),
664 }
665
666 #[derive(serde::Serialize)]
667 enum BinaryCommandRef<'a> {
668 MoveCall(&'a MoveCall),
669 TransferObjects(&'a TransferObjects),
670 SplitCoins(&'a SplitCoins),
671 MergeCoins(&'a MergeCoins),
672 Publish(&'a Publish),
673 MakeMoveVector(&'a MakeMoveVector),
674 Upgrade(&'a Upgrade),
675 }
676
677 #[derive(serde::Deserialize)]
678 enum BinaryCommand {
679 MoveCall(MoveCall),
680 TransferObjects(TransferObjects),
681 SplitCoins(SplitCoins),
682 MergeCoins(MergeCoins),
683 Publish(Publish),
684 MakeMoveVector(MakeMoveVector),
685 Upgrade(Upgrade),
686 }
687
688 impl Serialize for Command {
689 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
690 where
691 S: Serializer,
692 {
693 if serializer.is_human_readable() {
694 let readable = match self {
695 Command::MoveCall(c) => ReadableCommandRef::MoveCall(c),
696 Command::TransferObjects(c) => ReadableCommandRef::TransferObjects(c),
697 Command::SplitCoins(c) => ReadableCommandRef::SplitCoins(c),
698 Command::MergeCoins(c) => ReadableCommandRef::MergeCoins(c),
699 Command::Publish(c) => ReadableCommandRef::Publish(c),
700 Command::MakeMoveVector(c) => ReadableCommandRef::MakeMoveVector(c),
701 Command::Upgrade(c) => ReadableCommandRef::Upgrade(c),
702 };
703 readable.serialize(serializer)
704 } else {
705 let binary = match self {
706 Command::MoveCall(c) => BinaryCommandRef::MoveCall(c),
707 Command::TransferObjects(c) => BinaryCommandRef::TransferObjects(c),
708 Command::SplitCoins(c) => BinaryCommandRef::SplitCoins(c),
709 Command::MergeCoins(c) => BinaryCommandRef::MergeCoins(c),
710 Command::Publish(c) => BinaryCommandRef::Publish(c),
711 Command::MakeMoveVector(c) => BinaryCommandRef::MakeMoveVector(c),
712 Command::Upgrade(c) => BinaryCommandRef::Upgrade(c),
713 };
714 binary.serialize(serializer)
715 }
716 }
717 }
718
719 impl<'de> Deserialize<'de> for Command {
720 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
721 where
722 D: Deserializer<'de>,
723 {
724 if deserializer.is_human_readable() {
725 ReadableCommand::deserialize(deserializer).map(|readable| match readable {
726 ReadableCommand::MoveCall(c) => Command::MoveCall(c),
727 ReadableCommand::TransferObjects(c) => Command::TransferObjects(c),
728 ReadableCommand::SplitCoins(c) => Command::SplitCoins(c),
729 ReadableCommand::MergeCoins(c) => Command::MergeCoins(c),
730 ReadableCommand::Publish(c) => Command::Publish(c),
731 ReadableCommand::MakeMoveVector(c) => Command::MakeMoveVector(c),
732 ReadableCommand::Upgrade(c) => Command::Upgrade(c),
733 })
734 } else {
735 BinaryCommand::deserialize(deserializer).map(|binary| match binary {
736 BinaryCommand::MoveCall(c) => Command::MoveCall(c),
737 BinaryCommand::TransferObjects(c) => Command::TransferObjects(c),
738 BinaryCommand::SplitCoins(c) => Command::SplitCoins(c),
739 BinaryCommand::MergeCoins(c) => Command::MergeCoins(c),
740 BinaryCommand::Publish(c) => Command::Publish(c),
741 BinaryCommand::MakeMoveVector(c) => Command::MakeMoveVector(c),
742 BinaryCommand::Upgrade(c) => Command::Upgrade(c),
743 })
744 }
745 }
746 }
747}
748
749pub(crate) use signed_transaction::SignedTransactionWithIntentMessage;
750
751mod signed_transaction {
752 use serde::ser::SerializeSeq;
753
754 use super::*;
755 use crate::{
756 UserSignature,
757 transaction::{SignedTransaction, Transaction},
758 };
759
760 struct IntentMessageWrappedTransaction;
791
792 impl SerializeAs<Transaction> for IntentMessageWrappedTransaction {
793 fn serialize_as<S>(transaction: &Transaction, serializer: S) -> Result<S::Ok, S::Error>
794 where
795 S: Serializer,
796 {
797 use serde::ser::SerializeTuple;
798
799 let mut s = serializer.serialize_tuple(4)?;
800 s.serialize_element(&0u8)?;
801 s.serialize_element(&0u8)?;
802 s.serialize_element(&0u8)?;
803 s.serialize_element(transaction)?;
804 s.end()
805 }
806 }
807
808 impl<'de> DeserializeAs<'de, Transaction> for IntentMessageWrappedTransaction {
809 fn deserialize_as<D>(deserializer: D) -> Result<Transaction, D::Error>
810 where
811 D: Deserializer<'de>,
812 {
813 let (scope, version, app, transaction): (u8, u8, u8, Transaction) =
814 Deserialize::deserialize(deserializer)?;
815 match (scope, version, app) {
816 (0, 0, 0) => {}
817 _ => {
818 return Err(serde::de::Error::custom(format!(
819 "invalid intent message ({scope}, {version}, {app})"
820 )));
821 }
822 }
823
824 Ok(transaction)
825 }
826 }
827
828 pub(crate) struct SignedTransactionWithIntentMessage;
829
830 #[derive(serde::Serialize)]
831 struct BinarySignedTransactionWithIntentMessageRef<'a> {
832 #[serde(with = "::serde_with::As::<IntentMessageWrappedTransaction>")]
833 transaction: &'a Transaction,
834 signatures: &'a Vec<UserSignature>,
835 }
836
837 #[derive(serde::Deserialize)]
838 struct BinarySignedTransactionWithIntentMessage {
839 #[serde(with = "::serde_with::As::<IntentMessageWrappedTransaction>")]
840 transaction: Transaction,
841 signatures: Vec<UserSignature>,
842 }
843
844 impl SerializeAs<SignedTransaction> for SignedTransactionWithIntentMessage {
845 fn serialize_as<S>(
846 transaction: &SignedTransaction,
847 serializer: S,
848 ) -> Result<S::Ok, S::Error>
849 where
850 S: Serializer,
851 {
852 if serializer.is_human_readable() {
853 transaction.serialize(serializer)
854 } else {
855 let SignedTransaction {
856 transaction,
857 signatures,
858 } = transaction;
859 let binary = BinarySignedTransactionWithIntentMessageRef {
860 transaction,
861 signatures,
862 };
863
864 let mut s = serializer.serialize_seq(Some(1))?;
865 s.serialize_element(&binary)?;
866 s.end()
867 }
868 }
869 }
870
871 impl<'de> DeserializeAs<'de, SignedTransaction> for SignedTransactionWithIntentMessage {
872 fn deserialize_as<D>(deserializer: D) -> Result<SignedTransaction, D::Error>
873 where
874 D: Deserializer<'de>,
875 {
876 if deserializer.is_human_readable() {
877 SignedTransaction::deserialize(deserializer)
878 } else {
879 struct V;
880 impl<'de> serde::de::Visitor<'de> for V {
881 type Value = SignedTransaction;
882
883 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
884 formatter.write_str("expected a sequence with length 1")
885 }
886
887 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
888 where
889 A: serde::de::SeqAccess<'de>,
890 {
891 if seq.size_hint().is_some_and(|size| size != 1) {
892 return Err(serde::de::Error::custom(
893 "expected a sequence with length 1",
894 ));
895 }
896
897 let BinarySignedTransactionWithIntentMessage {
898 transaction,
899 signatures,
900 } = seq.next_element()?.ok_or_else(|| {
901 serde::de::Error::custom("expected a sequence with length 1")
902 })?;
903 Ok(SignedTransaction {
904 transaction,
905 signatures,
906 })
907 }
908 }
909
910 deserializer.deserialize_seq(V)
911 }
912 }
913 }
914}
915
916mod transaction_expiration {
917 use serde::{Deserialize, Deserializer, Serialize, Serializer};
918
919 use crate::{EpochId, TransactionExpiration};
920
921 #[derive(serde::Serialize, serde::Deserialize)]
922 #[serde(rename = "TransactionExpiration")]
923 #[serde(rename_all = "lowercase")]
924 enum ReadableTransactionExpiration {
925 Epoch(
928 #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))] EpochId,
929 ),
930 }
931
932 #[derive(serde::Serialize, serde::Deserialize)]
933 pub enum BinaryTransactionExpiration {
934 None,
936 Epoch(EpochId),
939 }
940
941 impl Serialize for TransactionExpiration {
942 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
943 where
944 S: Serializer,
945 {
946 if serializer.is_human_readable() {
947 match *self {
948 Self::None => None,
949 Self::Epoch(epoch) => Some(ReadableTransactionExpiration::Epoch(epoch)),
950 }
951 .serialize(serializer)
952 } else {
953 match *self {
954 Self::None => BinaryTransactionExpiration::None,
955 Self::Epoch(epoch) => BinaryTransactionExpiration::Epoch(epoch),
956 }
957 .serialize(serializer)
958 }
959 }
960 }
961
962 impl<'de> Deserialize<'de> for TransactionExpiration {
963 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
964 where
965 D: Deserializer<'de>,
966 {
967 if deserializer.is_human_readable() {
968 Option::<ReadableTransactionExpiration>::deserialize(deserializer).map(|readable| {
969 match readable {
970 None => Self::None,
971 Some(ReadableTransactionExpiration::Epoch(epoch)) => Self::Epoch(epoch),
972 }
973 })
974 } else {
975 BinaryTransactionExpiration::deserialize(deserializer).map(|binary| match binary {
976 BinaryTransactionExpiration::None => Self::None,
977 BinaryTransactionExpiration::Epoch(epoch) => Self::Epoch(epoch),
978 })
979 }
980 }
981 }
982
983 #[cfg(feature = "schemars")]
984 impl schemars::JsonSchema for TransactionExpiration {
985 fn schema_name() -> String {
986 "TransactionExpiration".into()
987 }
988
989 fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
990 use schemars::{
991 Map, Set,
992 schema::{
993 InstanceType, ObjectValidation, Schema, SchemaObject, SubschemaValidation,
994 },
995 };
996 let mut object = SchemaObject {
997 instance_type: Some(InstanceType::Object.into()),
998 object: Some(Box::new(ObjectValidation {
999 properties: {
1000 let mut props = Map::new();
1001 props.insert(
1002 "epoch".to_owned(),
1003 gen.subschema_for::<crate::_schemars::U64>(),
1004 );
1005 props
1006 },
1007 required: {
1008 let mut required = Set::new();
1009 required.insert("epoch".to_owned());
1010 required
1011 },
1012 additional_properties: Some(Box::new(false.into())),
1019 ..Default::default()
1020 })),
1021 ..Default::default()
1022 };
1023 object.metadata().description = Some("Validators wont sign a transaction unless the expiration Epoch is greater than or equal to the current epoch".to_owned());
1024 let schema = Schema::Object(object);
1025 Schema::Object(SchemaObject {
1026 subschemas: Some(Box::new(SubschemaValidation {
1027 one_of: Some(vec![
1028 schema,
1029 Schema::Object(SchemaObject {
1030 instance_type: Some(InstanceType::Null.into()),
1031 ..SchemaObject::default()
1032 }),
1033 ]),
1034 ..Default::default()
1035 })),
1036 ..Default::default()
1037 })
1038 }
1039 }
1040}
1041
1042#[cfg(test)]
1043mod tests {
1044 use base64ct::{Base64, Encoding};
1045 #[cfg(target_arch = "wasm32")]
1046 use wasm_bindgen_test::wasm_bindgen_test as test;
1047
1048 use crate::{
1049 Digest, ObjectId, ObjectReference,
1050 transaction::{Argument, Input, Transaction},
1051 };
1052
1053 #[test]
1054 fn argument() {
1055 let test_cases = [
1056 (Argument::Gas, serde_json::json!("gas")),
1057 (Argument::Input(1), serde_json::json!({"input": 1})),
1058 (Argument::Result(2), serde_json::json!({"result": 2})),
1059 (
1060 Argument::NestedResult(3, 4),
1061 serde_json::json!({"result": [3, 4]}),
1062 ),
1063 ];
1064
1065 for (case, expected) in test_cases {
1066 let actual = serde_json::to_value(case).unwrap();
1067 assert_eq!(actual, expected);
1068 println!("{actual}");
1069
1070 let deser = serde_json::from_value(expected).unwrap();
1071 assert_eq!(case, deser);
1072 }
1073 }
1074
1075 #[test]
1076 fn input_argument() {
1077 let test_cases = [
1078 (
1079 Input::Pure {
1080 value: vec![1, 2, 3, 4],
1081 },
1082 serde_json::json!({
1083 "type": "pure",
1084 "value": "AQIDBA=="
1085 }),
1086 ),
1087 (
1088 Input::ImmutableOrOwned(ObjectReference::new(ObjectId::ZERO, 1, Digest::ZERO)),
1089 serde_json::json!({
1090 "type": "immutable_or_owned",
1091 "object_id": "0x0000000000000000000000000000000000000000000000000000000000000000",
1092 "version": "1",
1093 "digest": "11111111111111111111111111111111"
1094 }),
1095 ),
1096 (
1097 Input::Shared {
1098 object_id: ObjectId::ZERO,
1099 initial_shared_version: 1,
1100 mutable: true,
1101 },
1102 serde_json::json!({
1103 "type": "shared",
1104 "object_id": "0x0000000000000000000000000000000000000000000000000000000000000000",
1105 "initial_shared_version": "1",
1106 "mutable": true
1107 }),
1108 ),
1109 (
1110 Input::Receiving(ObjectReference::new(ObjectId::ZERO, 1, Digest::ZERO)),
1111 serde_json::json!({
1112 "type": "receiving",
1113 "object_id": "0x0000000000000000000000000000000000000000000000000000000000000000",
1114 "version": "1",
1115 "digest": "11111111111111111111111111111111"
1116 }),
1117 ),
1118 ];
1119
1120 for (case, expected) in test_cases {
1121 let actual = serde_json::to_value(&case).unwrap();
1122 assert_eq!(actual, expected);
1123 println!("{actual}");
1124
1125 let deser = serde_json::from_value(expected).unwrap();
1126 assert_eq!(case, deser);
1127 }
1128 }
1129
1130 #[test]
1131 fn transaction_fixtures() {
1132 const GENESIS_TRANSACTION: &str = include_str!("fixtures/genesis");
1134 const CONSENSUS_PROLOGUE: &str = include_str!("fixtures/consensus-commit-prologue-v1");
1135 const EPOCH_CHANGE: &str = include_str!("fixtures/change-epoch-v2");
1136 const PTB: &str = include_str!("fixtures/ptb");
1137
1138 for fixture in [GENESIS_TRANSACTION, CONSENSUS_PROLOGUE, EPOCH_CHANGE, PTB] {
1139 let fixture = Base64::decode_vec(fixture.trim()).unwrap();
1140 let tx: Transaction = bcs::from_bytes(&fixture).unwrap();
1141 assert_eq!(bcs::to_bytes(&tx).unwrap(), fixture);
1142
1143 let json = serde_json::to_string_pretty(&tx).unwrap();
1144 println!("{json}");
1145 assert_eq!(tx, serde_json::from_str(&json).unwrap());
1146 }
1147 }
1148}