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