1use async_graphql::*;
5use move_core_types::{
6 account_address::AccountAddress,
7 annotated_value as A, ident_str,
8 identifier::{IdentStr, Identifier},
9 language_storage::{StructTag, TypeTag},
10};
11use serde::{Deserialize, Serialize};
12use sui_types::object::bounded_visitor::BoundedVisitor;
13
14use crate::data::package_resolver::PackageResolver;
15use crate::{error::Error, types::json::Json, types::move_type::unexpected_signer_error};
16
17use super::{base64::Base64, big_int::BigInt, move_type::MoveType, sui_address::SuiAddress};
18
19const STD: AccountAddress = AccountAddress::ONE;
20const SUI: AccountAddress = AccountAddress::TWO;
21
22const MOD_ASCII: &IdentStr = ident_str!("ascii");
23const MOD_OBJECT: &IdentStr = ident_str!("object");
24const MOD_OPTION: &IdentStr = ident_str!("option");
25const MOD_STRING: &IdentStr = ident_str!("string");
26
27const TYP_ID: &IdentStr = ident_str!("ID");
28const TYP_OPTION: &IdentStr = ident_str!("Option");
29const TYP_STRING: &IdentStr = ident_str!("String");
30const TYP_UID: &IdentStr = ident_str!("UID");
31
32#[derive(SimpleObject)]
33#[graphql(complex)]
34pub(crate) struct MoveValue {
35 #[graphql(name = "type")]
37 type_: MoveType,
38 bcs: Base64,
40}
41
42scalar!(
43 MoveData,
44 "MoveData",
45 "The contents of a Move Value, corresponding to the following recursive type:
46
47type MoveData =
48 { Address: SuiAddress }
49 | { UID: SuiAddress }
50 | { ID: SuiAddress }
51 | { Bool: bool }
52 | { Number: BigInt }
53 | { String: string }
54 | { Vector: [MoveData] }
55 | { Option: MoveData? }
56 | { Struct: [{ name: string , value: MoveData }] }
57 | { Variant: {
58 name: string,
59 fields: [{ name: string, value: MoveData }],
60 }"
61);
62
63#[derive(Serialize, Deserialize, Debug)]
64pub(crate) enum MoveData {
65 Address(SuiAddress),
66 #[serde(rename = "UID")]
67 Uid(SuiAddress),
68 #[serde(rename = "ID")]
69 Id(SuiAddress),
70 Bool(bool),
71 Number(BigInt),
72 String(String),
73 Vector(Vec<MoveData>),
74 Option(Option<Box<MoveData>>),
75 Struct(Vec<MoveField>),
76 Variant(MoveVariant),
77}
78
79#[derive(Serialize, Deserialize, Debug)]
80pub(crate) struct MoveVariant {
81 name: String,
82 fields: Vec<MoveField>,
83}
84
85#[derive(Serialize, Deserialize, Debug)]
86pub(crate) struct MoveField {
87 name: String,
88 value: MoveData,
89}
90
91#[ComplexObject]
93impl MoveValue {
94 async fn data(&self, ctx: &Context<'_>) -> Result<MoveData> {
96 let resolver: &PackageResolver = ctx
97 .data()
98 .map_err(|_| Error::Internal("Unable to fetch Package Cache.".to_string()))
99 .extend()?;
100
101 let Some(layout) = self.type_.layout_impl(resolver).await.extend()? else {
102 return Err(Error::Internal(
103 "Move value must have valid layout".to_string(),
104 ))
105 .extend();
106 };
107
108 self.data_impl(layout).extend()
110 }
111
112 async fn json(&self, ctx: &Context<'_>) -> Result<Json> {
125 let resolver: &PackageResolver = ctx
126 .data()
127 .map_err(|_| Error::Internal("Unable to fetch Package Cache.".to_string()))
128 .extend()?;
129
130 let Some(layout) = self.type_.layout_impl(resolver).await.extend()? else {
131 return Err(Error::Internal(
132 "Move value must have valid layout".to_string(),
133 ))
134 .extend();
135 };
136
137 self.json_impl(layout).extend()
139 }
140}
141
142impl MoveValue {
143 pub fn new(tag: TypeTag, bcs: Base64) -> Self {
144 let type_ = MoveType::from(tag);
145 Self { type_, bcs }
146 }
147
148 fn value_impl(&self, layout: A::MoveTypeLayout) -> Result<A::MoveValue, Error> {
149 BoundedVisitor::deserialize_value(&self.bcs.0[..], &layout).map_err(|_| {
151 let type_tag: TypeTag = (&layout).into();
152 Error::Internal(format!(
153 "Failed to deserialize Move value for type: {}",
154 type_tag
155 ))
156 })
157 }
158
159 fn data_impl(&self, layout: A::MoveTypeLayout) -> Result<MoveData, Error> {
160 MoveData::try_from(self.value_impl(layout)?)
161 }
162
163 fn json_impl(&self, layout: A::MoveTypeLayout) -> Result<Json, Error> {
164 Ok(try_to_json_value(self.value_impl(layout)?)?.into())
165 }
166}
167
168impl TryFrom<A::MoveValue> for MoveData {
169 type Error = Error;
170
171 fn try_from(value: A::MoveValue) -> Result<Self, Error> {
172 use A::MoveValue as V;
173
174 Ok(match value {
175 V::U8(n) => Self::Number(BigInt::from(n)),
176 V::U16(n) => Self::Number(BigInt::from(n)),
177 V::U32(n) => Self::Number(BigInt::from(n)),
178 V::U64(n) => Self::Number(BigInt::from(n)),
179 V::U128(n) => Self::Number(BigInt::from(n)),
180 V::U256(n) => Self::Number(BigInt::from(n)),
181
182 V::Bool(b) => Self::Bool(b),
183 V::Address(a) => Self::Address(a.into()),
184
185 V::Vector(v) => Self::Vector(
186 v.into_iter()
187 .map(MoveData::try_from)
188 .collect::<Result<Vec<_>, _>>()?,
189 ),
190
191 V::Struct(s) => {
192 let A::MoveStruct { type_, fields } = s;
193 if is_type(&type_, &STD, MOD_OPTION, TYP_OPTION) {
194 Self::Option(match extract_option(&type_, fields)? {
196 Some(value) => Some(Box::new(MoveData::try_from(value)?)),
197 None => None,
198 })
199 } else if is_type(&type_, &STD, MOD_ASCII, TYP_STRING)
200 || is_type(&type_, &STD, MOD_STRING, TYP_STRING)
201 {
202 Self::String(extract_string(&type_, fields)?)
204 } else if is_type(&type_, &SUI, MOD_OBJECT, TYP_UID) {
205 Self::Uid(extract_uid(&type_, fields)?.into())
207 } else if is_type(&type_, &SUI, MOD_OBJECT, TYP_ID) {
208 Self::Id(extract_id(&type_, fields)?.into())
210 } else {
211 let fields: Result<Vec<_>, _> =
213 fields.into_iter().map(MoveField::try_from).collect();
214 Self::Struct(fields?)
215 }
216 }
217
218 V::Variant(A::MoveVariant {
219 type_: _,
220 variant_name,
221 tag: _,
222 fields,
223 }) => {
224 let fields = fields
225 .into_iter()
226 .map(MoveField::try_from)
227 .collect::<Result<_, _>>()?;
228 Self::Variant(MoveVariant {
229 name: variant_name.to_string(),
230 fields,
231 })
232 }
233
234 V::Signer(_) => return Err(unexpected_signer_error()),
236 })
237 }
238}
239
240impl TryFrom<(Identifier, A::MoveValue)> for MoveField {
241 type Error = Error;
242
243 fn try_from((ident, value): (Identifier, A::MoveValue)) -> Result<Self, Error> {
244 Ok(MoveField {
245 name: ident.to_string(),
246 value: MoveData::try_from(value)?,
247 })
248 }
249}
250
251fn try_to_json_value(value: A::MoveValue) -> Result<Value, Error> {
252 use A::MoveValue as V;
253 Ok(match value {
254 V::U8(n) => Value::Number(n.into()),
255 V::U16(n) => Value::Number(n.into()),
256 V::U32(n) => Value::Number(n.into()),
257 V::U64(n) => Value::String(n.to_string()),
258 V::U128(n) => Value::String(n.to_string()),
259 V::U256(n) => Value::String(n.to_string()),
260
261 V::Bool(b) => Value::Boolean(b),
262 V::Address(a) => Value::String(a.to_canonical_string(true)),
263
264 V::Vector(xs) => Value::List(
265 xs.into_iter()
266 .map(try_to_json_value)
267 .collect::<Result<_, _>>()?,
268 ),
269
270 V::Struct(s) => {
271 let A::MoveStruct { type_, fields } = s;
272 if is_type(&type_, &STD, MOD_OPTION, TYP_OPTION) {
273 match extract_option(&type_, fields)? {
275 Some(value) => try_to_json_value(value)?,
276 None => Value::Null,
277 }
278 } else if is_type(&type_, &STD, MOD_ASCII, TYP_STRING)
279 || is_type(&type_, &STD, MOD_STRING, TYP_STRING)
280 {
281 Value::String(extract_string(&type_, fields)?)
283 } else if is_type(&type_, &SUI, MOD_OBJECT, TYP_UID) {
284 Value::String(
286 extract_uid(&type_, fields)?.to_canonical_string(true),
287 )
288 } else if is_type(&type_, &SUI, MOD_OBJECT, TYP_ID) {
289 Value::String(
291 extract_id(&type_, fields)?.to_canonical_string(true),
292 )
293 } else {
294 Value::Object(
296 fields
297 .into_iter()
298 .map(|(name, value)| {
299 Ok((Name::new(name.to_string()), try_to_json_value(value)?))
300 })
301 .collect::<Result<_, Error>>()?,
302 )
303 }
304 }
305
306 V::Variant(A::MoveVariant {
307 type_: _,
308 variant_name,
309 tag: _,
310 fields,
311 }) => {
312 let fields = fields
313 .into_iter()
314 .map(|(name, value)| Ok((Name::new(name.to_string()), try_to_json_value(value)?)))
315 .collect::<Result<_, Error>>()?;
316 Value::Object(
317 vec![(Name::new(variant_name.to_string()), Value::Object(fields))]
318 .into_iter()
319 .collect(),
320 )
321 }
322 V::Signer(_) => return Err(unexpected_signer_error()),
324 })
325}
326
327fn is_type(tag: &StructTag, address: &AccountAddress, module: &IdentStr, name: &IdentStr) -> bool {
328 &tag.address == address
329 && tag.module.as_ident_str() == module
330 && tag.name.as_ident_str() == name
331}
332
333macro_rules! extract_field {
334 ($type:expr, $fields:expr, $name:ident) => {{
335 let _name = ident_str!(stringify!($name));
336 let _type = $type;
337 if let Some(value) = ($fields)
338 .into_iter()
339 .find_map(|(name, value)| (&*name == _name).then_some(value))
340 {
341 value
342 } else {
343 return Err(Error::Internal(format!(
344 "Couldn't find expected field '{_name}' of {_type}."
345 )));
346 }
347 }};
348}
349
350fn extract_bytes(value: A::MoveValue) -> Result<Vec<u8>, Error> {
353 use A::MoveValue as V;
354 let V::Vector(elements) = value else {
355 return Err(Error::Internal("Expected a vector.".to_string()));
356 };
357
358 let mut bytes = Vec::with_capacity(elements.len());
359 for element in elements {
360 let V::U8(byte) = element else {
361 return Err(Error::Internal("Expected a byte.".to_string()));
362 };
363 bytes.push(byte)
364 }
365
366 Ok(bytes)
367}
368
369fn extract_string(
378 type_: &StructTag,
379 fields: Vec<(Identifier, A::MoveValue)>,
380) -> Result<String, Error> {
381 let bytes = extract_bytes(extract_field!(type_, fields, bytes))?;
382 String::from_utf8(bytes).map_err(|e| {
383 const PREFIX: usize = 30;
384 let bytes = e.as_bytes();
385
386 let sample = if bytes.len() < PREFIX {
388 String::from_utf8_lossy(bytes)
389 } else {
390 String::from_utf8_lossy(&bytes[..PREFIX - 3]) + "..."
391 };
392
393 Error::Internal(format!("{e} in {sample:?}"))
394 })
395}
396
397fn extract_id(
406 type_: &StructTag,
407 fields: Vec<(Identifier, A::MoveValue)>,
408) -> Result<AccountAddress, Error> {
409 use A::MoveValue as V;
410 let V::Address(addr) = extract_field!(type_, fields, bytes) else {
411 return Err(Error::Internal(
412 "Expected ID.bytes to have type address.".to_string(),
413 ));
414 };
415
416 Ok(addr)
417}
418
419fn extract_uid(
428 type_: &StructTag,
429 fields: Vec<(Identifier, A::MoveValue)>,
430) -> Result<AccountAddress, Error> {
431 use A::MoveValue as V;
432 let V::Struct(s) = extract_field!(type_, fields, id) else {
433 return Err(Error::Internal(
434 "Expected UID.id to be a struct".to_string(),
435 ));
436 };
437
438 let A::MoveStruct { type_, fields } = s;
439 if !is_type(&type_, &SUI, MOD_OBJECT, TYP_ID) {
440 return Err(Error::Internal(
441 "Expected UID.id to have type ID.".to_string(),
442 ));
443 }
444
445 extract_id(&type_, fields)
446}
447
448fn extract_option(
457 type_: &StructTag,
458 fields: Vec<(Identifier, A::MoveValue)>,
459) -> Result<Option<A::MoveValue>, Error> {
460 let A::MoveValue::Vector(mut elements) = extract_field!(type_, fields, vec) else {
461 return Err(Error::Internal(
462 "Expected Option.vec to be a vector.".to_string(),
463 ));
464 };
465
466 if elements.len() > 1 {
467 return Err(Error::Internal(
468 "Expected Option.vec to contain at most one element.".to_string(),
469 ));
470 };
471
472 Ok(elements.pop())
473}
474
475#[cfg(test)]
476mod tests {
477 use std::str::FromStr;
478
479 use expect_test::expect;
480 use move_core_types::{
481 annotated_value::{self as A, MoveFieldLayout, MoveStructLayout as S, MoveTypeLayout as L},
482 u256::U256,
483 };
484
485 use super::*;
486
487 macro_rules! struct_layout {
488 ($type:literal { $($name:literal : $layout:expr),* $(,)?}) => {
489 A::MoveTypeLayout::Struct(Box::new(S {
490 type_: StructTag::from_str($type).expect("Failed to parse struct"),
491 fields: vec![$(MoveFieldLayout {
492 name: ident_str!($name).to_owned(),
493 layout: $layout,
494 }),*]
495 }))
496 }
497 }
498
499 macro_rules! vector_layout {
500 ($inner:expr) => {
501 A::MoveTypeLayout::Vector(Box::new($inner))
502 };
503 }
504
505 fn address(a: &str) -> SuiAddress {
506 SuiAddress::from_str(a).unwrap()
507 }
508
509 fn data<T: Serialize>(layout: A::MoveTypeLayout, data: T) -> Result<MoveData, Error> {
510 let tag: TypeTag = (&layout).into();
511
512 data_with_tag(format!("{}", tag), layout, data)
516 }
517
518 fn data_with_tag<T: Serialize>(
519 tag: impl Into<String>,
520 layout: A::MoveTypeLayout,
521 data: T,
522 ) -> Result<MoveData, Error> {
523 let tag = TypeTag::from_str(tag.into().as_str()).unwrap();
524 let type_ = MoveType::from(tag);
525 let bcs = Base64(bcs::to_bytes(&data).unwrap());
526 MoveValue { type_, bcs }.data_impl(layout)
527 }
528
529 fn json<T: Serialize>(layout: A::MoveTypeLayout, data: T) -> Result<Json, Error> {
530 let tag: TypeTag = (&layout).into();
531 let type_ = MoveType::from(tag);
532 let bcs = Base64(bcs::to_bytes(&data).unwrap());
533 MoveValue { type_, bcs }.json_impl(layout)
534 }
535
536 #[test]
537 fn bool_data() {
538 let v = data(L::Bool, true);
539 let expect = expect!["Ok(Bool(true))"];
540 expect.assert_eq(&format!("{v:?}"));
541 }
542
543 #[test]
544 fn bool_json() {
545 let v = json(L::Bool, true).unwrap();
546 let expect = expect!["true"];
547 expect.assert_eq(&format!("{v}"));
548 }
549
550 #[test]
551 fn u8_data() {
552 let v = data(L::U8, 42u8);
553 let expect = expect![[r#"Ok(Number(BigInt("42")))"#]];
554 expect.assert_eq(&format!("{v:?}"));
555 }
556
557 #[test]
558 fn u8_json() {
559 let v = json(L::U8, 42u8).unwrap();
560 let expect = expect!["42"];
561 expect.assert_eq(&format!("{v}"));
562 }
563
564 #[test]
565 fn u16_data() {
566 let v = data(L::U16, 424u16);
567 let expect = expect![[r#"Ok(Number(BigInt("424")))"#]];
568 expect.assert_eq(&format!("{v:?}"));
569 }
570
571 #[test]
572 fn u16_json() {
573 let v = json(L::U16, 424u16).unwrap();
574 let expect = expect!["424"];
575 expect.assert_eq(&format!("{v}"));
576 }
577
578 #[test]
579 fn u32_data() {
580 let v = data(L::U32, 424_242u32);
581 let expect = expect![[r#"Ok(Number(BigInt("424242")))"#]];
582 expect.assert_eq(&format!("{v:?}"));
583 }
584
585 #[test]
586 fn u32_json() {
587 let v = json(L::U32, 424_242u32).unwrap();
588 let expect = expect!["424242"];
589 expect.assert_eq(&format!("{v}"));
590 }
591
592 #[test]
593 fn u64_data() {
594 let v = data(L::U64, 42_424_242_424u64);
595 let expect = expect![[r#"Ok(Number(BigInt("42424242424")))"#]];
596 expect.assert_eq(&format!("{v:?}"));
597 }
598
599 #[test]
600 fn u64_json() {
601 let v = json(L::U64, 42_424_242_424u64).unwrap();
602 let expect = expect![[r#""42424242424""#]];
603 expect.assert_eq(&format!("{v}"));
604 }
605
606 #[test]
607 fn u128_data() {
608 let v = data(L::U128, 424_242_424_242_424_242_424u128);
609 let expect = expect![[r#"Ok(Number(BigInt("424242424242424242424")))"#]];
610 expect.assert_eq(&format!("{v:?}"));
611 }
612
613 #[test]
614 fn u128_json() {
615 let v = json(L::U128, 424_242_424_242_424_242_424u128).unwrap();
616 let expect = expect![[r#""424242424242424242424""#]];
617 expect.assert_eq(&format!("{v}"));
618 }
619
620 #[test]
621 fn u256_data() {
622 let v = data(
623 L::U256,
624 U256::from_str("42424242424242424242424242424242424242424").unwrap(),
625 );
626 let expect =
627 expect![[r#"Ok(Number(BigInt("42424242424242424242424242424242424242424")))"#]];
628 expect.assert_eq(&format!("{v:?}"));
629 }
630
631 #[test]
632 fn u256_json() {
633 let v = json(
634 L::U256,
635 U256::from_str("42424242424242424242424242424242424242424").unwrap(),
636 )
637 .unwrap();
638 let expect = expect![[r#""42424242424242424242424242424242424242424""#]];
639 expect.assert_eq(&format!("{v}"));
640 }
641
642 #[test]
643 fn ascii_string_data() {
644 let l = struct_layout!("0x1::ascii::String" {
645 "bytes": vector_layout!(L::U8)
646 });
647
648 let v = data(l, "The quick brown fox");
649 let expect = expect![[r#"Ok(String("The quick brown fox"))"#]];
650 expect.assert_eq(&format!("{v:?}"));
651 }
652
653 #[test]
654 fn ascii_string_json() {
655 let l = struct_layout!("0x1::ascii::String" {
656 "bytes": vector_layout!(L::U8)
657 });
658
659 let v = json(l, "The quick brown fox").unwrap();
660 let expect = expect![[r#""The quick brown fox""#]];
661 expect.assert_eq(&format!("{v}"));
662 }
663
664 #[test]
665 fn utf8_string_data() {
666 let l = struct_layout!("0x1::string::String" {
667 "bytes": vector_layout!(L::U8)
668 });
669
670 let v = data(l, "jumped over the lazy dog.");
671 let expect = expect![[r#"Ok(String("jumped over the lazy dog."))"#]];
672 expect.assert_eq(&format!("{v:?}"));
673 }
674
675 #[test]
676 fn utf8_string_json() {
677 let l = struct_layout!("0x1::string::String" {
678 "bytes": vector_layout!(L::U8)
679 });
680
681 let v = json(l, "jumped over the lazy dog.").unwrap();
682 let expect = expect![[r#""jumped over the lazy dog.""#]];
683 expect.assert_eq(&format!("{v}"));
684 }
685
686 #[test]
687 fn string_encoding_error() {
688 let l = struct_layout!("0x1::string::String" {
689 "bytes": vector_layout!(L::U8)
690 });
691
692 let mut bytes = "Lorem ipsum dolor sit amet consectetur".as_bytes().to_vec();
693 bytes[5] = 0xff;
694
695 let v = data(l, bytes);
696 let expect = expect![[r#"
697 Err(
698 Internal(
699 "invalid utf-8 sequence of 1 bytes from index 5 in \"Lorem�ipsum dolor sit amet ...\"",
700 ),
701 )"#]];
702 expect.assert_eq(&format!("{v:#?}"));
703 }
704
705 #[test]
706 fn address_data() {
707 let v = data(L::Address, address("0x42"));
708 let expect = expect!["Ok(Address(SuiAddress([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, 0, 0, 0, 66])))"];
709 expect.assert_eq(&format!("{v:?}"));
710 }
711
712 #[test]
713 fn address_json() {
714 let v = json(L::Address, address("0x42")).unwrap();
715 let expect =
716 expect![[r#""0x0000000000000000000000000000000000000000000000000000000000000042""#]];
717 expect.assert_eq(&format!("{v}"));
718 }
719
720 #[test]
721 fn uid_data() {
722 let l = struct_layout!("0x2::object::UID" {
723 "id": struct_layout!("0x2::object::ID" {
724 "bytes": L::Address,
725 })
726 });
727
728 let v = data(l, address("0x42"));
729 let expect = expect!["Ok(Uid(SuiAddress([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, 0, 0, 0, 66])))"];
730 expect.assert_eq(&format!("{v:?}"));
731 }
732
733 #[test]
734 fn uid_json() {
735 let l = struct_layout!("0x2::object::UID" {
736 "id": struct_layout!("0x2::object::ID" {
737 "bytes": L::Address,
738 })
739 });
740
741 let v = json(l, address("0x42")).unwrap();
742 let expect =
743 expect![[r#""0x0000000000000000000000000000000000000000000000000000000000000042""#]];
744 expect.assert_eq(&format!("{v}"));
745 }
746
747 #[test]
748 fn compound_data() {
749 let l = struct_layout!("0x42::foo::Bar" {
750 "baz": struct_layout!("0x1::option::Option" { "vec": vector_layout!(L::U8) }),
751 "qux": vector_layout!(struct_layout!("0x43::xy::Zzy" {
752 "quy": L::U16,
753 "quz": struct_layout!("0x1::option::Option" {
754 "vec": vector_layout!(struct_layout!("0x1::ascii::String" {
755 "bytes": vector_layout!(L::U8),
756 }))
757 }),
758 "frob": L::Address,
759 })),
760 });
761
762 let v = data(
763 l,
764 (
765 vec![] as Vec<Vec<u8>>,
766 vec![
767 (44u16, vec!["Hello, world!"], address("0x45")),
768 (46u16, vec![], address("0x47")),
769 ],
770 ),
771 );
772
773 let expect = expect![[r#"
774 Ok(
775 Struct(
776 [
777 MoveField {
778 name: "baz",
779 value: Option(
780 None,
781 ),
782 },
783 MoveField {
784 name: "qux",
785 value: Vector(
786 [
787 Struct(
788 [
789 MoveField {
790 name: "quy",
791 value: Number(
792 BigInt(
793 "44",
794 ),
795 ),
796 },
797 MoveField {
798 name: "quz",
799 value: Option(
800 Some(
801 String(
802 "Hello, world!",
803 ),
804 ),
805 ),
806 },
807 MoveField {
808 name: "frob",
809 value: Address(
810 SuiAddress(
811 [
812 0,
813 0,
814 0,
815 0,
816 0,
817 0,
818 0,
819 0,
820 0,
821 0,
822 0,
823 0,
824 0,
825 0,
826 0,
827 0,
828 0,
829 0,
830 0,
831 0,
832 0,
833 0,
834 0,
835 0,
836 0,
837 0,
838 0,
839 0,
840 0,
841 0,
842 0,
843 69,
844 ],
845 ),
846 ),
847 },
848 ],
849 ),
850 Struct(
851 [
852 MoveField {
853 name: "quy",
854 value: Number(
855 BigInt(
856 "46",
857 ),
858 ),
859 },
860 MoveField {
861 name: "quz",
862 value: Option(
863 None,
864 ),
865 },
866 MoveField {
867 name: "frob",
868 value: Address(
869 SuiAddress(
870 [
871 0,
872 0,
873 0,
874 0,
875 0,
876 0,
877 0,
878 0,
879 0,
880 0,
881 0,
882 0,
883 0,
884 0,
885 0,
886 0,
887 0,
888 0,
889 0,
890 0,
891 0,
892 0,
893 0,
894 0,
895 0,
896 0,
897 0,
898 0,
899 0,
900 0,
901 0,
902 71,
903 ],
904 ),
905 ),
906 },
907 ],
908 ),
909 ],
910 ),
911 },
912 ],
913 ),
914 )"#]];
915 expect.assert_eq(&format!("{v:#?}"));
916 }
917
918 #[test]
919 fn compound_json() {
920 let l = struct_layout!("0x42::foo::Bar" {
921 "baz": struct_layout!("0x1::option::Option" { "vec": vector_layout!(L::U8) }),
922 "qux": vector_layout!(struct_layout!("0x43::xy::Zzy" {
923 "quy": L::U16,
924 "quz": struct_layout!("0x1::option::Option" {
925 "vec": vector_layout!(struct_layout!("0x1::ascii::String" {
926 "bytes": vector_layout!(L::U8),
927 }))
928 }),
929 "frob": L::Address,
930 })),
931 });
932
933 let v = json(
934 l,
935 (
936 vec![] as Vec<Vec<u8>>,
937 vec![
938 (44u16, vec!["Hello, world!"], address("0x45")),
939 (46u16, vec![], address("0x47")),
940 ],
941 ),
942 )
943 .unwrap();
944
945 let expect = expect![[
946 r#"{baz: null,qux: [{quy: 44,quz: "Hello, world!",frob: "0x0000000000000000000000000000000000000000000000000000000000000045"},{quy: 46,quz: null,frob: "0x0000000000000000000000000000000000000000000000000000000000000047"}]}"#
947 ]];
948 expect.assert_eq(&format!("{v}"));
949 }
950
951 #[test]
952 fn signer_value() {
953 let v = data(L::Signer, address("0x42"));
954 let expect = expect![[r#"
955 Err(
956 Internal(
957 "Unexpected value of type: signer.",
958 ),
959 )"#]];
960 expect.assert_eq(&format!("{v:#?}"));
961 }
962
963 #[test]
964 fn signer_json() {
965 let err = json(L::Signer, address("0x42")).unwrap_err();
966 let expect = expect![[r#"Internal("Unexpected value of type: signer.")"#]];
967 expect.assert_eq(&format!("{err:?}"));
968 }
969
970 #[test]
971 fn signer_nested_data() {
972 let v = data(
973 vector_layout!(L::Signer),
974 vec![address("0x42"), address("0x43")],
975 );
976 let expect = expect![[r#"
977 Err(
978 Internal(
979 "Unexpected value of type: signer.",
980 ),
981 )"#]];
982 expect.assert_eq(&format!("{v:#?}"));
983 }
984
985 #[test]
986 fn signer_nested_json() {
987 let err = json(
988 vector_layout!(L::Signer),
989 vec![address("0x42"), address("0x43")],
990 )
991 .unwrap_err();
992
993 let expect = expect![[r#"Internal("Unexpected value of type: signer.")"#]];
994 expect.assert_eq(&format!("{err:?}"));
995 }
996}