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