1use async_graphql::*;
6use iota_types::{
7 base_types::{StructTag, TypeTag},
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 Some(layout) = self.type_.layout_impl(resolver).await.extend()? else {
115 return Err(Error::Internal(
116 "Move value must have valid layout".to_string(),
117 ))
118 .extend();
119 };
120
121 self.data_impl(layout).extend()
124 }
125
126 #[graphql(complexity = 0)]
140 async fn json(&self, ctx: &Context<'_>) -> Result<Json> {
141 let resolver: &PackageResolver = ctx
142 .data()
143 .map_err(|_| Error::Internal("Unable to fetch Package Cache.".to_string()))
144 .extend()?;
145
146 let Some(layout) = self.type_.layout_impl(resolver).await.extend()? else {
147 return Err(Error::Internal(
148 "Move value must have valid layout".to_string(),
149 ))
150 .extend();
151 };
152
153 self.json_impl(layout).extend()
156 }
157}
158
159impl MoveValue {
160 pub fn new(tag: TypeTag, bcs: Base64) -> Self {
161 let type_ = MoveType::from(tag);
162 Self { type_, bcs }
163 }
164
165 fn value_impl(&self, layout: A::MoveTypeLayout) -> Result<A::MoveValue, Error> {
166 BoundedVisitor::deserialize_value(&self.bcs.0[..], &layout).map_err(|_| {
168 let type_tag: TypeTag = type_tag_core_to_sdk(&(&layout).into());
169 Error::Internal(format!(
170 "Failed to deserialize Move value for type: {type_tag}"
171 ))
172 })
173 }
174
175 fn data_impl(&self, layout: A::MoveTypeLayout) -> Result<MoveData, Error> {
176 MoveData::try_from(self.value_impl(layout)?)
177 }
178
179 fn json_impl(&self, layout: A::MoveTypeLayout) -> Result<Json, Error> {
180 Ok(try_to_json_value(self.value_impl(layout)?)?.into())
181 }
182}
183
184impl TryFrom<A::MoveValue> for MoveData {
185 type Error = Error;
186
187 fn try_from(value: A::MoveValue) -> Result<Self, Error> {
188 use A::MoveValue as V;
189
190 Ok(match value {
191 V::U8(n) => Self::Number(BigInt::from(n)),
192 V::U16(n) => Self::Number(BigInt::from(n)),
193 V::U32(n) => Self::Number(BigInt::from(n)),
194 V::U64(n) => Self::Number(BigInt::from(n)),
195 V::U128(n) => Self::Number(BigInt::from(n)),
196 V::U256(n) => Self::Number(BigInt::from(n)),
197
198 V::Bool(b) => Self::Bool(b),
199 V::Address(a) => Self::Address(a.into()),
200
201 V::Vector(v) => Self::Vector(
202 v.into_iter()
203 .map(MoveData::try_from)
204 .collect::<Result<Vec<_>, _>>()?,
205 ),
206
207 V::Struct(s) => {
208 let A::MoveStruct { type_, fields } = s;
209 let type_ = struct_tag_core_to_sdk(&type_);
210 if is_type(&type_, &STD, MOD_OPTION, TYPE_OPTION) {
211 Self::Option(match extract_option(&type_, fields)? {
213 Some(value) => Some(Box::new(MoveData::try_from(value)?)),
214 None => None,
215 })
216 } else if is_type(&type_, &STD, MOD_ASCII, TYPE_STRING)
217 || is_type(&type_, &STD, MOD_STRING, TYPE_STRING)
218 {
219 Self::String(extract_string(&type_, fields)?)
221 } else if is_type(&type_, &IOTA, MOD_OBJECT, TYPE_UID) {
222 Self::Uid(extract_uid(&type_, fields)?.into())
224 } else if is_type(&type_, &IOTA, MOD_OBJECT, TYPE_ID) {
225 Self::Id(extract_id(&type_, fields)?.into())
227 } else {
228 let fields: Result<Vec<_>, _> =
230 fields.into_iter().map(MoveField::try_from).collect();
231 Self::Struct(fields?)
232 }
233 }
234
235 V::Variant(A::MoveVariant {
236 type_: _,
237 variant_name,
238 tag: _,
239 fields,
240 }) => {
241 let fields = fields
242 .into_iter()
243 .map(MoveField::try_from)
244 .collect::<Result<_, _>>()?;
245 Self::Variant(MoveVariant {
246 name: variant_name.to_string(),
247 fields,
248 })
249 }
250
251 V::Signer(_) => return Err(unexpected_signer_error()),
253 })
254 }
255}
256
257impl TryFrom<(Identifier, A::MoveValue)> for MoveField {
258 type Error = Error;
259
260 fn try_from((ident, value): (Identifier, A::MoveValue)) -> Result<Self, Error> {
261 Ok(MoveField {
262 name: ident.to_string(),
263 value: MoveData::try_from(value)?,
264 })
265 }
266}
267
268fn try_to_json_value(value: A::MoveValue) -> Result<Value, Error> {
269 use A::MoveValue as V;
270 Ok(match value {
271 V::U8(n) => Value::Number(n.into()),
272 V::U16(n) => Value::Number(n.into()),
273 V::U32(n) => Value::Number(n.into()),
274 V::U64(n) => Value::String(n.to_string()),
275 V::U128(n) => Value::String(n.to_string()),
276 V::U256(n) => Value::String(n.to_string()),
277
278 V::Bool(b) => Value::Boolean(b),
279 V::Address(a) => Value::String(a.to_canonical_string(true)),
280
281 V::Vector(xs) => Value::List(
282 xs.into_iter()
283 .map(try_to_json_value)
284 .collect::<Result<_, _>>()?,
285 ),
286
287 V::Struct(s) => {
288 let A::MoveStruct { type_, fields } = s;
289 let type_ = struct_tag_core_to_sdk(&type_);
290 if is_type(&type_, &STD, MOD_OPTION, TYPE_OPTION) {
291 match extract_option(&type_, fields)? {
293 Some(value) => try_to_json_value(value)?,
294 None => Value::Null,
295 }
296 } else if is_type(&type_, &STD, MOD_ASCII, TYPE_STRING)
297 || is_type(&type_, &STD, MOD_STRING, TYPE_STRING)
298 {
299 Value::String(extract_string(&type_, fields)?)
301 } else if is_type(&type_, &IOTA, MOD_OBJECT, TYPE_UID) {
302 Value::String(
304 extract_uid(&type_, fields)?.to_canonical_string(true),
305 )
306 } else if is_type(&type_, &IOTA, MOD_OBJECT, TYPE_ID) {
307 Value::String(
309 extract_id(&type_, fields)?.to_canonical_string(true),
310 )
311 } else {
312 Value::Object(
314 fields
315 .into_iter()
316 .map(|(name, value)| {
317 Ok((Name::new(name.to_string()), try_to_json_value(value)?))
318 })
319 .collect::<Result<_, Error>>()?,
320 )
321 }
322 }
323
324 V::Variant(A::MoveVariant {
325 type_: _,
326 variant_name,
327 tag: _,
328 fields,
329 }) => {
330 let fields = fields
331 .into_iter()
332 .map(|(name, value)| Ok((Name::new(name.to_string()), try_to_json_value(value)?)))
333 .collect::<Result<_, Error>>()?;
334 Value::Object(
335 vec![(Name::new(variant_name.to_string()), Value::Object(fields))]
336 .into_iter()
337 .collect(),
338 )
339 }
340 V::Signer(_) => return Err(unexpected_signer_error()),
342 })
343}
344
345fn is_type(tag: &StructTag, address: &AccountAddress, module: &IdentStr, name: &IdentStr) -> bool {
346 tag.address().as_bytes() == address.as_ref()
347 && tag.module().as_str() == module.as_str()
348 && tag.name().as_str() == name.as_str()
349}
350
351macro_rules! extract_field {
352 ($type:expr, $fields:expr, $name:ident) => {{
353 let _name = ident_str!(stringify!($name));
354 let _type = $type;
355 if let Some(value) = ($fields)
356 .into_iter()
357 .find_map(|(name, value)| (&*name == _name).then_some(value))
358 {
359 value
360 } else {
361 return Err(Error::Internal(format!(
362 "Couldn't find expected field '{_name}' of {_type}."
363 )));
364 }
365 }};
366}
367
368fn extract_bytes(value: A::MoveValue) -> Result<Vec<u8>, Error> {
371 use A::MoveValue as V;
372 let V::Vector(elements) = value else {
373 return Err(Error::Internal("Expected a vector.".to_string()));
374 };
375
376 let mut bytes = Vec::with_capacity(elements.len());
377 for element in elements {
378 let V::U8(byte) = element else {
379 return Err(Error::Internal("Expected a byte.".to_string()));
380 };
381 bytes.push(byte)
382 }
383
384 Ok(bytes)
385}
386
387fn extract_string(
397 type_: &StructTag,
398 fields: Vec<(Identifier, A::MoveValue)>,
399) -> Result<String, Error> {
400 let bytes = extract_bytes(extract_field!(type_, fields, bytes))?;
401 String::from_utf8(bytes).map_err(|e| {
402 const PREFIX: usize = 30;
403 let bytes = e.as_bytes();
404
405 let sample = if bytes.len() < PREFIX {
407 String::from_utf8_lossy(bytes)
408 } else {
409 String::from_utf8_lossy(&bytes[..PREFIX - 3]) + "..."
410 };
411
412 Error::Internal(format!("{e} in {sample:?}"))
413 })
414}
415
416fn extract_id(
425 type_: &StructTag,
426 fields: Vec<(Identifier, A::MoveValue)>,
427) -> Result<AccountAddress, Error> {
428 use A::MoveValue as V;
429 let V::Address(addr) = extract_field!(type_, fields, bytes) else {
430 return Err(Error::Internal(
431 "Expected ID.bytes to have type address.".to_string(),
432 ));
433 };
434
435 Ok(addr)
436}
437
438fn extract_uid(
447 type_: &StructTag,
448 fields: Vec<(Identifier, A::MoveValue)>,
449) -> Result<AccountAddress, Error> {
450 use A::MoveValue as V;
451 let V::Struct(s) = extract_field!(type_, fields, id) else {
452 return Err(Error::Internal(
453 "Expected UID.id to be a struct".to_string(),
454 ));
455 };
456
457 let A::MoveStruct { type_, fields } = s;
458 let type_ = struct_tag_core_to_sdk(&type_);
459 if !is_type(&type_, &IOTA, MOD_OBJECT, TYPE_ID) {
460 return Err(Error::Internal(
461 "Expected UID.id to have type ID.".to_string(),
462 ));
463 }
464
465 extract_id(&type_, fields)
466}
467
468fn extract_option(
478 type_: &StructTag,
479 fields: Vec<(Identifier, A::MoveValue)>,
480) -> Result<Option<A::MoveValue>, Error> {
481 let A::MoveValue::Vector(mut elements) = extract_field!(type_, fields, vec) else {
482 return Err(Error::Internal(
483 "Expected Option.vec to be a vector.".to_string(),
484 ));
485 };
486
487 if elements.len() > 1 {
488 return Err(Error::Internal(
489 "Expected Option.vec to contain at most one element.".to_string(),
490 ));
491 };
492
493 Ok(elements.pop())
494}
495
496#[cfg(test)]
497mod tests {
498 use std::str::FromStr;
499
500 use expect_test::expect;
501 use move_core_types::{
502 annotated_value::{self as A, MoveFieldLayout, MoveStructLayout as S, MoveTypeLayout as L},
503 u256::U256,
504 };
505
506 use super::*;
507
508 macro_rules! struct_layout {
509 ($type:literal { $($name:literal : $layout:expr),* $(,)?}) => {
510 A::MoveTypeLayout::Struct(Box::new(S {
511 type_: move_core_types::language_storage::StructTag::from_str($type).expect("failed to parse struct"),
512 fields: vec![$(MoveFieldLayout {
513 name: ident_str!($name).to_owned(),
514 layout: $layout,
515 }),*]
516 }))
517 }
518 }
519
520 macro_rules! vector_layout {
521 ($inner:expr) => {
522 A::MoveTypeLayout::Vector(Box::new($inner))
523 };
524 }
525
526 fn address(a: &str) -> IotaAddress {
527 IotaAddress::from_str(a).unwrap()
528 }
529
530 fn data<T: Serialize>(layout: A::MoveTypeLayout, data: T) -> Result<MoveData, Error> {
531 let tag: TypeTag = type_tag_core_to_sdk(&(&layout).into());
532
533 data_with_tag(format!("{tag}"), layout, data)
537 }
538
539 fn data_with_tag<T: Serialize>(
540 tag: impl Into<String>,
541 layout: A::MoveTypeLayout,
542 data: T,
543 ) -> Result<MoveData, Error> {
544 let tag = TypeTag::from_str(tag.into().as_str()).unwrap();
545 let type_ = MoveType::from(tag);
546 let bcs = Base64(bcs::to_bytes(&data).unwrap());
547 MoveValue { type_, bcs }.data_impl(layout)
548 }
549
550 fn json<T: Serialize>(layout: A::MoveTypeLayout, data: T) -> Result<Json, Error> {
551 let tag: TypeTag = type_tag_core_to_sdk(&(&layout).into());
552 let type_ = MoveType::from(tag);
553 let bcs = Base64(bcs::to_bytes(&data).unwrap());
554 MoveValue { type_, bcs }.json_impl(layout)
555 }
556
557 #[test]
558 fn bool_data() {
559 let v = data(L::Bool, true);
560 let expect = expect!["Ok(Bool(true))"];
561 expect.assert_eq(&format!("{v:?}"));
562 }
563
564 #[test]
565 fn bool_json() {
566 let v = json(L::Bool, true).unwrap();
567 let expect = expect!["true"];
568 expect.assert_eq(&format!("{v}"));
569 }
570
571 #[test]
572 fn u8_data() {
573 let v = data(L::U8, 42u8);
574 let expect = expect![[r#"Ok(Number(BigInt("42")))"#]];
575 expect.assert_eq(&format!("{v:?}"));
576 }
577
578 #[test]
579 fn u8_json() {
580 let v = json(L::U8, 42u8).unwrap();
581 let expect = expect!["42"];
582 expect.assert_eq(&format!("{v}"));
583 }
584
585 #[test]
586 fn u16_data() {
587 let v = data(L::U16, 424u16);
588 let expect = expect![[r#"Ok(Number(BigInt("424")))"#]];
589 expect.assert_eq(&format!("{v:?}"));
590 }
591
592 #[test]
593 fn u16_json() {
594 let v = json(L::U16, 424u16).unwrap();
595 let expect = expect!["424"];
596 expect.assert_eq(&format!("{v}"));
597 }
598
599 #[test]
600 fn u32_data() {
601 let v = data(L::U32, 424_242u32);
602 let expect = expect![[r#"Ok(Number(BigInt("424242")))"#]];
603 expect.assert_eq(&format!("{v:?}"));
604 }
605
606 #[test]
607 fn u32_json() {
608 let v = json(L::U32, 424_242u32).unwrap();
609 let expect = expect!["424242"];
610 expect.assert_eq(&format!("{v}"));
611 }
612
613 #[test]
614 fn u64_data() {
615 let v = data(L::U64, 42_424_242_424u64);
616 let expect = expect![[r#"Ok(Number(BigInt("42424242424")))"#]];
617 expect.assert_eq(&format!("{v:?}"));
618 }
619
620 #[test]
621 fn u64_json() {
622 let v = json(L::U64, 42_424_242_424u64).unwrap();
623 let expect = expect![[r#""42424242424""#]];
624 expect.assert_eq(&format!("{v}"));
625 }
626
627 #[test]
628 fn u128_data() {
629 let v = data(L::U128, 424_242_424_242_424_242_424u128);
630 let expect = expect![[r#"Ok(Number(BigInt("424242424242424242424")))"#]];
631 expect.assert_eq(&format!("{v:?}"));
632 }
633
634 #[test]
635 fn u128_json() {
636 let v = json(L::U128, 424_242_424_242_424_242_424u128).unwrap();
637 let expect = expect![[r#""424242424242424242424""#]];
638 expect.assert_eq(&format!("{v}"));
639 }
640
641 #[test]
642 fn u256_data() {
643 let v = data(
644 L::U256,
645 U256::from_str("42424242424242424242424242424242424242424").unwrap(),
646 );
647 let expect =
648 expect![[r#"Ok(Number(BigInt("42424242424242424242424242424242424242424")))"#]];
649 expect.assert_eq(&format!("{v:?}"));
650 }
651
652 #[test]
653 fn u256_json() {
654 let v = json(
655 L::U256,
656 U256::from_str("42424242424242424242424242424242424242424").unwrap(),
657 )
658 .unwrap();
659 let expect = expect![[r#""42424242424242424242424242424242424242424""#]];
660 expect.assert_eq(&format!("{v}"));
661 }
662
663 #[test]
664 fn ascii_string_data() {
665 let l = struct_layout!("0x1::ascii::String" {
666 "bytes": vector_layout!(L::U8)
667 });
668
669 let v = data(l, "The quick brown fox");
670 let expect = expect![[r#"Ok(String("The quick brown fox"))"#]];
671 expect.assert_eq(&format!("{v:?}"));
672 }
673
674 #[test]
675 fn ascii_string_json() {
676 let l = struct_layout!("0x1::ascii::String" {
677 "bytes": vector_layout!(L::U8)
678 });
679
680 let v = json(l, "The quick brown fox").unwrap();
681 let expect = expect![[r#""The quick brown fox""#]];
682 expect.assert_eq(&format!("{v}"));
683 }
684
685 #[test]
686 fn utf8_string_data() {
687 let l = struct_layout!("0x1::string::String" {
688 "bytes": vector_layout!(L::U8)
689 });
690
691 let v = data(l, "jumped over the lazy dog.");
692 let expect = expect![[r#"Ok(String("jumped over the lazy dog."))"#]];
693 expect.assert_eq(&format!("{v:?}"));
694 }
695
696 #[test]
697 fn utf8_string_json() {
698 let l = struct_layout!("0x1::string::String" {
699 "bytes": vector_layout!(L::U8)
700 });
701
702 let v = json(l, "jumped over the lazy dog.").unwrap();
703 let expect = expect![[r#""jumped over the lazy dog.""#]];
704 expect.assert_eq(&format!("{v}"));
705 }
706
707 #[test]
708 fn string_encoding_error() {
709 let l = struct_layout!("0x1::string::String" {
710 "bytes": vector_layout!(L::U8)
711 });
712
713 let mut bytes = "Lorem ipsum dolor sit amet consectetur".as_bytes().to_vec();
714 bytes[5] = 0xff;
715
716 let v = data(l, bytes);
717 let expect = expect![[r#"
718 Err(
719 Internal(
720 "invalid utf-8 sequence of 1 bytes from index 5 in \"Lorem�ipsum dolor sit amet ...\"",
721 ),
722 )"#]];
723 expect.assert_eq(&format!("{v:#?}"));
724 }
725
726 #[test]
727 fn address_data() {
728 let v = data(L::Address, address("0x42"));
729 let expect = expect![
730 "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])))"
731 ];
732 expect.assert_eq(&format!("{v:?}"));
733 }
734
735 #[test]
736 fn address_json() {
737 let v = json(L::Address, address("0x42")).unwrap();
738 let expect =
739 expect![[r#""0x0000000000000000000000000000000000000000000000000000000000000042""#]];
740 expect.assert_eq(&format!("{v}"));
741 }
742
743 #[test]
744 fn uid_data() {
745 let l = struct_layout!("0x2::object::UID" {
746 "id": struct_layout!("0x2::object::ID" {
747 "bytes": L::Address,
748 })
749 });
750
751 let v = data(l, address("0x42"));
752 let expect = expect![
753 "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])))"
754 ];
755 expect.assert_eq(&format!("{v:?}"));
756 }
757
758 #[test]
759 fn uid_json() {
760 let l = struct_layout!("0x2::object::UID" {
761 "id": struct_layout!("0x2::object::ID" {
762 "bytes": L::Address,
763 })
764 });
765
766 let v = json(l, address("0x42")).unwrap();
767 let expect =
768 expect![[r#""0x0000000000000000000000000000000000000000000000000000000000000042""#]];
769 expect.assert_eq(&format!("{v}"));
770 }
771
772 #[test]
773 fn compound_data() {
774 let l = struct_layout!("0x42::foo::Bar" {
775 "baz": struct_layout!("0x1::option::Option" { "vec": vector_layout!(L::U8) }),
776 "qux": vector_layout!(struct_layout!("0x43::xy::Zzy" {
777 "quy": L::U16,
778 "quz": struct_layout!("0x1::option::Option" {
779 "vec": vector_layout!(struct_layout!("0x1::ascii::String" {
780 "bytes": vector_layout!(L::U8),
781 }))
782 }),
783 "frob": L::Address,
784 })),
785 });
786
787 let v = data(
788 l,
789 (
790 vec![] as Vec<Vec<u8>>,
791 vec![
792 (44u16, vec!["Hello, world!"], address("0x45")),
793 (46u16, vec![], address("0x47")),
794 ],
795 ),
796 );
797
798 let expect = expect![[r#"
799 Ok(
800 Struct(
801 [
802 MoveField {
803 name: "baz",
804 value: Option(
805 None,
806 ),
807 },
808 MoveField {
809 name: "qux",
810 value: Vector(
811 [
812 Struct(
813 [
814 MoveField {
815 name: "quy",
816 value: Number(
817 BigInt(
818 "44",
819 ),
820 ),
821 },
822 MoveField {
823 name: "quz",
824 value: Option(
825 Some(
826 String(
827 "Hello, world!",
828 ),
829 ),
830 ),
831 },
832 MoveField {
833 name: "frob",
834 value: Address(
835 IotaAddress(
836 [
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 0,
859 0,
860 0,
861 0,
862 0,
863 0,
864 0,
865 0,
866 0,
867 0,
868 69,
869 ],
870 ),
871 ),
872 },
873 ],
874 ),
875 Struct(
876 [
877 MoveField {
878 name: "quy",
879 value: Number(
880 BigInt(
881 "46",
882 ),
883 ),
884 },
885 MoveField {
886 name: "quz",
887 value: Option(
888 None,
889 ),
890 },
891 MoveField {
892 name: "frob",
893 value: Address(
894 IotaAddress(
895 [
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 0,
918 0,
919 0,
920 0,
921 0,
922 0,
923 0,
924 0,
925 0,
926 0,
927 71,
928 ],
929 ),
930 ),
931 },
932 ],
933 ),
934 ],
935 ),
936 },
937 ],
938 ),
939 )"#]];
940 expect.assert_eq(&format!("{v:#?}"));
941 }
942
943 #[test]
944 fn compound_json() {
945 let l = struct_layout!("0x42::foo::Bar" {
946 "baz": struct_layout!("0x1::option::Option" { "vec": vector_layout!(L::U8) }),
947 "qux": vector_layout!(struct_layout!("0x43::xy::Zzy" {
948 "quy": L::U16,
949 "quz": struct_layout!("0x1::option::Option" {
950 "vec": vector_layout!(struct_layout!("0x1::ascii::String" {
951 "bytes": vector_layout!(L::U8),
952 }))
953 }),
954 "frob": L::Address,
955 })),
956 });
957
958 let v = json(
959 l,
960 (
961 vec![] as Vec<Vec<u8>>,
962 vec![
963 (44u16, vec!["Hello, world!"], address("0x45")),
964 (46u16, vec![], address("0x47")),
965 ],
966 ),
967 )
968 .unwrap();
969
970 let expect = expect![[
971 r#"{baz: null, qux: [{quy: 44, quz: "Hello, world!", frob: "0x0000000000000000000000000000000000000000000000000000000000000045"}, {quy: 46, quz: null, frob: "0x0000000000000000000000000000000000000000000000000000000000000047"}]}"#
972 ]];
973 expect.assert_eq(&format!("{v}"));
974 }
975
976 #[test]
977 fn signer_value() {
978 let v = data(L::Signer, address("0x42"));
979 let expect = expect![[r#"
980 Err(
981 Internal(
982 "Unexpected value of type: signer.",
983 ),
984 )"#]];
985 expect.assert_eq(&format!("{v:#?}"));
986 }
987
988 #[test]
989 fn signer_json() {
990 let err = json(L::Signer, address("0x42")).unwrap_err();
991 let expect = expect![[r#"Internal("Unexpected value of type: signer.")"#]];
992 expect.assert_eq(&format!("{err:?}"));
993 }
994
995 #[test]
996 fn signer_nested_data() {
997 let v = data(
998 vector_layout!(L::Signer),
999 vec![address("0x42"), address("0x43")],
1000 );
1001 let expect = expect![[r#"
1002 Err(
1003 Internal(
1004 "Unexpected value of type: signer.",
1005 ),
1006 )"#]];
1007 expect.assert_eq(&format!("{v:#?}"));
1008 }
1009
1010 #[test]
1011 fn signer_nested_json() {
1012 let err = json(
1013 vector_layout!(L::Signer),
1014 vec![address("0x42"), address("0x43")],
1015 )
1016 .unwrap_err();
1017
1018 let expect = expect![[r#"Internal("Unexpected value of type: signer.")"#]];
1019 expect.assert_eq(&format!("{err:?}"));
1020 }
1021}