1use std::collections::BTreeMap;
2
3use super::Address;
4use super::Digest;
5use super::Identifier;
6use super::StructTag;
7
8pub type Version = u64;
9
10#[derive(Clone, Debug, PartialEq, Eq)]
22#[cfg_attr(
23 feature = "serde",
24 derive(serde_derive::Serialize, serde_derive::Deserialize)
25)]
26#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
27pub struct ObjectReference {
28 object_id: Address,
30 version: Version,
32 digest: Digest,
34}
35
36impl ObjectReference {
37 pub fn new(object_id: Address, version: Version, digest: Digest) -> Self {
39 Self {
40 object_id,
41 version,
42 digest,
43 }
44 }
45
46 pub fn object_id(&self) -> &Address {
48 &self.object_id
49 }
50
51 pub fn version(&self) -> Version {
53 self.version
54 }
55
56 pub fn digest(&self) -> &Digest {
58 &self.digest
59 }
60
61 #[cfg(all(feature = "hash", feature = "serde"))]
72 #[cfg_attr(doc_cfg, doc(cfg(all(feature = "hash", feature = "serde"))))]
73 pub fn coin_reservation(
74 coin_type: &crate::StructTag,
75 balance: u64,
76 epoch: u64,
77 chain_id: Digest,
78 owner: Address,
79 ) -> Self {
80 use super::Identifier;
81
82 let accumulator_root = const { Address::from_static("0xacc") };
88
89 let balance_sui_type = StructTag::new(
90 Address::TWO,
91 Identifier::from_static("balance"),
92 Identifier::from_static("Balance"),
93 vec![coin_type.clone().into()],
94 );
95 let key_type_tag: super::TypeTag = StructTag::new(
96 Address::TWO,
97 Identifier::from_static("accumulator"),
98 Identifier::from_static("Key"),
99 vec![balance_sui_type.into()],
100 )
101 .into();
102
103 let object_id = accumulator_root.derive_dynamic_child_id(&key_type_tag, owner.as_ref());
104
105 let masked_id = {
108 let id_bytes = object_id.into_inner();
109 let mask_bytes = chain_id.into_inner();
110 let mut masked = [0u8; 32];
111 for i in 0..32 {
112 masked[i] = id_bytes[i] ^ mask_bytes[i];
113 }
114 Address::new(masked)
115 };
116
117 let digest = {
122 let mut bytes = [0u8; 32];
123 bytes[0..8].copy_from_slice(&balance.to_le_bytes());
124 bytes[8..12].copy_from_slice(&(epoch as u32).to_le_bytes());
125 bytes[12..32].copy_from_slice(&[0xac; 20]);
126 Digest::new(bytes)
127 };
128
129 Self::new(masked_id, 0, digest)
130 }
131
132 pub fn into_parts(self) -> (Address, Version, Digest) {
134 let Self {
135 object_id,
136 version,
137 digest,
138 } = self;
139
140 (object_id, version, digest)
141 }
142}
143
144#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
159#[cfg_attr(
160 feature = "serde",
161 derive(serde_derive::Serialize, serde_derive::Deserialize),
162 serde(rename_all = "lowercase")
163)]
164#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
165#[non_exhaustive]
166pub enum Owner {
167 Address(Address),
169 Object(Address),
171 Shared(
173 Version,
175 ),
176 Immutable,
178
179 ConsensusAddress {
181 start_version: Version,
185
186 owner: Address,
188 },
189}
190
191#[derive(Clone, Debug, PartialEq, Eq, Hash)]
204#[cfg_attr(
205 feature = "serde",
206 derive(serde_derive::Serialize, serde_derive::Deserialize)
207)]
208#[allow(clippy::large_enum_variant)]
209#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
210pub enum ObjectData {
212 Struct(MoveStruct),
214 Package(MovePackage),
216 }
218
219#[derive(Eq, PartialEq, Debug, Clone, Hash)]
233#[cfg_attr(
234 feature = "serde",
235 derive(serde_derive::Serialize, serde_derive::Deserialize)
236)]
237#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
238pub struct MovePackage {
239 pub id: Address,
241
242 pub version: Version,
253
254 #[cfg_attr(
256 feature = "serde",
257 serde(with = "::serde_with::As::<BTreeMap<::serde_with::Same, ::serde_with::Bytes>>")
258 )]
259 #[cfg_attr(
260 feature = "proptest",
261 strategy(
262 proptest::collection::btree_map(proptest::arbitrary::any::<Identifier>(), proptest::collection::vec(proptest::arbitrary::any::<u8>(), 0..=1024), 0..=5)
263 )
264 )]
265 pub modules: BTreeMap<Identifier, Vec<u8>>,
266
267 #[cfg_attr(feature = "proptest", any(proptest::collection::size_range(0..=1).lift()))]
270 pub type_origin_table: Vec<TypeOrigin>,
271
272 #[cfg_attr(
275 feature = "proptest",
276 strategy(
277 proptest::collection::btree_map(proptest::arbitrary::any::<Address>(), proptest::arbitrary::any::<UpgradeInfo>(), 0..=5)
278 )
279 )]
280 pub linkage_table: BTreeMap<Address, UpgradeInfo>,
281}
282
283#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
293#[cfg_attr(
294 feature = "serde",
295 derive(serde_derive::Serialize, serde_derive::Deserialize)
296)]
297#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
298pub struct TypeOrigin {
299 pub module_name: Identifier,
300 pub struct_name: Identifier,
301 pub package: Address,
302}
303
304#[derive(Eq, PartialEq, Debug, Clone, Hash)]
314#[cfg_attr(
315 feature = "serde",
316 derive(serde_derive::Serialize, serde_derive::Deserialize)
317)]
318#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
319pub struct UpgradeInfo {
320 pub upgraded_id: Address,
322 pub upgraded_version: Version,
324}
325
326#[derive(Eq, PartialEq, Debug, Clone, Hash)]
345#[cfg_attr(
347 feature = "serde",
348 derive(serde_derive::Serialize, serde_derive::Deserialize)
349)]
350#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
351pub struct MoveStruct {
352 #[cfg_attr(
354 feature = "serde",
355 serde(with = "::serde_with::As::<serialization::BinaryMoveStructType>")
356 )]
357 pub(crate) type_: StructTag,
358
359 has_public_transfer: bool,
362
363 version: Version,
366
367 #[cfg_attr(
369 feature = "serde",
370 serde(with = "crate::_serde::ReadableBase64Encoded")
371 )]
372 #[cfg_attr(feature = "proptest", any(proptest::collection::size_range(32..=1024).lift()))]
373 pub(crate) contents: Vec<u8>,
374}
375
376impl MoveStruct {
377 pub fn new(
379 type_: StructTag,
380 has_public_transfer: bool,
381 version: Version,
382 contents: Vec<u8>,
383 ) -> Option<Self> {
384 id_opt(&contents).map(|_| Self {
385 type_,
386 has_public_transfer,
387 version,
388 contents,
389 })
390 }
391
392 pub fn object_type(&self) -> &StructTag {
394 &self.type_
395 }
396
397 #[doc(hidden)]
404 pub fn has_public_transfer(&self) -> bool {
405 self.has_public_transfer
406 }
407
408 pub fn version(&self) -> Version {
410 self.version
411 }
412
413 pub fn contents(&self) -> &[u8] {
415 &self.contents
416 }
417
418 pub fn object_id(&self) -> Address {
420 id_opt(self.contents()).unwrap()
421 }
422}
423
424#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Debug)]
426pub enum ObjectType {
427 Package,
429 Struct(StructTag),
431}
432
433#[derive(Clone, Debug, PartialEq, Eq)]
443#[cfg_attr(
444 feature = "serde",
445 derive(serde_derive::Serialize, serde_derive::Deserialize)
446)]
447#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
448pub struct Object {
449 pub(crate) data: ObjectData,
451
452 owner: Owner,
454
455 previous_transaction: Digest,
457
458 storage_rebate: u64,
462}
463
464impl Object {
465 pub fn new(
467 data: ObjectData,
468 owner: Owner,
469 previous_transaction: Digest,
470 storage_rebate: u64,
471 ) -> Self {
472 Self {
473 data,
474 owner,
475 previous_transaction,
476 storage_rebate,
477 }
478 }
479
480 pub fn object_id(&self) -> Address {
482 match &self.data {
483 ObjectData::Struct(struct_) => id_opt(&struct_.contents).unwrap(),
484 ObjectData::Package(package) => package.id,
485 }
486 }
487
488 pub fn version(&self) -> Version {
490 match &self.data {
491 ObjectData::Struct(struct_) => struct_.version,
492 ObjectData::Package(package) => package.version,
493 }
494 }
495
496 pub fn object_type(&self) -> ObjectType {
498 match &self.data {
499 ObjectData::Struct(struct_) => ObjectType::Struct(struct_.type_.clone()),
500 ObjectData::Package(_) => ObjectType::Package,
501 }
502 }
503
504 pub fn as_struct(&self) -> Option<&MoveStruct> {
506 match &self.data {
507 ObjectData::Struct(struct_) => Some(struct_),
508 _ => None,
509 }
510 }
511
512 pub fn owner(&self) -> &Owner {
514 &self.owner
515 }
516
517 pub fn data(&self) -> &ObjectData {
519 &self.data
520 }
521
522 pub fn previous_transaction(&self) -> Digest {
524 self.previous_transaction
525 }
526
527 pub fn storage_rebate(&self) -> u64 {
532 self.storage_rebate
533 }
534}
535
536fn id_opt(contents: &[u8]) -> Option<Address> {
537 if Address::LENGTH > contents.len() {
538 return None;
539 }
540
541 Some(Address::from_bytes(&contents[..Address::LENGTH]).unwrap())
542}
543
544#[derive(Clone, Debug, PartialEq, Eq)]
557#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
558pub struct GenesisObject {
559 data: ObjectData,
560 owner: Owner,
561}
562
563impl GenesisObject {
564 pub fn new(data: ObjectData, owner: Owner) -> Self {
565 Self { data, owner }
566 }
567
568 pub fn object_id(&self) -> Address {
569 match &self.data {
570 ObjectData::Struct(struct_) => id_opt(&struct_.contents).unwrap(),
571 ObjectData::Package(package) => package.id,
572 }
573 }
574
575 pub fn version(&self) -> Version {
576 match &self.data {
577 ObjectData::Struct(struct_) => struct_.version,
578 ObjectData::Package(package) => package.version,
579 }
580 }
581
582 pub fn object_type(&self) -> ObjectType {
583 match &self.data {
584 ObjectData::Struct(struct_) => ObjectType::Struct(struct_.type_.clone()),
585 ObjectData::Package(_) => ObjectType::Package,
586 }
587 }
588
589 pub fn owner(&self) -> &Owner {
590 &self.owner
591 }
592
593 pub fn data(&self) -> &ObjectData {
594 &self.data
595 }
596}
597
598#[cfg(feature = "serde")]
600#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
601mod serialization {
602 use serde::Deserialize;
603 use serde::Deserializer;
604 use serde::Serialize;
605 use serde::Serializer;
606 use serde_with::DeserializeAs;
607 use serde_with::SerializeAs;
608
609 use super::*;
610 use crate::TypeTag;
611
612 #[derive(serde_derive::Deserialize)]
617 enum MoveStructType {
618 Other(StructTag),
620 GasCoin,
622 StakedSui,
624 Coin(TypeTag),
626 SuiBalanceAccumulatorField,
629 BalanceAccumulatorField(TypeTag),
633 }
637
638 #[derive(serde_derive::Serialize)]
640 enum MoveStructTypeRef<'a> {
641 Other(&'a StructTag),
643 GasCoin,
645 StakedSui,
647 Coin(&'a TypeTag),
649 SuiBalanceAccumulatorField,
652 BalanceAccumulatorField(&'a TypeTag),
656 }
660
661 impl MoveStructType {
662 fn into_struct_tag(self) -> StructTag {
663 match self {
664 MoveStructType::Other(tag) => tag,
665 MoveStructType::GasCoin => StructTag::gas_coin(),
666 MoveStructType::StakedSui => StructTag::staked_sui(),
667 MoveStructType::Coin(type_tag) => StructTag::coin(type_tag),
668 MoveStructType::SuiBalanceAccumulatorField => {
669 StructTag::balance_accumulator_field(StructTag::sui().into())
670 }
671 MoveStructType::BalanceAccumulatorField(type_tag) => {
672 StructTag::balance_accumulator_field(type_tag)
673 }
674 }
675 }
676 }
677
678 impl<'a> MoveStructTypeRef<'a> {
679 fn from_struct_tag(s: &'a StructTag) -> Self {
680 let address = s.address();
681 let module = s.module();
682 let name = s.name();
683 let type_params = s.type_params();
684
685 if let Some(coin_type) = s.is_coin() {
686 if let TypeTag::Struct(s_inner) = coin_type
687 && s_inner.is_gas()
688 {
689 Self::GasCoin
690 } else {
691 Self::Coin(coin_type)
692 }
693 } else if address == &Address::THREE
694 && module == "staking_pool"
695 && name == "StakedSui"
696 && type_params.is_empty()
697 {
698 Self::StakedSui
699 } else if let Some(coin_type) = s.is_balance_accumulator_field() {
700 if let TypeTag::Struct(s_inner) = coin_type
701 && s_inner.is_gas()
702 {
703 Self::SuiBalanceAccumulatorField
704 } else {
705 Self::BalanceAccumulatorField(coin_type)
706 }
707 } else {
708 Self::Other(s)
709 }
710 }
711 }
712
713 pub(super) struct BinaryMoveStructType;
714
715 impl SerializeAs<StructTag> for BinaryMoveStructType {
716 fn serialize_as<S>(source: &StructTag, serializer: S) -> Result<S::Ok, S::Error>
717 where
718 S: Serializer,
719 {
720 let move_object_type = MoveStructTypeRef::from_struct_tag(source);
721 move_object_type.serialize(serializer)
722 }
723 }
724
725 impl<'de> DeserializeAs<'de, StructTag> for BinaryMoveStructType {
726 fn deserialize_as<D>(deserializer: D) -> Result<StructTag, D::Error>
727 where
728 D: Deserializer<'de>,
729 {
730 let struct_type = MoveStructType::deserialize(deserializer)?;
731 Ok(struct_type.into_struct_tag())
732 }
733 }
734
735 #[derive(serde_derive::Serialize, serde_derive::Deserialize)]
736 enum BinaryGenesisObject {
737 RawObject { data: ObjectData, owner: Owner },
738 }
739
740 impl Serialize for GenesisObject {
741 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
742 where
743 S: Serializer,
744 {
745 let binary = BinaryGenesisObject::RawObject {
746 data: self.data.clone(),
747 owner: self.owner,
748 };
749 binary.serialize(serializer)
750 }
751 }
752
753 impl<'de> Deserialize<'de> for GenesisObject {
754 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
755 where
756 D: Deserializer<'de>,
757 {
758 let BinaryGenesisObject::RawObject { data, owner } =
759 Deserialize::deserialize(deserializer)?;
760
761 Ok(GenesisObject { data, owner })
762 }
763 }
764
765 #[cfg(test)]
766 mod test {
767 use crate::bcs::FromBcs;
768 use crate::bcs::ToBcs;
769 use crate::object::Object;
770
771 #[cfg(target_arch = "wasm32")]
772 use wasm_bindgen_test::wasm_bindgen_test as test;
773
774 #[test]
775 fn object_fixture() {
776 const SUI_COIN: &[u8] = &[
777 0, 1, 1, 32, 79, 43, 0, 0, 0, 0, 0, 40, 35, 95, 175, 213, 151, 87, 206, 190, 35,
778 131, 79, 35, 254, 22, 15, 181, 40, 108, 28, 77, 68, 229, 107, 254, 191, 160, 196,
779 186, 42, 2, 122, 53, 52, 133, 199, 58, 0, 0, 0, 0, 0, 79, 255, 208, 0, 85, 34, 190,
780 75, 192, 41, 114, 76, 127, 15, 110, 215, 9, 58, 107, 243, 160, 155, 144, 230, 47,
781 97, 220, 21, 24, 30, 26, 62, 32, 17, 197, 192, 38, 64, 173, 142, 143, 49, 111, 15,
782 211, 92, 84, 48, 160, 243, 102, 229, 253, 251, 137, 210, 101, 119, 173, 228, 51,
783 141, 20, 15, 85, 96, 19, 15, 0, 0, 0, 0, 0,
784 ];
785
786 const SUI_STAKE: &[u8] = &[
787 0, 2, 1, 154, 1, 52, 5, 0, 0, 0, 0, 80, 3, 112, 71, 231, 166, 234, 205, 164, 99,
788 237, 29, 56, 97, 170, 21, 96, 105, 158, 227, 122, 22, 251, 60, 162, 12, 97, 151,
789 218, 71, 253, 231, 239, 116, 138, 12, 233, 128, 195, 128, 77, 33, 38, 122, 77, 53,
790 154, 197, 198, 75, 212, 12, 182, 163, 224, 42, 82, 123, 69, 248, 40, 207, 143, 211,
791 13, 106, 1, 0, 0, 0, 0, 0, 0, 59, 81, 183, 246, 112, 0, 0, 0, 0, 79, 255, 208, 0,
792 85, 34, 190, 75, 192, 41, 114, 76, 127, 15, 110, 215, 9, 58, 107, 243, 160, 155,
793 144, 230, 47, 97, 220, 21, 24, 30, 26, 62, 32, 247, 239, 248, 71, 247, 102, 190,
794 149, 232, 153, 138, 67, 169, 209, 203, 29, 255, 215, 223, 57, 159, 44, 40, 218,
795 166, 13, 80, 71, 14, 188, 232, 68, 0, 0, 0, 0, 0, 0, 0, 0,
796 ];
797
798 const NFT: &[u8] = &[
799 0, 0, 97, 201, 195, 159, 216, 97, 133, 173, 96, 215, 56, 212, 229, 43, 208, 139,
800 218, 7, 29, 54, 106, 205, 224, 126, 7, 195, 145, 106, 45, 117, 168, 22, 12, 100,
801 105, 115, 116, 114, 105, 98, 117, 116, 105, 111, 110, 11, 68, 69, 69, 80, 87, 114,
802 97, 112, 112, 101, 114, 0, 0, 124, 24, 223, 4, 0, 0, 0, 0, 40, 31, 8, 18, 84, 38,
803 164, 252, 84, 115, 250, 246, 137, 132, 128, 186, 156, 36, 62, 18, 140, 21, 4, 90,
804 209, 105, 85, 84, 92, 214, 97, 81, 207, 64, 194, 198, 208, 21, 0, 0, 0, 0, 79, 255,
805 208, 0, 85, 34, 190, 75, 192, 41, 114, 76, 127, 15, 110, 215, 9, 58, 107, 243, 160,
806 155, 144, 230, 47, 97, 220, 21, 24, 30, 26, 62, 32, 170, 4, 94, 114, 207, 155, 31,
807 80, 62, 254, 220, 206, 240, 218, 83, 54, 204, 197, 255, 239, 41, 66, 199, 150, 56,
808 189, 86, 217, 166, 216, 128, 241, 64, 205, 21, 0, 0, 0, 0, 0,
809 ];
810
811 const FUD_COIN: &[u8] = &[
812 0, 3, 7, 118, 203, 129, 155, 1, 171, 237, 80, 43, 238, 138, 112, 43, 76, 45, 84,
813 117, 50, 193, 47, 37, 0, 28, 157, 234, 121, 90, 94, 99, 28, 38, 241, 3, 102, 117,
814 100, 3, 70, 85, 68, 0, 1, 193, 89, 252, 3, 0, 0, 0, 0, 40, 33, 214, 90, 11, 56,
815 243, 115, 10, 250, 121, 250, 28, 34, 237, 104, 130, 148, 40, 130, 29, 248, 137,
816 244, 27, 138, 94, 150, 28, 182, 104, 162, 185, 0, 152, 247, 62, 93, 1, 0, 0, 0, 42,
817 95, 32, 226, 13, 31, 128, 91, 188, 127, 235, 12, 75, 73, 116, 112, 3, 227, 244,
818 126, 59, 81, 214, 118, 144, 243, 195, 17, 82, 216, 119, 170, 32, 239, 247, 71, 249,
819 241, 98, 133, 53, 46, 37, 100, 242, 94, 231, 241, 184, 8, 69, 192, 69, 67, 1, 116,
820 251, 229, 226, 99, 119, 79, 255, 71, 43, 64, 242, 19, 0, 0, 0, 0, 0,
821 ];
822
823 const BULLSHARK_PACKAGE: &[u8] = &[
824 1, 135, 35, 29, 28, 138, 126, 114, 145, 204, 122, 145, 8, 244, 199, 188, 26, 10,
825 28, 14, 182, 55, 91, 91, 97, 10, 245, 202, 35, 223, 14, 140, 86, 1, 0, 0, 0, 0, 0,
826 0, 0, 1, 9, 98, 117, 108, 108, 115, 104, 97, 114, 107, 162, 6, 161, 28, 235, 11, 6,
827 0, 0, 0, 10, 1, 0, 12, 2, 12, 36, 3, 48, 61, 4, 109, 12, 5, 121, 137, 1, 7, 130, 2,
828 239, 1, 8, 241, 3, 96, 6, 209, 4, 82, 10, 163, 5, 5, 12, 168, 5, 75, 0, 7, 1, 16,
829 2, 9, 2, 21, 2, 22, 2, 23, 0, 0, 2, 0, 1, 3, 7, 1, 0, 0, 2, 1, 12, 1, 0, 1, 2, 2,
830 12, 1, 0, 1, 2, 4, 12, 1, 0, 1, 4, 5, 2, 0, 5, 6, 7, 0, 0, 12, 0, 1, 0, 0, 13, 2,
831 1, 0, 0, 8, 3, 1, 0, 1, 20, 7, 8, 1, 0, 2, 8, 18, 19, 1, 0, 2, 10, 10, 11, 1, 2, 2,
832 14, 17, 1, 1, 0, 3, 17, 7, 1, 1, 12, 3, 18, 16, 1, 1, 12, 4, 19, 13, 14, 0, 5, 15,
833 5, 6, 0, 3, 6, 5, 9, 7, 12, 8, 15, 6, 9, 4, 9, 2, 8, 0, 7, 8, 5, 0, 4, 7, 11, 4, 1,
834 8, 0, 3, 5, 7, 8, 5, 2, 7, 11, 4, 1, 8, 0, 11, 2, 1, 8, 0, 2, 11, 3, 1, 8, 0, 11,
835 4, 1, 8, 0, 1, 10, 2, 1, 8, 6, 1, 9, 0, 1, 11, 1, 1, 9, 0, 1, 8, 0, 7, 9, 0, 2, 10,
836 2, 10, 2, 10, 2, 11, 1, 1, 8, 6, 7, 8, 5, 2, 11, 4, 1, 9, 0, 11, 3, 1, 9, 0, 1, 11,
837 3, 1, 8, 0, 1, 6, 8, 5, 1, 5, 1, 11, 4, 1, 8, 0, 2, 9, 0, 5, 4, 7, 11, 4, 1, 9, 0,
838 3, 5, 7, 8, 5, 2, 7, 11, 4, 1, 9, 0, 11, 2, 1, 9, 0, 1, 3, 9, 66, 85, 76, 76, 83,
839 72, 65, 82, 75, 4, 67, 111, 105, 110, 12, 67, 111, 105, 110, 77, 101, 116, 97, 100,
840 97, 116, 97, 6, 79, 112, 116, 105, 111, 110, 11, 84, 114, 101, 97, 115, 117, 114,
841 121, 67, 97, 112, 9, 84, 120, 67, 111, 110, 116, 101, 120, 116, 3, 85, 114, 108, 9,
842 98, 117, 108, 108, 115, 104, 97, 114, 107, 4, 98, 117, 114, 110, 4, 99, 111, 105,
843 110, 15, 99, 114, 101, 97, 116, 101, 95, 99, 117, 114, 114, 101, 110, 99, 121, 11,
844 100, 117, 109, 109, 121, 95, 102, 105, 101, 108, 100, 4, 105, 110, 105, 116, 4,
845 109, 105, 110, 116, 17, 109, 105, 110, 116, 95, 97, 110, 100, 95, 116, 114, 97,
846 110, 115, 102, 101, 114, 21, 110, 101, 119, 95, 117, 110, 115, 97, 102, 101, 95,
847 102, 114, 111, 109, 95, 98, 121, 116, 101, 115, 6, 111, 112, 116, 105, 111, 110,
848 20, 112, 117, 98, 108, 105, 99, 95, 102, 114, 101, 101, 122, 101, 95, 111, 98, 106,
849 101, 99, 116, 15, 112, 117, 98, 108, 105, 99, 95, 116, 114, 97, 110, 115, 102, 101,
850 114, 6, 115, 101, 110, 100, 101, 114, 4, 115, 111, 109, 101, 8, 116, 114, 97, 110,
851 115, 102, 101, 114, 10, 116, 120, 95, 99, 111, 110, 116, 101, 120, 116, 3, 117,
852 114, 108, 135, 35, 29, 28, 138, 126, 114, 145, 204, 122, 145, 8, 244, 199, 188, 26,
853 10, 28, 14, 182, 55, 91, 91, 97, 10, 245, 202, 35, 223, 14, 140, 86, 0, 0, 0, 0, 0,
854 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
855 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
856 0, 0, 2, 10, 2, 10, 9, 66, 85, 76, 76, 83, 72, 65, 82, 75, 10, 2, 20, 19, 66, 117,
857 108, 108, 32, 83, 104, 97, 114, 107, 32, 83, 117, 105, 70, 114, 101, 110, 115, 10,
858 2, 1, 0, 10, 2, 39, 38, 104, 116, 116, 112, 115, 58, 47, 47, 105, 46, 105, 98, 98,
859 46, 99, 111, 47, 104, 87, 89, 50, 87, 53, 120, 47, 98, 117, 108, 108, 115, 104, 97,
860 114, 107, 46, 112, 110, 103, 0, 2, 1, 11, 1, 0, 0, 0, 0, 4, 20, 11, 0, 49, 6, 7, 0,
861 7, 1, 7, 2, 7, 3, 17, 10, 56, 0, 10, 1, 56, 1, 12, 2, 12, 3, 11, 2, 56, 2, 11, 3,
862 11, 1, 46, 17, 9, 56, 3, 2, 1, 1, 4, 0, 1, 6, 11, 0, 11, 1, 11, 2, 11, 3, 56, 4, 2,
863 2, 1, 4, 0, 1, 5, 11, 0, 11, 1, 56, 5, 1, 2, 0, 1, 9, 98, 117, 108, 108, 115, 104,
864 97, 114, 107, 9, 66, 85, 76, 76, 83, 72, 65, 82, 75, 135, 35, 29, 28, 138, 126,
865 114, 145, 204, 122, 145, 8, 244, 199, 188, 26, 10, 28, 14, 182, 55, 91, 91, 97, 10,
866 245, 202, 35, 223, 14, 140, 86, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
867 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
868 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0,
869 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
870 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
871 0, 0, 0, 0, 0, 0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 3, 32, 87, 145, 191, 231, 147, 185,
872 46, 159, 240, 181, 95, 126, 236, 65, 154, 55, 16, 196, 229, 218, 47, 59, 99, 197,
873 13, 89, 18, 159, 205, 129, 112, 131, 112, 192, 126, 0, 0, 0, 0, 0,
874 ];
875
876 for fixture in [SUI_COIN, SUI_STAKE, NFT, FUD_COIN, BULLSHARK_PACKAGE] {
877 let object: Object = bcs::from_bytes(fixture).unwrap();
878 assert_eq!(bcs::to_bytes(&object).unwrap(), fixture);
879
880 let json = serde_json::to_string_pretty(&object).unwrap();
881 println!("{json}");
882 assert_eq!(object, serde_json::from_str(&json).unwrap());
883 }
884 }
885
886 #[test]
889 fn address_balance_objects() {
890 let non_sui_address_balance_type = "AAUHIRSU0QWQjjOQW/wFv4O24+PddAa8JQ45YwhB+i7EfzgGY29pbl9hBkNPSU5fQQAAEAAAAAAAAABQCSgWThHEQ1NqPKQQsXVKd/yFD0FSDYUtrvXx1xt+jIk0Bsyk3bbd4hLE1MDxwok6jzp0k3365HVXhJgmi+4vjcQJAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACswgmPj1SN1ZkPLtiVtVs0XD3QCgS/YYUFBh9Q6p4b+zoJAAAAAAAAAAAA==";
891
892 let non_sui = Object::from_bcs_base64(non_sui_address_balance_type).unwrap();
893 assert_eq!(
894 non_sui.to_bcs_base64().unwrap(),
895 non_sui_address_balance_type
896 );
897
898 let sui_address_balance_type = "AAQAAgAAAAAAAABQlJ321C1hKFc15SQmGZUdTDrwVh7xQ46GoV2zEnFK88b/JOPl1wGyhHd/R1itnNXhAzGoyXuDHuOL3V34auvxf+gDAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACswgjRbaObiwu6bn07xewfd3V9iFJfbhcaWy7K6YgNsZdKkAAAAAAAAAAA==";
899
900 let sui = Object::from_bcs_base64(sui_address_balance_type).unwrap();
901 assert_eq!(sui.to_bcs_base64().unwrap(), sui_address_balance_type);
902 }
903 }
904}