1use super::{
6 Address, MovePackage, ObjectDigest, ObjectId, StructTag, TransactionDigest, TypeTag, Version,
7};
8
9#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
21#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
22#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
23#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
24pub struct ObjectReference {
25 pub object_id: ObjectId,
27 pub version: Version,
29 pub digest: ObjectDigest,
31}
32
33impl ObjectReference {
34 pub const fn new(object_id: ObjectId, version: Version, digest: ObjectDigest) -> Self {
37 Self {
38 object_id,
39 version,
40 digest,
41 }
42 }
43
44 pub fn object_id(&self) -> &ObjectId {
47 &self.object_id
48 }
49
50 pub fn version(&self) -> Version {
53 self.version
54 }
55
56 pub fn digest(&self) -> &ObjectDigest {
59 &self.digest
60 }
61
62 pub fn into_parts(self) -> (ObjectId, Version, ObjectDigest) {
64 let Self {
65 object_id,
66 version,
67 digest,
68 } = self;
69
70 (object_id, version, digest)
71 }
72}
73
74impl crate::TreeDisplay for ObjectReference {
75 fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
76 w.header("Object Reference")?;
77 w.leaf("Object ID", &self.object_id, false)?;
78 w.leaf("Version", &self.version, false)?;
79 w.leaf("Digest", &self.digest, true)
80 }
81}
82
83#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
88pub struct OwnedObjectReference {
89 pub reference: ObjectReference,
91 pub owner: Owner,
93}
94
95impl OwnedObjectReference {
96 pub const fn new(reference: ObjectReference, owner: Owner) -> Self {
98 Self { reference, owner }
99 }
100}
101
102impl crate::TreeDisplay for OwnedObjectReference {
103 fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
104 w.header("Owned Object Reference")?;
105 w.child("Reference", &self.reference, false)?;
106 w.leaf("Owner", &self.owner, true)
107 }
108}
109
110#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
115pub struct ObjectVersion {
116 pub object_id: ObjectId,
118 pub version: Version,
120}
121
122impl ObjectVersion {
123 pub const fn new(object_id: ObjectId, version: Version) -> Self {
125 Self { object_id, version }
126 }
127}
128
129impl crate::TreeDisplay for ObjectVersion {
130 fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
131 w.header("Object Version")?;
132 w.leaf("Object ID", &self.object_id, false)?;
133 w.leaf("Version", &self.version, true)
134 }
135}
136
137#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
152#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
153#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
154#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
155#[non_exhaustive]
156pub enum Owner {
157 Address(Address),
159 Object(ObjectId),
161 Shared(
163 Version,
165 ),
166 Immutable,
168}
169
170impl Owner {
171 crate::def_is!(Immutable);
172
173 crate::def_is_as_into_opt!(Address, Object(ObjectId), Shared(Version));
174
175 pub fn address_or_object(&self) -> Option<&Address> {
178 Some(match self {
179 Self::Address(address) => address,
180 Self::Object(object_id) => object_id.as_address(),
181 _ => return None,
182 })
183 }
184}
185
186impl PartialEq<Address> for Owner {
187 fn eq(&self, other: &Address) -> bool {
188 self.as_opt_address() == Some(other)
189 }
190}
191
192impl PartialEq<ObjectId> for Owner {
193 fn eq(&self, other: &ObjectId) -> bool {
194 self.as_opt_object() == Some(other)
195 }
196}
197
198impl std::fmt::Display for Owner {
199 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
200 match self {
201 Owner::Address(address) => write!(f, "Address({address})"),
202 Owner::Object(object_id) => write!(f, "Object({object_id})"),
203 Owner::Shared(version) => write!(f, "Shared({version})"),
204 Owner::Immutable => write!(f, "Immutable"),
205 }
206 }
207}
208
209#[derive(Clone, Debug, Eq, Hash, PartialEq)]
222#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
223#[allow(clippy::large_enum_variant)]
224#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
225#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
226pub enum ObjectData {
228 Struct(MoveStruct),
230 Package(MovePackage),
232 }
234
235impl ObjectData {
236 crate::def_is_as_into_opt!(Struct(MoveStruct), Package(MovePackage));
237
238 pub fn opt_object_type(&self) -> Option<&MoveObjectType> {
239 match self {
240 Self::Struct(m) => Some(m.object_type()),
241 Self::Package(_) => None,
242 }
243 }
244
245 pub fn opt_struct_tag(&self) -> Option<StructTag> {
246 match self {
247 Self::Struct(m) => Some(m.struct_tag().clone()),
248 Self::Package(_) => None,
249 }
250 }
251
252 pub fn id(&self) -> ObjectId {
253 match self {
254 Self::Struct(v) => v.id(),
255 Self::Package(m) => m.id(),
256 }
257 }
258}
259
260impl crate::TreeDisplay for ObjectData {
261 fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
262 w.enum_name("Object Data");
263 match self {
264 ObjectData::Struct(s) => s.fmt_tree(w),
265 ObjectData::Package(p) => p.fmt_tree(w),
266 }
267 }
268}
269
270#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
286#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
287pub struct MoveObjectType(StructTag);
288
289impl MoveObjectType {
290 pub fn new(tag: StructTag) -> Self {
291 Self(tag)
292 }
293
294 pub fn into_inner(self) -> StructTag {
295 self.0
296 }
297}
298
299impl std::ops::Deref for MoveObjectType {
300 type Target = StructTag;
301
302 fn deref(&self) -> &Self::Target {
303 &self.0
304 }
305}
306
307impl From<StructTag> for MoveObjectType {
308 fn from(tag: StructTag) -> Self {
309 Self(tag)
310 }
311}
312
313impl From<MoveObjectType> for StructTag {
314 fn from(obj_type: MoveObjectType) -> Self {
315 obj_type.0
316 }
317}
318
319impl PartialEq<StructTag> for MoveObjectType {
320 fn eq(&self, other: &StructTag) -> bool {
321 &self.0 == other
322 }
323}
324
325impl std::fmt::Display for MoveObjectType {
326 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
327 self.0.fmt(f)
328 }
329}
330
331impl std::str::FromStr for MoveObjectType {
332 type Err = crate::TypeParseError;
333
334 fn from_str(s: &str) -> Result<Self, Self::Err> {
335 StructTag::from_str(s).map(Self)
336 }
337}
338
339#[derive(Clone, derive_more::Debug, Eq, Hash, PartialEq)]
357#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
358#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
359#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
360pub struct MoveStruct {
361 #[cfg_attr(feature = "bcs-schema", bcs_schema(as_type = "compressed-struct-tag"))]
363 object_type: MoveObjectType,
364 version: Version,
368 #[cfg_attr(
373 feature = "serde",
374 serde(with = "crate::_serde::ReadableBase64Encoded")
375 )]
376 #[cfg_attr(feature = "proptest", any(proptest::collection::size_range(32..=1024).lift()))]
377 #[debug("{:?}", <base64ct::Base64 as base64ct::Encoding>::encode_string(contents))]
378 contents: Vec<u8>,
379}
380
381impl MoveStruct {
382 pub fn new(
390 object_type: MoveObjectType,
391 version: Version,
392 contents: Vec<u8>,
393 ) -> Result<Self, MoveStructContentsError> {
394 if contents.len() < ObjectId::LENGTH {
395 return Err(MoveStructContentsError {
396 actual: contents.len(),
397 });
398 }
399 Ok(Self {
400 object_type,
401 version,
402 contents,
403 })
404 }
405
406 pub fn object_type(&self) -> &MoveObjectType {
408 &self.object_type
409 }
410
411 pub fn struct_tag(&self) -> &StructTag {
413 &self.object_type
414 }
415
416 pub fn is_struct_tag(&self, s: &StructTag) -> bool {
418 &self.object_type == s
419 }
420
421 pub fn id(&self) -> ObjectId {
426 ObjectId::from_bytes(&self.contents[..ObjectId::LENGTH]).unwrap()
427 }
428
429 pub fn version(&self) -> Version {
431 self.version
432 }
433
434 pub fn set_version(&mut self, version: Version) {
436 self.version = version;
437 }
438
439 pub fn set_object_type(&mut self, object_type: MoveObjectType) {
444 self.object_type = object_type;
445 }
446
447 pub fn contents(&self) -> &[u8] {
449 &self.contents
450 }
451
452 pub fn set_contents(&mut self, contents: Vec<u8>) -> Result<(), MoveStructContentsError> {
462 if contents.len() < ObjectId::LENGTH {
463 return Err(MoveStructContentsError {
464 actual: contents.len(),
465 });
466 }
467 self.contents = contents;
468 Ok(())
469 }
470
471 pub fn into_contents(self) -> Vec<u8> {
473 self.contents
474 }
475
476 pub fn type_tag(&self) -> TypeTag {
478 TypeTag::Struct(Box::new(self.struct_tag().clone()))
479 }
480
481 pub fn into_parts(self) -> (MoveObjectType, Version, Vec<u8>) {
483 (self.object_type, self.version, self.contents)
484 }
485
486 #[cfg(feature = "serde")]
488 pub fn to_rust<'de, T: serde::Deserialize<'de>>(&'de self) -> Result<T, bcs::Error> {
489 bcs::from_bytes(self.contents())
490 }
491}
492
493impl crate::TreeDisplay for MoveStruct {
494 fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
495 w.header("Move Struct")?;
496 w.leaf("Type", &self.object_type, false)?;
497 w.leaf("Version", &self.version, false)?;
498 w.leaf("Contents", &hex::encode(&self.contents), true)
499 }
500}
501
502#[derive(Clone, Debug, thiserror::Error)]
505#[error(
506 "MoveStruct contents must be at least {} bytes to contain an ObjectId, got {actual}",
507 ObjectId::LENGTH
508)]
509pub struct MoveStructContentsError {
510 actual: usize,
511}
512
513#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
515pub enum ObjectType {
516 Package,
518 Struct(StructTag),
520}
521
522impl ObjectType {
523 crate::def_is!(Package);
524
525 crate::def_is_as_into_opt!(Struct(StructTag));
526}
527
528impl std::fmt::Display for ObjectType {
529 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
530 match self {
531 ObjectType::Package => write!(f, "Package"),
532 ObjectType::Struct(struct_tag) => write!(f, "Struct({struct_tag})"),
533 }
534 }
535}
536
537#[derive(Clone, Debug, Eq, Hash, PartialEq)]
547#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
548#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
549#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
550pub struct Object {
551 pub data: ObjectData,
553 pub owner: Owner,
555 pub previous_transaction: TransactionDigest,
557 #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
561 pub storage_rebate: u64,
562}
563
564impl Object {
565 pub fn new(
567 data: ObjectData,
568 owner: Owner,
569 previous_transaction: TransactionDigest,
570 storage_rebate: u64,
571 ) -> Self {
572 Self {
573 data,
574 owner,
575 previous_transaction,
576 storage_rebate,
577 }
578 }
579
580 pub fn id(&self) -> ObjectId {
582 match &self.data {
583 ObjectData::Struct(struct_) => struct_.id(),
584 ObjectData::Package(package) => package.id,
585 }
586 }
587
588 #[cfg(all(feature = "hash", feature = "serde"))]
590 pub fn object_ref(&self) -> ObjectReference {
591 ObjectReference {
592 object_id: self.id(),
593 version: self.version(),
594 digest: self.digest(),
595 }
596 }
597
598 pub fn version(&self) -> Version {
600 match &self.data {
601 ObjectData::Struct(struct_) => struct_.version(),
602 ObjectData::Package(package) => package.version,
603 }
604 }
605
606 pub fn object_type(&self) -> ObjectType {
608 match &self.data {
609 ObjectData::Struct(struct_) => ObjectType::Struct(struct_.struct_tag().clone()),
610 ObjectData::Package(_) => ObjectType::Package,
611 }
612 }
613
614 pub fn as_opt_struct(&self) -> Option<&MoveStruct> {
616 match &self.data {
617 ObjectData::Struct(struct_) => Some(struct_),
618 _ => None,
619 }
620 }
621
622 pub fn as_struct(&self) -> &MoveStruct {
624 self.as_opt_struct().expect("not a move struct")
625 }
626
627 pub fn as_opt_package(&self) -> Option<&MovePackage> {
629 match &self.data {
630 ObjectData::Package(package) => Some(package),
631 _ => None,
632 }
633 }
634
635 pub fn as_package(&self) -> &MovePackage {
637 self.as_opt_package().expect("not a move package")
638 }
639
640 pub fn owner(&self) -> &Owner {
642 &self.owner
643 }
644
645 pub fn data(&self) -> &ObjectData {
647 &self.data
648 }
649
650 pub fn previous_transaction(&self) -> TransactionDigest {
652 self.previous_transaction
653 }
654
655 pub fn storage_rebate(&self) -> u64 {
660 self.storage_rebate
661 }
662
663 #[cfg(feature = "serde")]
664 pub fn to_rust<'de, T: serde::Deserialize<'de>>(
665 &'de self,
666 ) -> Result<T, Box<dyn std::error::Error + Send + Sync>> {
667 let contents = self.as_opt_struct().ok_or("not a struct")?.contents();
668 Ok(bcs::from_bytes::<T>(contents)?)
669 }
670
671 pub fn is_immutable(&self) -> bool {
673 self.owner.is_immutable()
674 }
675
676 pub fn is_address_owned(&self) -> bool {
678 self.owner.is_address()
679 }
680
681 pub fn is_child_object(&self) -> bool {
683 self.owner.is_object()
684 }
685
686 pub fn is_shared(&self) -> bool {
688 self.owner.is_shared()
689 }
690
691 pub fn is_package(&self) -> bool {
693 self.data.is_package()
694 }
695
696 pub fn is_system_package(&self) -> bool {
698 self.is_package() && self.id().is_system_package()
699 }
700
701 pub fn struct_tag(&self) -> Option<StructTag> {
703 self.data.opt_struct_tag()
704 }
705
706 pub fn is_gas_coin(&self) -> bool {
708 self.as_opt_struct()
709 .is_some_and(|move_object| move_object.struct_tag().is_gas_coin())
710 }
711
712 pub fn opt_coin_type(&self) -> Option<&TypeTag> {
714 self.as_opt_struct()
715 .and_then(|move_object| move_object.struct_tag().opt_coin_type())
716 }
717
718 pub fn single_owner(&self) -> Option<Address> {
721 self.owner.address_or_object().copied()
722 }
723
724 pub fn set_owner(&mut self, new_owner: Address) {
726 self.owner = Owner::Address(new_owner);
727 }
728}
729
730impl crate::TreeDisplay for Object {
731 fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
732 w.header("Object")?;
733 w.leaf("Object ID", &self.id(), false)?;
734 w.child("Data", &self.data, false)?;
735 w.leaf("Owner", &self.owner, false)?;
736 w.leaf("Previous Tx", &self.previous_transaction, false)?;
737 w.leaf("Storage Rebate", &self.storage_rebate, true)
738 }
739}
740
741#[derive(Clone, Debug, Eq, Hash, PartialEq)]
754#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
755pub struct GenesisObject {
756 pub data: ObjectData,
757 pub owner: Owner,
758}
759
760impl GenesisObject {
761 pub fn new(data: ObjectData, owner: Owner) -> Self {
762 Self { data, owner }
763 }
764
765 pub fn object_id(&self) -> ObjectId {
766 match &self.data {
767 ObjectData::Struct(struct_) => struct_.id(),
768 ObjectData::Package(package) => package.id,
769 }
770 }
771
772 pub fn version(&self) -> Version {
773 match &self.data {
774 ObjectData::Struct(struct_) => struct_.version(),
775 ObjectData::Package(package) => package.version,
776 }
777 }
778
779 pub fn object_type(&self) -> ObjectType {
780 match &self.data {
781 ObjectData::Struct(struct_) => ObjectType::Struct(struct_.struct_tag().clone()),
782 ObjectData::Package(_) => ObjectType::Package,
783 }
784 }
785
786 pub fn owner(&self) -> &Owner {
787 &self.owner
788 }
789
790 pub fn data(&self) -> &ObjectData {
791 &self.data
792 }
793
794 pub fn id(&self) -> ObjectId {
795 self.data.id()
796 }
797}
798
799impl crate::TreeDisplay for GenesisObject {
800 fn fmt_tree(&self, w: &mut crate::TreeWriter<'_, '_>) -> std::fmt::Result {
801 w.header("Genesis Object")?;
802 w.leaf("Object ID", &self.object_id(), false)?;
803 w.child("Data", &self.data, false)?;
804 w.leaf("Owner", &self.owner, true)
805 }
806}
807
808crate::impl_tree_display!(
809 ObjectReference,
810 OwnedObjectReference,
811 ObjectVersion,
812 ObjectData,
813 MoveStruct,
814 Object,
815 GenesisObject
816);
817
818#[cfg(feature = "serde")]
820#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
821mod serialization {
822 use serde::{Deserialize, Deserializer, Serialize, Serializer};
823
824 use super::*;
825 use crate::TypeTag;
826
827 #[derive(serde::Deserialize)]
834 #[serde(rename = "MoveObjectType")]
835 #[cfg_attr(
836 feature = "bcs-schema",
837 derive(iota_bcs_schema::BcsSchema),
838 bcs_schema(name = "compressed-struct-tag")
839 )]
840 enum MoveObjectTypeWrapper {
841 Other(StructTag),
843 GasCoin,
845 StakedIota,
848 Coin(TypeTag),
851 }
855
856 #[derive(serde::Serialize)]
858 #[serde(rename = "MoveObjectType")]
859 enum MoveObjectTypeRef<'a> {
860 Other(&'a StructTag),
862 GasCoin,
864 StakedIota,
867 Coin(&'a TypeTag),
870 }
874
875 impl MoveObjectTypeWrapper {
876 fn into_struct_tag(self) -> StructTag {
877 match self {
878 MoveObjectTypeWrapper::Other(tag) => tag,
879 MoveObjectTypeWrapper::GasCoin => StructTag::new_gas_coin(),
880 MoveObjectTypeWrapper::StakedIota => StructTag::new_staked_iota(),
881 MoveObjectTypeWrapper::Coin(type_tag) => StructTag::new_coin(type_tag),
882 }
883 }
884 }
885
886 impl<'a> MoveObjectTypeRef<'a> {
887 fn from_struct_tag(s: &'a StructTag) -> Self {
888 if let Some(coin_type) = s.opt_coin_type() {
889 if let TypeTag::Struct(s_inner) = coin_type
890 && s_inner.address() == Address::FRAMEWORK
891 && s_inner.module() == "iota"
892 && s_inner.name() == "IOTA"
893 && s_inner.type_params().is_empty()
894 {
895 return Self::GasCoin;
896 }
897
898 Self::Coin(coin_type)
899 } else if s.address() == Address::SYSTEM
900 && s.module() == "staking_pool"
901 && s.name() == "StakedIota"
902 && s.type_params().is_empty()
903 {
904 Self::StakedIota
905 } else {
906 Self::Other(s)
907 }
908 }
909 }
910
911 impl Serialize for MoveObjectType {
912 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
913 where
914 S: Serializer,
915 {
916 if serializer.is_human_readable() {
917 self.0.serialize(serializer)
918 } else {
919 MoveObjectTypeRef::from_struct_tag(&self.0).serialize(serializer)
920 }
921 }
922 }
923
924 impl<'de> Deserialize<'de> for MoveObjectType {
925 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
926 where
927 D: Deserializer<'de>,
928 {
929 if deserializer.is_human_readable() {
930 StructTag::deserialize(deserializer).map(Self)
931 } else {
932 MoveObjectTypeWrapper::deserialize(deserializer).map(|t| Self(t.into_struct_tag()))
933 }
934 }
935 }
936
937 #[derive(serde::Serialize)]
938 #[serde(rename = "GenesisObject")]
939 struct ReadableGenesisObjectRef<'a> {
940 data: &'a ObjectData,
941 owner: &'a Owner,
942 }
943
944 #[derive(serde::Deserialize)]
945 #[serde(rename = "GenesisObject")]
946 struct ReadableGenesisObject {
947 data: ObjectData,
948 owner: Owner,
949 }
950
951 #[derive(serde::Deserialize, serde::Serialize)]
952 #[serde(rename = "GenesisObject")]
953 #[cfg_attr(
954 feature = "bcs-schema",
955 derive(iota_bcs_schema::BcsSchema),
956 bcs_schema(name = "genesis-object")
957 )]
958 enum BinaryGenesisObject {
959 RawObject { data: ObjectData, owner: Owner },
960 }
961
962 impl Serialize for GenesisObject {
963 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
964 where
965 S: Serializer,
966 {
967 if serializer.is_human_readable() {
968 ReadableGenesisObjectRef {
969 data: &self.data,
970 owner: &self.owner,
971 }
972 .serialize(serializer)
973 } else {
974 BinaryGenesisObject::RawObject {
975 data: self.data.clone(),
976 owner: self.owner,
977 }
978 .serialize(serializer)
979 }
980 }
981 }
982
983 impl<'de> Deserialize<'de> for GenesisObject {
984 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
985 where
986 D: Deserializer<'de>,
987 {
988 if deserializer.is_human_readable() {
989 let ReadableGenesisObject { data, owner } = Deserialize::deserialize(deserializer)?;
990
991 Ok(GenesisObject { data, owner })
992 } else {
993 let BinaryGenesisObject::RawObject { data, owner } =
994 Deserialize::deserialize(deserializer)?;
995
996 Ok(GenesisObject { data, owner })
997 }
998 }
999 }
1000
1001 #[cfg(test)]
1002 mod tests {
1003 use std::collections::BTreeMap;
1004
1005 #[cfg(target_arch = "wasm32")]
1006 use wasm_bindgen_test::wasm_bindgen_test as test;
1007
1008 use super::*;
1009 use crate::{Identifier, TypeOrigin, UpgradeInfo, object::Object};
1010
1011 #[test]
1012 fn package_object_json_snapshot() {
1013 let package = MovePackage {
1014 id: ObjectId::ZERO,
1015 version: Version::from_u64(12),
1016 modules: BTreeMap::from([(
1017 Identifier::new("my_module").unwrap(),
1018 vec![1, 2, 3, 4],
1019 )]),
1020 type_origin_table: vec![TypeOrigin {
1021 module_name: Identifier::new("my_module").unwrap(),
1022 datatype_name: Identifier::new("MyType").unwrap(),
1023 package: ObjectId::ZERO,
1024 }],
1025 linkage_table: BTreeMap::from([(
1026 ObjectId::ZERO,
1027 UpgradeInfo {
1028 upgraded_id: ObjectId::ZERO,
1029 upgraded_version: Version::from_u64(13),
1030 },
1031 )]),
1032 };
1033 let object = Object {
1034 data: ObjectData::Package(package),
1035 owner: Owner::Object(ObjectId::ZERO),
1036 previous_transaction: TransactionDigest::ZERO,
1037 storage_rebate: 100,
1038 };
1039
1040 let json = serde_json::to_string_pretty(&object)
1041 .unwrap()
1042 .replace('\n', "\n ");
1044 assert_eq!(
1045 json,
1046 r#"{
1047 "data": {
1048 "Package": {
1049 "id": "0x0000000000000000000000000000000000000000000000000000000000000000",
1050 "version": "12",
1051 "modules": {
1052 "my_module": "AQIDBA=="
1053 },
1054 "type_origin_table": [
1055 {
1056 "module_name": "my_module",
1057 "datatype_name": "MyType",
1058 "package": "0x0000000000000000000000000000000000000000000000000000000000000000"
1059 }
1060 ],
1061 "linkage_table": {
1062 "0x0000000000000000000000000000000000000000000000000000000000000000": {
1063 "upgraded_id": "0x0000000000000000000000000000000000000000000000000000000000000000",
1064 "upgraded_version": "13"
1065 }
1066 }
1067 }
1068 },
1069 "owner": {
1070 "Object": "0x0000000000000000000000000000000000000000000000000000000000000000"
1071 },
1072 "previous_transaction": "11111111111111111111111111111111",
1073 "storage_rebate": "100"
1074 }"#
1075 );
1076
1077 let roundtrip: Object = serde_json::from_str(&json).unwrap();
1079 assert_eq!(object, roundtrip);
1080 }
1081
1082 #[test]
1083 fn object_reference_tuple_format() {
1084 let json = r#"["0x0000000000000000000000000000000000000000000000000000000000000000","0","11111111111111111111111111111111"]"#;
1085 let obj_ref: ObjectReference = serde_json::from_str(json).unwrap();
1086 assert_eq!(obj_ref.object_id, ObjectId::ZERO);
1087 assert_eq!(obj_ref.version, Version::from_u64(0));
1088 assert_eq!(obj_ref.digest, ObjectDigest::ZERO);
1089
1090 let serialized = serde_json::to_string(&obj_ref).unwrap();
1092 let roundtrip: ObjectReference = serde_json::from_str(&serialized).unwrap();
1093 assert_eq!(obj_ref, roundtrip);
1094 }
1095
1096 #[test]
1097 fn object_reference_in_map() {
1098 use std::collections::BTreeMap;
1099
1100 let json = r#"{"4vJ9JU1bJJE96FWSJKvHsmmFADCg4gpZQff4P3bkLKi":[["0x0000000000000000000000000000000000000000000000000000000000000000","0","11111111111111111111111111111111"]],"8qbHbw2BbbTHBW1sbeqakYXVKRQM8Ne7pLK7m6CVfeR":[["0x0000000000000000000000000000000000000000000000000000000000000000","0","11111111111111111111111111111111"]]}"#;
1101
1102 let from_json: BTreeMap<String, Vec<ObjectReference>> =
1103 serde_json::from_str(json).unwrap();
1104
1105 assert_eq!(from_json.len(), 2);
1106 for refs in from_json.values() {
1107 assert_eq!(refs.len(), 1);
1108 assert_eq!(refs[0].object_id, ObjectId::ZERO);
1109 assert_eq!(refs[0].version, Version::from_u64(0));
1110 assert_eq!(refs[0].digest, ObjectDigest::ZERO);
1111 }
1112 }
1113
1114 #[test]
1115 fn object_fixture() {
1116 const IOTA_COIN: &[u8] = &[
1117 0, 1, 32, 79, 43, 0, 0, 0, 0, 0, 40, 35, 95, 175, 213, 151, 87, 206, 190, 35, 131,
1118 79, 35, 254, 22, 15, 181, 40, 108, 28, 77, 68, 229, 107, 254, 191, 160, 196, 186,
1119 42, 2, 122, 53, 52, 133, 199, 58, 0, 0, 0, 0, 0, 79, 255, 208, 0, 85, 34, 190, 75,
1120 192, 41, 114, 76, 127, 15, 110, 215, 9, 58, 107, 243, 160, 155, 144, 230, 47, 97,
1121 220, 21, 24, 30, 26, 62, 32, 17, 197, 192, 38, 64, 173, 142, 143, 49, 111, 15, 211,
1122 92, 84, 48, 160, 243, 102, 229, 253, 251, 137, 210, 101, 119, 173, 228, 51, 141,
1123 20, 15, 85, 96, 19, 15, 0, 0, 0, 0, 0,
1124 ];
1125
1126 const IOTA_STAKE: &[u8] = &[
1127 0, 2, 154, 1, 52, 5, 0, 0, 0, 0, 80, 3, 112, 71, 231, 166, 234, 205, 164, 99, 237,
1128 29, 56, 97, 170, 21, 96, 105, 158, 227, 122, 22, 251, 60, 162, 12, 97, 151, 218,
1129 71, 253, 231, 239, 116, 138, 12, 233, 128, 195, 128, 77, 33, 38, 122, 77, 53, 154,
1130 197, 198, 75, 212, 12, 182, 163, 224, 42, 82, 123, 69, 248, 40, 207, 143, 211, 13,
1131 106, 1, 0, 0, 0, 0, 0, 0, 59, 81, 183, 246, 112, 0, 0, 0, 0, 79, 255, 208, 0, 85,
1132 34, 190, 75, 192, 41, 114, 76, 127, 15, 110, 215, 9, 58, 107, 243, 160, 155, 144,
1133 230, 47, 97, 220, 21, 24, 30, 26, 62, 32, 247, 239, 248, 71, 247, 102, 190, 149,
1134 232, 153, 138, 67, 169, 209, 203, 29, 255, 215, 223, 57, 159, 44, 40, 218, 166, 13,
1135 80, 71, 14, 188, 232, 68, 0, 0, 0, 0, 0, 0, 0, 0,
1136 ];
1137
1138 const NFT: &[u8] = &[
1139 0, 0, 97, 201, 195, 159, 216, 97, 133, 173, 96, 215, 56, 212, 229, 43, 208, 139,
1140 218, 7, 29, 54, 106, 205, 224, 126, 7, 195, 145, 106, 45, 117, 168, 22, 12, 100,
1141 105, 115, 116, 114, 105, 98, 117, 116, 105, 111, 110, 11, 68, 69, 69, 80, 87, 114,
1142 97, 112, 112, 101, 114, 0, 124, 24, 223, 4, 0, 0, 0, 0, 40, 31, 8, 18, 84, 38, 164,
1143 252, 84, 115, 250, 246, 137, 132, 128, 186, 156, 36, 62, 18, 140, 21, 4, 90, 209,
1144 105, 85, 84, 92, 214, 97, 81, 207, 64, 194, 198, 208, 21, 0, 0, 0, 0, 79, 255, 208,
1145 0, 85, 34, 190, 75, 192, 41, 114, 76, 127, 15, 110, 215, 9, 58, 107, 243, 160, 155,
1146 144, 230, 47, 97, 220, 21, 24, 30, 26, 62, 32, 170, 4, 94, 114, 207, 155, 31, 80,
1147 62, 254, 220, 206, 240, 218, 83, 54, 204, 197, 255, 239, 41, 66, 199, 150, 56, 189,
1148 86, 217, 166, 216, 128, 241, 64, 205, 21, 0, 0, 0, 0, 0,
1149 ];
1150
1151 const FUD_COIN: &[u8] = &[
1152 0, 3, 7, 118, 203, 129, 155, 1, 171, 237, 80, 43, 238, 138, 112, 43, 76, 45, 84,
1153 117, 50, 193, 47, 37, 0, 28, 157, 234, 121, 90, 94, 99, 28, 38, 241, 3, 102, 117,
1154 100, 3, 70, 85, 68, 0, 193, 89, 252, 3, 0, 0, 0, 0, 40, 33, 214, 90, 11, 56, 243,
1155 115, 10, 250, 121, 250, 28, 34, 237, 104, 130, 148, 40, 130, 29, 248, 137, 244, 27,
1156 138, 94, 150, 28, 182, 104, 162, 185, 0, 152, 247, 62, 93, 1, 0, 0, 0, 42, 95, 32,
1157 226, 13, 31, 128, 91, 188, 127, 235, 12, 75, 73, 116, 112, 3, 227, 244, 126, 59,
1158 81, 214, 118, 144, 243, 195, 17, 82, 216, 119, 170, 32, 239, 247, 71, 249, 241, 98,
1159 133, 53, 46, 37, 100, 242, 94, 231, 241, 184, 8, 69, 192, 69, 67, 1, 116, 251, 229,
1160 226, 99, 119, 79, 255, 71, 43, 64, 242, 19, 0, 0, 0, 0, 0,
1161 ];
1162
1163 const BULLSHARK_PACKAGE: &[u8] = &[
1164 1, 135, 35, 29, 28, 138, 126, 114, 145, 204, 122, 145, 8, 244, 199, 188, 26, 10,
1165 28, 14, 182, 55, 91, 91, 97, 10, 245, 202, 35, 223, 14, 140, 86, 1, 0, 0, 0, 0, 0,
1166 0, 0, 1, 9, 98, 117, 108, 108, 115, 104, 97, 114, 107, 162, 6, 161, 28, 235, 11, 6,
1167 0, 0, 0, 10, 1, 0, 12, 2, 12, 36, 3, 48, 61, 4, 109, 12, 5, 121, 137, 1, 7, 130, 2,
1168 239, 1, 8, 241, 3, 96, 6, 209, 4, 82, 10, 163, 5, 5, 12, 168, 5, 75, 0, 7, 1, 16,
1169 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,
1170 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,
1171 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,
1172 14, 17, 1, 1, 0, 3, 17, 7, 1, 1, 12, 3, 18, 16, 1, 1, 12, 4, 19, 13, 14, 0, 5, 15,
1173 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,
1174 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,
1175 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,
1176 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,
1177 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,
1178 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,
1179 72, 65, 82, 75, 4, 67, 111, 105, 110, 12, 67, 111, 105, 110, 77, 101, 116, 97, 100,
1180 97, 116, 97, 6, 79, 112, 116, 105, 111, 110, 11, 84, 114, 101, 97, 115, 117, 114,
1181 121, 67, 97, 112, 9, 84, 120, 67, 111, 110, 116, 101, 120, 116, 3, 85, 114, 108, 9,
1182 98, 117, 108, 108, 115, 104, 97, 114, 107, 4, 98, 117, 114, 110, 4, 99, 111, 105,
1183 110, 15, 99, 114, 101, 97, 116, 101, 95, 99, 117, 114, 114, 101, 110, 99, 121, 11,
1184 100, 117, 109, 109, 121, 95, 102, 105, 101, 108, 100, 4, 105, 110, 105, 116, 4,
1185 109, 105, 110, 116, 17, 109, 105, 110, 116, 95, 97, 110, 100, 95, 116, 114, 97,
1186 110, 115, 102, 101, 114, 21, 110, 101, 119, 95, 117, 110, 115, 97, 102, 101, 95,
1187 102, 114, 111, 109, 95, 98, 121, 116, 101, 115, 6, 111, 112, 116, 105, 111, 110,
1188 20, 112, 117, 98, 108, 105, 99, 95, 102, 114, 101, 101, 122, 101, 95, 111, 98, 106,
1189 101, 99, 116, 15, 112, 117, 98, 108, 105, 99, 95, 116, 114, 97, 110, 115, 102, 101,
1190 114, 6, 115, 101, 110, 100, 101, 114, 4, 115, 111, 109, 101, 8, 116, 114, 97, 110,
1191 115, 102, 101, 114, 10, 116, 120, 95, 99, 111, 110, 116, 101, 120, 116, 3, 117,
1192 114, 108, 135, 35, 29, 28, 138, 126, 114, 145, 204, 122, 145, 8, 244, 199, 188, 26,
1193 10, 28, 14, 182, 55, 91, 91, 97, 10, 245, 202, 35, 223, 14, 140, 86, 0, 0, 0, 0, 0,
1194 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,
1195 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,
1196 0, 0, 2, 10, 2, 10, 9, 66, 85, 76, 76, 83, 72, 65, 82, 75, 10, 2, 20, 19, 66, 117,
1197 108, 108, 32, 83, 104, 97, 114, 107, 32, 83, 117, 105, 70, 114, 101, 110, 115, 10,
1198 2, 1, 0, 10, 2, 39, 38, 104, 116, 116, 112, 115, 58, 47, 47, 105, 46, 105, 98, 98,
1199 46, 99, 111, 47, 104, 87, 89, 50, 87, 53, 120, 47, 98, 117, 108, 108, 115, 104, 97,
1200 114, 107, 46, 112, 110, 103, 0, 2, 1, 11, 1, 0, 0, 0, 0, 4, 20, 11, 0, 49, 6, 7, 0,
1201 7, 1, 7, 2, 7, 3, 17, 10, 56, 0, 10, 1, 56, 1, 12, 2, 12, 3, 11, 2, 56, 2, 11, 3,
1202 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,
1203 2, 1, 4, 0, 1, 5, 11, 0, 11, 1, 56, 5, 1, 2, 0, 1, 9, 98, 117, 108, 108, 115, 104,
1204 97, 114, 107, 9, 66, 85, 76, 76, 83, 72, 65, 82, 75, 135, 35, 29, 28, 138, 126,
1205 114, 145, 204, 122, 145, 8, 244, 199, 188, 26, 10, 28, 14, 182, 55, 91, 91, 97, 10,
1206 245, 202, 35, 223, 14, 140, 86, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1207 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,
1208 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,
1209 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,
1210 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,
1211 0, 0, 0, 0, 0, 0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 3, 32, 87, 145, 191, 231, 147, 185,
1212 46, 159, 240, 181, 95, 126, 236, 65, 154, 55, 16, 196, 229, 218, 47, 59, 99, 197,
1213 13, 89, 18, 159, 205, 129, 112, 131, 112, 192, 126, 0, 0, 0, 0, 0,
1214 ];
1215
1216 for fixture in [IOTA_COIN, IOTA_STAKE, NFT, FUD_COIN, BULLSHARK_PACKAGE] {
1217 let object: Object = bcs::from_bytes(fixture).unwrap();
1218 assert_eq!(bcs::to_bytes(&object).unwrap(), fixture);
1219
1220 let json = serde_json::to_string_pretty(&object).unwrap();
1221 println!("{json}");
1222 assert_eq!(object, serde_json::from_str(&json).unwrap());
1223 }
1224 }
1225 }
1226}