soroban_spec_tools/
lib.rs

1#![allow(clippy::missing_errors_doc, clippy::must_use_candidate)]
2use std::fmt::Write;
3use std::str::FromStr;
4
5use itertools::Itertools;
6use serde_json::{json, Value};
7use stellar_xdr::curr::{
8    AccountId, BytesM, ContractExecutable, ContractId, Error as XdrError, Hash, Int128Parts,
9    Int256Parts, MuxedEd25519Account, PublicKey, ScAddress, ScBytes, ScContractInstance, ScMap,
10    ScMapEntry, ScNonceKey, ScSpecEntry, ScSpecEventV0, ScSpecFunctionV0, ScSpecTypeDef as ScType,
11    ScSpecTypeMap, ScSpecTypeOption, ScSpecTypeResult, ScSpecTypeTuple, ScSpecTypeUdt,
12    ScSpecTypeVec, ScSpecUdtEnumV0, ScSpecUdtErrorEnumCaseV0, ScSpecUdtErrorEnumV0,
13    ScSpecUdtStructV0, ScSpecUdtUnionCaseTupleV0, ScSpecUdtUnionCaseV0, ScSpecUdtUnionCaseVoidV0,
14    ScSpecUdtUnionV0, ScString, ScSymbol, ScVal, ScVec, StringM, UInt128Parts, UInt256Parts,
15    Uint256, VecM,
16};
17
18pub mod contract;
19pub mod utils;
20
21#[derive(thiserror::Error, Debug)]
22pub enum Error {
23    #[error("an unknown error occurred")]
24    Unknown,
25    #[error("Invalid pair {0:#?} {1:#?}")]
26    InvalidPair(ScVal, ScType),
27    #[error("value is not parseable to {0:#?}")]
28    InvalidValue(Option<ScType>),
29    #[error("Unknown case {0} for {1}")]
30    EnumCase(String, String),
31    #[error("Enum {0} missing value for type {1}")]
32    EnumMissingSecondValue(String, String),
33    #[error("Enum {0} is illformed")]
34    IllFormedEnum(String),
35    #[error("Unknown const case {0}")]
36    EnumConst(u32),
37    #[error("Enum const value must be a u32 or smaller")]
38    EnumConstTooLarge(u64),
39    #[error("Missing Entry {0}")]
40    MissingEntry(String),
41    #[error("Missing Spec")]
42    MissingSpec,
43    #[error(transparent)]
44    Xdr(XdrError),
45    #[error(transparent)]
46    Serde(#[from] serde_json::Error),
47    #[error(transparent)]
48    Ethnum(#[from] core::num::ParseIntError),
49
50    #[error("Missing key {0} in map")]
51    MissingKey(String),
52    #[error("Failed to convert {0} to number")]
53    FailedNumConversion(serde_json::Number),
54    #[error("First argument in an enum must be a sybmol")]
55    EnumFirstValueNotSymbol,
56    #[error("Failed to find enum case {0}")]
57    FailedToFindEnumCase(String),
58    #[error(transparent)]
59    FailedSilceToByte(#[from] std::array::TryFromSliceError),
60    #[error(transparent)]
61    Infallible(#[from] std::convert::Infallible),
62    #[error("Missing Error case {0}")]
63    MissingErrorCase(u32),
64    #[error(transparent)]
65    Spec(#[from] soroban_spec::read::FromWasmError),
66    #[error(transparent)]
67    Base64Spec(#[from] soroban_spec::read::ParseSpecBase64Error),
68}
69
70#[derive(Default, Clone)]
71pub struct Spec(pub Option<Vec<ScSpecEntry>>);
72
73impl TryInto<Spec> for &[u8] {
74    type Error = soroban_spec::read::FromWasmError;
75
76    fn try_into(self) -> Result<Spec, Self::Error> {
77        let spec = soroban_spec::read::from_wasm(self)?;
78        Ok(Spec::new(spec.as_slice()))
79    }
80}
81
82impl Spec {
83    pub fn new(entries: &[ScSpecEntry]) -> Self {
84        Self(Some(entries.to_vec()))
85    }
86
87    pub fn from_wasm(wasm: &[u8]) -> Result<Spec, Error> {
88        let spec = soroban_spec::read::from_wasm(wasm)?;
89        Ok(Spec::new(spec.as_slice()))
90    }
91
92    pub fn parse_base64(base64: &str) -> Result<Spec, Error> {
93        let spec = soroban_spec::read::parse_base64(base64.as_bytes())?;
94        Ok(Spec::new(spec.as_slice()))
95    }
96}
97
98impl Spec {
99    /// # Errors
100    /// Could fail to find User Defined Type
101    pub fn doc(&self, name: &str, type_: &ScType) -> Result<Option<&'static str>, Error> {
102        let mut str = match type_ {
103            ScType::Val
104            | ScType::U64
105            | ScType::I64
106            | ScType::U128
107            | ScType::I128
108            | ScType::U32
109            | ScType::I32
110            | ScType::Result(_)
111            | ScType::Vec(_)
112            | ScType::Map(_)
113            | ScType::Tuple(_)
114            | ScType::BytesN(_)
115            | ScType::Symbol
116            | ScType::Error
117            | ScType::Bytes
118            | ScType::Void
119            | ScType::Timepoint
120            | ScType::Duration
121            | ScType::U256
122            | ScType::I256
123            | ScType::String
124            | ScType::Bool => String::new(),
125            ScType::MuxedAddress => {
126                String::from("Can be public key (G13..), contract ID (C13...), or a muxed account (M13..), or an identity")
127            }
128            ScType::Address => String::from(
129                "Can be public key (G13..), a contract ID (C13...) or an identity (alice), ",
130            ),
131            ScType::Option(type_) => return self.doc(name, &type_.value_type),
132            ScType::Udt(ScSpecTypeUdt { name }) => {
133                let spec_type = self.find(&name.to_utf8_string_lossy())?;
134                let spec_type_match = match spec_type {
135                    ScSpecEntry::FunctionV0(ScSpecFunctionV0 { doc, .. })
136                    | ScSpecEntry::UdtStructV0(ScSpecUdtStructV0 { doc, .. })
137                    | ScSpecEntry::UdtUnionV0(ScSpecUdtUnionV0 { doc, .. })
138                    | ScSpecEntry::UdtEnumV0(ScSpecUdtEnumV0 { doc, .. })
139                    | ScSpecEntry::UdtErrorEnumV0(ScSpecUdtErrorEnumV0 { doc, .. })
140                    | ScSpecEntry::EventV0(ScSpecEventV0 { doc, .. }) => doc,
141                };
142                spec_type_match.to_utf8_string_lossy()
143            }
144        };
145
146        if let Some(mut ex) = self.example(0, type_) {
147            if ex.contains(' ') {
148                ex = format!("'{ex}'");
149            } else if ex.contains('"') {
150                ex = ex.replace('"', "");
151            }
152            if matches!(type_, ScType::Bool) {
153                ex = String::new();
154            }
155            let sep = if str.is_empty() { "" } else { "\n" };
156            str = format!("{str}{sep}Example:\n  --{name} {ex}");
157            if ex.contains('"') {}
158        }
159        if str.is_empty() {
160            Ok(None)
161        } else {
162            Ok(Some(Box::leak(str.into_boxed_str())))
163        }
164    }
165
166    /// # Errors
167    ///
168    /// Might return errors
169    pub fn find(&self, name: &str) -> Result<&ScSpecEntry, Error> {
170        self.0
171            .as_ref()
172            .and_then(|specs| {
173                specs.iter().find(|e| {
174                    let entry_name = match e {
175                        ScSpecEntry::FunctionV0(x) => x.name.to_utf8_string_lossy(),
176                        ScSpecEntry::UdtStructV0(x) => x.name.to_utf8_string_lossy(),
177                        ScSpecEntry::UdtUnionV0(x) => x.name.to_utf8_string_lossy(),
178                        ScSpecEntry::UdtEnumV0(x) => x.name.to_utf8_string_lossy(),
179                        ScSpecEntry::UdtErrorEnumV0(x) => x.name.to_utf8_string_lossy(),
180                        ScSpecEntry::EventV0(x) => x.name.to_utf8_string_lossy(),
181                    };
182                    name == entry_name
183                })
184            })
185            .ok_or_else(|| Error::MissingEntry(name.to_owned()))
186    }
187
188    /// # Errors
189    ///
190    /// Might return errors
191    pub fn find_function(&self, name: &str) -> Result<&ScSpecFunctionV0, Error> {
192        match self.find(name)? {
193            ScSpecEntry::FunctionV0(f) => Ok(f),
194            _ => Err(Error::MissingEntry(name.to_owned())),
195        }
196    }
197    //
198    /// # Errors
199    ///
200    pub fn find_functions(&self) -> Result<impl Iterator<Item = &ScSpecFunctionV0>, Error> {
201        Ok(self
202            .0
203            .as_deref()
204            .ok_or(Error::MissingSpec)?
205            .iter()
206            .filter_map(|e| match e {
207                ScSpecEntry::FunctionV0(x) => Some(x),
208                _ => None,
209            }))
210    }
211
212    /// # Errors
213    ///
214    pub fn find_error_type(&self, value: u32) -> Result<&ScSpecUdtErrorEnumCaseV0, Error> {
215        if let ScSpecEntry::UdtErrorEnumV0(ScSpecUdtErrorEnumV0 { cases, .. }) =
216            self.find("Error")?
217        {
218            if let Some(case) = cases.iter().find(|case| value == case.value) {
219                return Ok(case);
220            }
221        }
222        Err(Error::MissingErrorCase(value))
223    }
224
225    /// # Errors
226    ///
227    /// Might return errors
228    pub fn from_string_primitive(s: &str, t: &ScType) -> Result<ScVal, Error> {
229        Self::default().from_string(s, t)
230    }
231
232    /// # Errors
233    ///
234    /// Might return errors
235    #[allow(clippy::wrong_self_convention)]
236    pub fn from_string(&self, s: &str, t: &ScType) -> Result<ScVal, Error> {
237        if let ScType::Option(b) = t {
238            if s == "null" {
239                return Ok(ScVal::Void);
240            }
241            let ScSpecTypeOption { value_type } = b.as_ref().clone();
242            let v = value_type.as_ref().clone();
243            return self.from_string(s, &v);
244        }
245        // Parse as string and for special types assume Value::String
246        serde_json::from_str(s)
247            .map_or_else(
248                |e| match t {
249                    ScType::Symbol
250                    | ScType::String
251                    | ScType::Bytes
252                    | ScType::BytesN(_)
253                    | ScType::U256
254                    | ScType::I256
255                    | ScType::U128
256                    | ScType::I128
257                    | ScType::Address
258                    | ScType::MuxedAddress => Ok(Value::String(s.to_owned())),
259                    ScType::Udt(ScSpecTypeUdt { name })
260                        if matches!(
261                            self.find(&name.to_utf8_string_lossy())?,
262                            ScSpecEntry::UdtUnionV0(_) | ScSpecEntry::UdtStructV0(_)
263                        ) =>
264                    {
265                        Ok(Value::String(s.to_owned()))
266                    }
267                    _ => Err(Error::Serde(e)),
268                },
269                |val| match t {
270                    ScType::U128 | ScType::I128 | ScType::U256 | ScType::I256 => {
271                        Ok(Value::String(s.to_owned()))
272                    }
273                    ScType::Timepoint | ScType::Duration => {
274                        // timepoint and duration both expect a JSON object with the value
275                        // being the u64 number as a string, and key being the type name
276                        let key = match t {
277                            ScType::Timepoint => "timepoint",
278                            ScType::Duration => "duration",
279                            _ => unreachable!(),
280                        };
281
282                        Ok(json!({ key: s }))
283                    }
284                    _ => Ok(val),
285                },
286            )
287            .and_then(|raw| self.from_json(&raw, t))
288    }
289
290    /// # Errors
291    ///
292    /// Might return errors
293    #[allow(clippy::wrong_self_convention)]
294    pub fn from_json(&self, v: &Value, t: &ScType) -> Result<ScVal, Error> {
295        let val: ScVal = match (t, v) {
296            (
297                ScType::Bool
298                | ScType::U128
299                | ScType::I128
300                | ScType::U256
301                | ScType::I256
302                | ScType::I32
303                | ScType::I64
304                | ScType::U32
305                | ScType::U64
306                | ScType::String
307                | ScType::Symbol
308                | ScType::Address
309                | ScType::MuxedAddress
310                | ScType::Bytes
311                | ScType::BytesN(_),
312                _,
313            ) => from_json_primitives(v, t)?,
314
315            // Vec parsing
316            (ScType::Vec(elem), Value::Array(raw)) => {
317                let converted: ScVec = raw
318                    .iter()
319                    .map(|item| self.from_json(item, &elem.element_type))
320                    .collect::<Result<Vec<ScVal>, Error>>()?
321                    .try_into()
322                    .map_err(Error::Xdr)?;
323                ScVal::Vec(Some(converted))
324            }
325
326            // Map parsing
327            (ScType::Map(map), Value::Object(raw)) => self.parse_map(map, raw)?,
328
329            // Option parsing
330            (ScType::Option(_), Value::Null) => ScVal::Void,
331            (ScType::Option(elem), v) => self.from_json(v, &elem.value_type)?,
332
333            // Tuple parsing
334            (ScType::Tuple(elem), Value::Array(raw)) => self.parse_tuple(t, elem, raw)?,
335
336            // User defined types parsing
337            (ScType::Udt(ScSpecTypeUdt { name }), _) => self.parse_udt(name, v)?,
338
339            // TODO: Implement the rest of these
340            (_, raw) => serde_json::from_value(raw.clone()).map_err(Error::Serde)?,
341        };
342        Ok(val)
343    }
344
345    fn parse_udt(&self, name: &StringM<60>, value: &Value) -> Result<ScVal, Error> {
346        let name = &name.to_utf8_string_lossy();
347        match (self.find(name)?, value) {
348            (ScSpecEntry::UdtStructV0(strukt), Value::Object(map)) => {
349                if strukt
350                    .fields
351                    .iter()
352                    .any(|f| f.name.to_utf8_string_lossy() == "0")
353                {
354                    self.parse_tuple_strukt(
355                        strukt,
356                        &(0..map.len())
357                            .map(|i| map.get(&i.to_string()).unwrap().clone())
358                            .collect::<Vec<_>>(),
359                    )
360                } else {
361                    self.parse_strukt(strukt, map)
362                }
363            }
364            (ScSpecEntry::UdtStructV0(strukt), Value::Array(arr)) => {
365                self.parse_tuple_strukt(strukt, arr)
366            }
367            (
368                ScSpecEntry::UdtUnionV0(union),
369                val @ (Value::Array(_) | Value::String(_) | Value::Object(_)),
370            ) => self.parse_union(union, val),
371            (ScSpecEntry::UdtEnumV0(enum_), Value::Number(num)) => parse_const_enum(num, enum_),
372            (s, v) => todo!("Not implemented for {s:#?} {v:#?}"),
373        }
374    }
375
376    fn parse_tuple_strukt(
377        &self,
378        strukt: &ScSpecUdtStructV0,
379        array: &[Value],
380    ) -> Result<ScVal, Error> {
381        let items = strukt
382            .fields
383            .to_vec()
384            .iter()
385            .zip(array.iter())
386            .map(|(f, v)| {
387                let val = self.from_json(v, &f.type_)?;
388                Ok(val)
389            })
390            .collect::<Result<Vec<_>, Error>>()?;
391        Ok(ScVal::Vec(Some(items.try_into().map_err(Error::Xdr)?)))
392    }
393
394    fn parse_strukt(
395        &self,
396        strukt: &ScSpecUdtStructV0,
397        map: &serde_json::Map<String, Value>,
398    ) -> Result<ScVal, Error> {
399        let items = strukt
400            .fields
401            .to_vec()
402            .iter()
403            .map(|f| {
404                let name = &f.name.to_utf8_string_lossy();
405                let v = map
406                    .get(name)
407                    .ok_or_else(|| Error::MissingKey(name.clone()))?;
408                let val = self.from_json(v, &f.type_)?;
409                let key = StringM::from_str(name).unwrap();
410                Ok(ScMapEntry {
411                    key: ScVal::Symbol(key.into()),
412                    val,
413                })
414            })
415            .collect::<Result<Vec<_>, Error>>()?;
416        let map = ScMap::sorted_from(items).map_err(Error::Xdr)?;
417        Ok(ScVal::Map(Some(map)))
418    }
419
420    fn parse_union(&self, union: &ScSpecUdtUnionV0, value: &Value) -> Result<ScVal, Error> {
421        let (enum_case, rest) = match value {
422            Value::String(s) => (s, None),
423            Value::Object(o) if o.len() == 1 => {
424                let res = o.values().next().map(|v| match v {
425                    Value::Object(obj) if obj.contains_key("0") => {
426                        let len = obj.len();
427                        Value::Array(
428                            (0..len)
429                                .map(|i| obj.get(&i.to_string()).unwrap().clone())
430                                .collect::<Vec<_>>(),
431                        )
432                    }
433                    _ => v.clone(),
434                });
435                (o.keys().next().unwrap(), res)
436            }
437            _ => todo!(),
438        };
439        let case = union
440            .cases
441            .iter()
442            .find(|c| {
443                let name = match c {
444                    ScSpecUdtUnionCaseV0::VoidV0(v) => &v.name,
445                    ScSpecUdtUnionCaseV0::TupleV0(v) => &v.name,
446                };
447                enum_case == &name.to_utf8_string_lossy()
448            })
449            .ok_or_else(|| Error::EnumCase(enum_case.clone(), union.name.to_utf8_string_lossy()))?;
450
451        let mut res = vec![ScVal::Symbol(ScSymbol(
452            enum_case.try_into().map_err(Error::Xdr)?,
453        ))];
454
455        match (case, rest) {
456            (ScSpecUdtUnionCaseV0::VoidV0(_), _) | (ScSpecUdtUnionCaseV0::TupleV0(_), None) => (),
457            (ScSpecUdtUnionCaseV0::TupleV0(ScSpecUdtUnionCaseTupleV0 { type_, .. }), Some(arr))
458                if type_.len() == 1 =>
459            {
460                res.push(self.from_json(&arr, &type_[0])?);
461            }
462            (
463                ScSpecUdtUnionCaseV0::TupleV0(ScSpecUdtUnionCaseTupleV0 { type_, .. }),
464                Some(Value::Array(arr)),
465            ) => {
466                res.extend(
467                    arr.iter()
468                        .zip(type_.iter())
469                        .map(|(elem, ty)| self.from_json(elem, ty))
470                        .collect::<Result<Vec<_>, _>>()?,
471                );
472            }
473            (ScSpecUdtUnionCaseV0::TupleV0(ScSpecUdtUnionCaseTupleV0 { .. }), Some(_)) => {}
474        }
475        Ok(ScVal::Vec(Some(res.try_into().map_err(Error::Xdr)?)))
476    }
477
478    fn parse_tuple(
479        &self,
480        t: &ScType,
481        tuple: &ScSpecTypeTuple,
482        items: &[Value],
483    ) -> Result<ScVal, Error> {
484        let ScSpecTypeTuple { value_types } = tuple;
485        if items.len() != value_types.len() {
486            return Err(Error::InvalidValue(Some(t.clone())));
487        }
488        let parsed: Result<Vec<ScVal>, Error> = items
489            .iter()
490            .zip(value_types.iter())
491            .map(|(item, t)| self.from_json(item, t))
492            .collect();
493        let converted: ScVec = parsed?.try_into().map_err(Error::Xdr)?;
494        Ok(ScVal::Vec(Some(converted)))
495    }
496
497    fn parse_map(
498        &self,
499        map: &ScSpecTypeMap,
500        value_map: &serde_json::Map<String, Value>,
501    ) -> Result<ScVal, Error> {
502        let ScSpecTypeMap {
503            key_type,
504            value_type,
505        } = map;
506        // TODO: What do we do if the expected key_type is not a string or symbol?
507        let parsed: Result<Vec<ScMapEntry>, Error> = value_map
508            .iter()
509            .map(|(k, v)| -> Result<ScMapEntry, Error> {
510                let key = self.from_string(k, key_type)?;
511                let val = self.from_json(v, value_type)?;
512                Ok(ScMapEntry { key, val })
513            })
514            .collect();
515        Ok(ScVal::Map(Some(
516            ScMap::sorted_from(parsed?).map_err(Error::Xdr)?,
517        )))
518    }
519}
520
521impl Spec {
522    /// # Errors
523    ///
524    /// Might return `Error::InvalidValue`
525    ///
526    /// # Panics
527    ///
528    /// May panic
529    pub fn xdr_to_json(&self, val: &ScVal, output: &ScType) -> Result<Value, Error> {
530        Ok(match (val, output) {
531            (ScVal::Void, ScType::Val | ScType::Option(_) | ScType::Tuple(_))
532            | (ScVal::Map(None) | ScVal::Vec(None), ScType::Option(_)) => Value::Null,
533            (ScVal::Bool(_), ScType::Bool)
534            | (ScVal::Void, ScType::Void)
535            | (ScVal::String(_), ScType::String)
536            | (ScVal::Symbol(_), ScType::Symbol)
537            | (ScVal::U64(_), ScType::U64)
538            | (ScVal::I64(_), ScType::I64)
539            | (ScVal::U32(_), ScType::U32)
540            | (ScVal::I32(_), ScType::I32)
541            | (ScVal::U128(_), ScType::U128)
542            | (ScVal::I128(_), ScType::I128)
543            | (ScVal::U256(_), ScType::U256)
544            | (ScVal::I256(_), ScType::I256)
545            | (ScVal::Duration(_), ScType::Duration)
546            | (ScVal::Timepoint(_), ScType::Timepoint)
547            | (
548                ScVal::ContractInstance(_)
549                | ScVal::LedgerKeyContractInstance
550                | ScVal::LedgerKeyNonce(_),
551                _,
552            )
553            | (ScVal::Address(_), ScType::Address | ScType::MuxedAddress)
554            | (ScVal::Bytes(_), ScType::Bytes | ScType::BytesN(_)) => to_json(val)?,
555
556            (val, ScType::Result(inner)) => self.xdr_to_json(val, &inner.ok_type)?,
557
558            (val, ScType::Option(inner)) => self.xdr_to_json(val, &inner.value_type)?,
559            (ScVal::Map(Some(_)) | ScVal::Vec(Some(_)) | ScVal::U32(_), type_) => {
560                self.sc_object_to_json(val, type_)?
561            }
562
563            (ScVal::Error(_), ScType::Error) => todo!(),
564            (v, typed) => todo!("{v:#?} doesn't have a matching {typed:#?}"),
565        })
566    }
567
568    /// # Errors
569    ///
570    /// Might return an error
571    pub fn vec_m_to_json<const MAX: u32>(
572        &self,
573        vec_m: &VecM<ScVal, MAX>,
574        type_: &ScType,
575    ) -> Result<Value, Error> {
576        Ok(Value::Array(
577            vec_m
578                .to_vec()
579                .iter()
580                .map(|sc_val| self.xdr_to_json(sc_val, type_))
581                .collect::<Result<Vec<_>, Error>>()?,
582        ))
583    }
584
585    /// # Errors
586    ///
587    /// Might return an error
588    pub fn sc_map_to_json(&self, sc_map: &ScMap, type_: &ScSpecTypeMap) -> Result<Value, Error> {
589        let v = sc_map
590            .iter()
591            .map(|ScMapEntry { key, val }| {
592                let key_s = self.xdr_to_json(key, &type_.key_type)?.to_string();
593                let val_value = self.xdr_to_json(val, &type_.value_type)?;
594                Ok((key_s, val_value))
595            })
596            .collect::<Result<serde_json::Map<String, Value>, Error>>()?;
597        Ok(Value::Object(v))
598    }
599
600    /// # Errors
601    ///
602    /// Might return an error
603    ///
604    /// # Panics
605    ///
606    /// May panic
607    pub fn udt_to_json(&self, name: &StringM<60>, sc_obj: &ScVal) -> Result<Value, Error> {
608        let name = &name.to_utf8_string_lossy();
609        let udt = self.find(name)?;
610        Ok(match (sc_obj, udt) {
611            (ScVal::Map(Some(map)), ScSpecEntry::UdtStructV0(strukt)) => serde_json::Value::Object(
612                strukt
613                    .fields
614                    .iter()
615                    .zip(map.iter())
616                    .map(|(field, entry)| {
617                        let val = self.xdr_to_json(&entry.val, &field.type_)?;
618                        Ok((field.name.to_utf8_string_lossy(), val))
619                    })
620                    .collect::<Result<serde_json::Map<String, _>, Error>>()?,
621            ),
622            (ScVal::Vec(Some(vec_)), ScSpecEntry::UdtStructV0(strukt)) => Value::Array(
623                strukt
624                    .fields
625                    .iter()
626                    .zip(vec_.iter())
627                    .map(|(field, entry)| self.xdr_to_json(entry, &field.type_))
628                    .collect::<Result<Vec<_>, Error>>()?,
629            ),
630            (ScVal::Vec(Some(vec_)), ScSpecEntry::UdtUnionV0(union)) => {
631                let v = vec_.to_vec();
632                // let val = &v[0];
633                let (first, rest) = match v.split_at(1) {
634                    ([first], []) => (first, None),
635                    ([first], rest) => (first, Some(rest)),
636                    _ => return Err(Error::IllFormedEnum(union.name.to_utf8_string_lossy())),
637                };
638
639                let ScVal::Symbol(case_name) = first else {
640                    return Err(Error::EnumFirstValueNotSymbol);
641                };
642                let case = union
643                    .cases
644                    .iter()
645                    .find(|case| {
646                        let name = match case {
647                            ScSpecUdtUnionCaseV0::VoidV0(v) => &v.name,
648                            ScSpecUdtUnionCaseV0::TupleV0(v) => &v.name,
649                        };
650                        name.as_vec() == case_name.as_vec()
651                    })
652                    .ok_or_else(|| Error::FailedToFindEnumCase(case_name.to_utf8_string_lossy()))?;
653
654                let case_name = case_name.to_utf8_string_lossy();
655                match case {
656                    ScSpecUdtUnionCaseV0::TupleV0(v) => {
657                        let rest = rest.ok_or_else(|| {
658                            Error::EnumMissingSecondValue(
659                                union.name.to_utf8_string_lossy(),
660                                case_name.clone(),
661                            )
662                        })?;
663                        let val = if v.type_.len() == 1 {
664                            self.xdr_to_json(&rest[0], &v.type_[0])?
665                        } else {
666                            Value::Array(
667                                v.type_
668                                    .iter()
669                                    .zip(rest.iter())
670                                    .map(|(type_, val)| self.xdr_to_json(val, type_))
671                                    .collect::<Result<Vec<_>, Error>>()?,
672                            )
673                        };
674
675                        Value::Object([(case_name, val)].into_iter().collect())
676                    }
677                    ScSpecUdtUnionCaseV0::VoidV0(_) => Value::String(case_name),
678                }
679            }
680            (ScVal::U32(v), ScSpecEntry::UdtEnumV0(_enum_)) => {
681                Value::Number(serde_json::Number::from(*v))
682            }
683            (s, v) => todo!("Not implemented for {s:#?} {v:#?}"),
684        })
685    }
686
687    /// # Errors
688    ///
689    /// Might return an error
690    ///
691    /// # Panics
692    ///
693    /// Some types are not yet supported and will cause a panic if supplied
694    pub fn sc_object_to_json(&self, val: &ScVal, spec_type: &ScType) -> Result<Value, Error> {
695        Ok(match (val, spec_type) {
696            (ScVal::Vec(Some(ScVec(vec_m))), ScType::Vec(type_)) => {
697                self.vec_m_to_json(vec_m, &type_.element_type)?
698            }
699            (ScVal::Vec(Some(ScVec(vec_m))), ScType::Tuple(tuple_type)) => Value::Array(
700                vec_m
701                    .iter()
702                    .zip(tuple_type.value_types.iter())
703                    .map(|(v, t)| self.xdr_to_json(v, t))
704                    .collect::<Result<Vec<_>, _>>()?,
705            ),
706            (
707                sc_obj @ (ScVal::Vec(_) | ScVal::Map(_) | ScVal::U32(_)),
708                ScType::Udt(ScSpecTypeUdt { name }),
709            ) => self.udt_to_json(name, sc_obj)?,
710
711            (ScVal::Map(Some(map)), ScType::Map(map_type)) => self.sc_map_to_json(map, map_type)?,
712
713            (ScVal::U64(u64_), ScType::U64) => Value::Number(serde_json::Number::from(*u64_)),
714
715            (ScVal::I64(i64_), ScType::I64) => Value::Number(serde_json::Number::from(*i64_)),
716            (int @ ScVal::U128(_), ScType::U128) => {
717                // Always output u128s as strings
718                let v: u128 = int
719                    .clone()
720                    .try_into()
721                    .map_err(|()| Error::InvalidValue(Some(ScType::U128)))?;
722                Value::String(v.to_string())
723            }
724
725            (int @ ScVal::I128(_), ScType::I128) => {
726                // Always output u128s as strings
727                let v: i128 = int
728                    .clone()
729                    .try_into()
730                    .map_err(|()| Error::InvalidValue(Some(ScType::I128)))?;
731                Value::String(v.to_string())
732            }
733
734            (ScVal::Bytes(v), ScType::Bytes | ScType::BytesN(_)) => {
735                Value::String(to_lower_hex(v.as_slice()))
736            }
737
738            (ScVal::Bytes(_), ScType::Udt(_)) => todo!(),
739
740            (ScVal::ContractInstance(_), _) => todo!(),
741
742            (ScVal::Address(v), ScType::Address | ScType::MuxedAddress) => sc_address_to_json(v),
743
744            (ok_val, ScType::Result(result_type)) => {
745                let ScSpecTypeResult { ok_type, .. } = result_type.as_ref();
746                self.xdr_to_json(ok_val, ok_type)?
747            }
748
749            (x, y) => return Err(Error::InvalidPair(x.clone(), y.clone())),
750        })
751    }
752}
753
754/// # Errors
755///
756/// Might return an error
757pub fn from_string_primitive(s: &str, t: &ScType) -> Result<ScVal, Error> {
758    Spec::from_string_primitive(s, t)
759}
760
761fn parse_const_enum(num: &serde_json::Number, enum_: &ScSpecUdtEnumV0) -> Result<ScVal, Error> {
762    let num = num
763        .as_u64()
764        .ok_or_else(|| Error::FailedNumConversion(num.clone()))?;
765    let num = u32::try_from(num).map_err(|_| Error::EnumConstTooLarge(num))?;
766    enum_
767        .cases
768        .iter()
769        .find(|c| c.value == num)
770        .ok_or(Error::EnumConst(num))
771        .map(|c| ScVal::U32(c.value))
772}
773
774/// # Errors
775///
776/// Might return an error
777#[allow(clippy::too_many_lines)]
778pub fn from_json_primitives(v: &Value, t: &ScType) -> Result<ScVal, Error> {
779    let val: ScVal = match (t, v) {
780        // Boolean parsing
781        (ScType::Bool, Value::Bool(true)) => ScVal::Bool(true),
782        (ScType::Bool, Value::Bool(false)) => ScVal::Bool(false),
783
784        // Number parsing
785        (ScType::U128, Value::String(s)) => {
786            let val: u128 = u128::from_str(s).map_err(|_| Error::InvalidValue(Some(t.clone())))?;
787            let bytes = val.to_be_bytes();
788            let (hi, lo) = bytes.split_at(8);
789            ScVal::U128(UInt128Parts {
790                hi: u64::from_be_bytes(hi.try_into()?),
791                lo: u64::from_be_bytes(lo.try_into()?),
792            })
793        }
794
795        (ScType::I128, Value::String(s)) => {
796            let val: i128 = i128::from_str(s).map_err(|_| Error::InvalidValue(Some(t.clone())))?;
797            let bytes = val.to_be_bytes();
798            let (hi, lo) = bytes.split_at(8);
799            ScVal::I128(Int128Parts {
800                hi: i64::from_be_bytes(hi.try_into()?),
801                lo: u64::from_be_bytes(lo.try_into()?),
802            })
803        }
804
805        // Number parsing
806        (ScType::U256, Value::String(s)) => {
807            let (hi, lo) = ethnum::U256::from_str_prefixed(s)?.into_words();
808            let hi_bytes = hi.to_be_bytes();
809            let (hi_hi, hi_lo) = hi_bytes.split_at(8);
810            let lo_bytes = lo.to_be_bytes();
811            let (lo_hi, lo_lo) = lo_bytes.split_at(8);
812            ScVal::U256(UInt256Parts {
813                hi_hi: u64::from_be_bytes(hi_hi.try_into()?),
814                hi_lo: u64::from_be_bytes(hi_lo.try_into()?),
815                lo_hi: u64::from_be_bytes(lo_hi.try_into()?),
816                lo_lo: u64::from_be_bytes(lo_lo.try_into()?),
817            })
818        }
819        (ScType::I256, Value::String(s)) => {
820            let (hi, lo) = ethnum::I256::from_str_prefixed(s)?.into_words();
821            let hi_bytes = hi.to_be_bytes();
822            let (hi_hi, hi_lo) = hi_bytes.split_at(8);
823            let lo_bytes = lo.to_be_bytes();
824            let (lo_hi, lo_lo) = lo_bytes.split_at(8);
825            ScVal::I256(Int256Parts {
826                hi_hi: i64::from_be_bytes(hi_hi.try_into()?),
827                hi_lo: u64::from_be_bytes(hi_lo.try_into()?),
828                lo_hi: u64::from_be_bytes(lo_hi.try_into()?),
829                lo_lo: u64::from_be_bytes(lo_lo.try_into()?),
830            })
831        }
832
833        (ScType::I32, Value::Number(n)) => ScVal::I32(
834            n.as_i64()
835                .ok_or_else(|| Error::InvalidValue(Some(t.clone())))?
836                .try_into()
837                .map_err(|_| Error::InvalidValue(Some(t.clone())))?,
838        ),
839        (ScType::U32, Value::Number(n)) => ScVal::U32(
840            n.as_u64()
841                .ok_or_else(|| Error::InvalidValue(Some(t.clone())))?
842                .try_into()
843                .map_err(|_| Error::InvalidValue(Some(t.clone())))?,
844        ),
845        (ScType::I64, Value::Number(n)) => ScVal::I64(
846            n.as_i64()
847                .ok_or_else(|| Error::InvalidValue(Some(t.clone())))?,
848        ),
849        (ScType::U64 | ScType::Timepoint | ScType::Duration, Value::Number(n)) => ScVal::U64(
850            n.as_u64()
851                .ok_or_else(|| Error::InvalidValue(Some(t.clone())))?,
852        ),
853
854        // Symbol parsing
855        (ScType::Symbol, Value::String(s)) => ScVal::Symbol(ScSymbol(
856            s.as_bytes()
857                .try_into()
858                .map_err(|_| Error::InvalidValue(Some(t.clone())))?,
859        )),
860
861        (ScType::Address | ScType::MuxedAddress, Value::String(s)) => sc_address_from_json(s)?,
862
863        // Bytes parsing
864        (bytes @ ScType::BytesN(_), Value::Number(n)) => {
865            from_json_primitives(&Value::String(format!("{n}")), bytes)?
866        }
867        (ScType::BytesN(bytes), Value::String(s)) => ScVal::Bytes(ScBytes({
868            if bytes.n == 32 {
869                // Bytes might be a strkey, try parsing it as one. Contract devs should use the new
870                // proper Address type, but for backwards compatibility some contracts might use a
871                // BytesN<32> to represent an Address.
872                if let Ok(key) = sc_address_from_json(s) {
873                    return Ok(key);
874                }
875            }
876            // Bytes are not an address, just parse as a hex string
877            utils::padded_hex_from_str(s, bytes.n as usize)
878                .map_err(|_| Error::InvalidValue(Some(t.clone())))?
879                .try_into()
880                .map_err(|_| Error::InvalidValue(Some(t.clone())))?
881        })),
882        (ScType::Bytes, Value::Number(n)) => {
883            from_json_primitives(&Value::String(format!("{n}")), &ScType::Bytes)?
884        }
885        (ScType::Bytes, Value::String(s)) => ScVal::Bytes(
886            hex::decode(s)
887                .map_err(|_| Error::InvalidValue(Some(t.clone())))?
888                .try_into()
889                .map_err(|_| Error::InvalidValue(Some(t.clone())))?,
890        ),
891        (ScType::Bytes | ScType::BytesN(_), Value::Array(raw)) => {
892            let b: Result<Vec<u8>, Error> = raw
893                .iter()
894                .map(|item| {
895                    item.as_u64()
896                        .ok_or_else(|| Error::InvalidValue(Some(t.clone())))?
897                        .try_into()
898                        .map_err(|_| Error::InvalidValue(Some(t.clone())))
899                })
900                .collect();
901            let converted: BytesM<{ u32::MAX }> = b?.try_into().map_err(Error::Xdr)?;
902            ScVal::Bytes(ScBytes(converted))
903        }
904
905        (ScType::String, Value::String(s)) => ScVal::String(ScString(
906            s.try_into()
907                .map_err(|_| Error::InvalidValue(Some(t.clone())))?,
908        )),
909        // Todo make proper error Which shouldn't exist
910        (_, raw) => serde_json::from_value(raw.clone())?,
911    };
912    Ok(val)
913}
914
915/// # Errors
916///
917/// Might return an error
918pub fn to_string(v: &ScVal) -> Result<String, Error> {
919    #[allow(clippy::match_same_arms)]
920    Ok(match v {
921        // If symbols are a top-level thing we omit the wrapping quotes
922        // TODO: Decide if this is a good idea or not.
923        ScVal::Symbol(v) => std::str::from_utf8(v.as_slice())
924            .map_err(|_| Error::InvalidValue(Some(ScType::Symbol)))?
925            .to_string(),
926        ScVal::LedgerKeyContractInstance => "LedgerKeyContractInstance".to_string(),
927        _ => serde_json::to_string(&to_json(v)?)?,
928    })
929}
930
931/// # Errors
932///
933/// Might return an error
934#[allow(clippy::too_many_lines)]
935pub fn to_json(v: &ScVal) -> Result<Value, Error> {
936    #[allow(clippy::match_same_arms)]
937    let val: Value = match v {
938        ScVal::Bool(b) => Value::Bool(*b),
939        ScVal::Void => Value::Null,
940        ScVal::LedgerKeyContractInstance => Value::String("LedgerKeyContractInstance".to_string()),
941        ScVal::U64(v) => Value::Number(serde_json::Number::from(*v)),
942        ScVal::Timepoint(tp) => Value::Number(serde_json::Number::from(tp.0)),
943        ScVal::Duration(d) => Value::Number(serde_json::Number::from(d.0)),
944        ScVal::I64(v) => Value::Number(serde_json::Number::from(*v)),
945        ScVal::U32(v) => Value::Number(serde_json::Number::from(*v)),
946        ScVal::I32(v) => Value::Number(serde_json::Number::from(*v)),
947        ScVal::Symbol(v) => Value::String(
948            std::str::from_utf8(v.as_slice())
949                .map_err(|_| Error::InvalidValue(Some(ScType::Symbol)))?
950                .to_string(),
951        ),
952        ScVal::String(v) => Value::String(
953            std::str::from_utf8(v.as_slice())
954                .map_err(|_| Error::InvalidValue(Some(ScType::Symbol)))?
955                .to_string(),
956        ),
957        ScVal::Vec(v) => {
958            let values: Result<Vec<Value>, Error> = v.as_ref().map_or_else(
959                || Ok(vec![]),
960                |v| {
961                    v.iter()
962                        .map(|item| -> Result<Value, Error> { to_json(item) })
963                        .collect()
964                },
965            );
966            Value::Array(values?)
967        }
968        ScVal::Map(None) => Value::Object(serde_json::Map::with_capacity(0)),
969        ScVal::Map(Some(v)) => {
970            // TODO: What do we do if the key is not a string?
971            let mut m = serde_json::Map::<String, Value>::with_capacity(v.len());
972            for ScMapEntry { key, val } in v.iter() {
973                let k: String = to_string(key)?;
974                let v: Value = to_json(val).map_err(|_| Error::InvalidValue(None))?;
975                m.insert(k, v);
976            }
977            Value::Object(m)
978        }
979        ScVal::Bytes(v) => Value::String(to_lower_hex(v.as_slice())),
980        ScVal::Address(v) => sc_address_to_json(v),
981        ScVal::U128(n) => {
982            let hi: [u8; 8] = n.hi.to_be_bytes();
983            let lo: [u8; 8] = n.lo.to_be_bytes();
984            let bytes = [hi, lo].concat();
985            // Always output u128s as strings
986            let v = u128::from_be_bytes(
987                bytes
988                    .as_slice()
989                    .try_into()
990                    .map_err(|_| Error::InvalidValue(Some(ScType::I128)))?,
991            )
992            .to_string();
993            Value::String(v)
994        }
995        ScVal::I128(n) => {
996            let hi: [u8; 8] = n.hi.to_be_bytes();
997            let lo: [u8; 8] = n.lo.to_be_bytes();
998            let bytes = [hi, lo].concat();
999            // Always output u128s as strings
1000            let v = i128::from_be_bytes(
1001                bytes
1002                    .as_slice()
1003                    .try_into()
1004                    .map_err(|_| Error::InvalidValue(Some(ScType::I128)))?,
1005            )
1006            .to_string();
1007            Value::String(v)
1008        }
1009        ScVal::U256(u256parts) => {
1010            let bytes = [
1011                u256parts.hi_hi.to_be_bytes(),
1012                u256parts.hi_lo.to_be_bytes(),
1013                u256parts.lo_hi.to_be_bytes(),
1014                u256parts.lo_lo.to_be_bytes(),
1015            ]
1016            .concat();
1017            let u256 = ethnum::U256::from_be_bytes(
1018                bytes
1019                    .as_slice()
1020                    .try_into()
1021                    .map_err(|_| Error::InvalidValue(Some(ScType::U256)))?,
1022            );
1023            Value::String(u256.to_string())
1024        }
1025        ScVal::I256(i256parts) => {
1026            let bytes = [
1027                i256parts.hi_hi.to_be_bytes(),
1028                i256parts.hi_lo.to_be_bytes(),
1029                i256parts.lo_hi.to_be_bytes(),
1030                i256parts.lo_lo.to_be_bytes(),
1031            ]
1032            .concat();
1033            let i256 = ethnum::I256::from_be_bytes(
1034                bytes
1035                    .as_slice()
1036                    .try_into()
1037                    .map_err(|_| Error::InvalidValue(Some(ScType::I256)))?,
1038            );
1039            Value::String(i256.to_string())
1040        }
1041        ScVal::ContractInstance(ScContractInstance {
1042            executable: ContractExecutable::Wasm(hash),
1043            ..
1044        }) => json!({ "hash": hash }),
1045        ScVal::ContractInstance(ScContractInstance {
1046            executable: ContractExecutable::StellarAsset,
1047            ..
1048        }) => json!({"SAC": true}),
1049        ScVal::LedgerKeyNonce(ScNonceKey { nonce }) => {
1050            Value::Number(serde_json::Number::from(*nonce))
1051        }
1052        ScVal::Error(e) => serde_json::to_value(e)?,
1053    };
1054    Ok(val)
1055}
1056
1057fn sc_address_to_json(v: &ScAddress) -> Value {
1058    match v {
1059        ScAddress::Account(AccountId(PublicKey::PublicKeyTypeEd25519(Uint256(k)))) => {
1060            Value::String(stellar_strkey::ed25519::PublicKey(*k).to_string())
1061        }
1062        ScAddress::Contract(ContractId(h)) => {
1063            Value::String(stellar_strkey::Contract(h.clone().into()).to_string())
1064        }
1065        ScAddress::MuxedAccount(MuxedEd25519Account { ed25519, id }) => Value::String(
1066            stellar_strkey::ed25519::MuxedAccount {
1067                ed25519: ed25519.0,
1068                id: *id,
1069            }
1070            .to_string(),
1071        ),
1072        ScAddress::ClaimableBalance(_) => todo!("ClaimableBalance is not supported"),
1073        ScAddress::LiquidityPool(_) => todo!("LiquidityPool is not supported"),
1074    }
1075}
1076
1077fn sc_address_from_json(s: &str) -> Result<ScVal, Error> {
1078    stellar_strkey::Strkey::from_string(s)
1079        .map_err(|_| Error::InvalidValue(Some(ScType::Address)))
1080        .map(|parsed| match parsed {
1081            stellar_strkey::Strkey::PublicKeyEd25519(p) => Some(ScVal::Address(
1082                ScAddress::Account(AccountId(PublicKey::PublicKeyTypeEd25519(Uint256(p.0)))),
1083            )),
1084            stellar_strkey::Strkey::Contract(c) => {
1085                Some(ScVal::Address(ScAddress::Contract(ContractId(Hash(c.0)))))
1086            }
1087            stellar_strkey::Strkey::MuxedAccountEd25519(m) => Some(ScVal::Address(
1088                ScAddress::MuxedAccount(MuxedEd25519Account {
1089                    ed25519: Uint256(m.ed25519),
1090                    id: m.id,
1091                }),
1092            )),
1093            _ => None,
1094        })?
1095        .ok_or(Error::InvalidValue(Some(ScType::Address)))
1096}
1097
1098fn to_lower_hex(bytes: &[u8]) -> String {
1099    let mut res = String::with_capacity(bytes.len());
1100    for b in bytes {
1101        let _ = write!(res, "{b:02x}");
1102    }
1103    res
1104}
1105
1106impl Spec {
1107    #[must_use]
1108    pub fn arg_value_name(&self, type_: &ScType, depth: usize) -> Option<String> {
1109        match type_ {
1110            ScType::U64 => Some("u64".to_string()),
1111            ScType::I64 => Some("i64".to_string()),
1112            ScType::U128 => Some("u128".to_string()),
1113            ScType::I128 => Some("i128".to_string()),
1114            ScType::U32 => Some("u32".to_string()),
1115            ScType::I32 => Some("i32".to_string()),
1116            ScType::Bool => Some("bool".to_string()),
1117            ScType::Symbol => Some("Symbol".to_string()),
1118            ScType::Error => Some("Error".to_string()),
1119            ScType::Bytes => Some("hex_bytes".to_string()),
1120            ScType::Address => Some("Address".to_string()),
1121            ScType::Void => Some("Null".to_string()),
1122            ScType::Timepoint => Some("Timepoint".to_string()),
1123            ScType::Duration => Some("Duration".to_string()),
1124            ScType::U256 => Some("u256".to_string()),
1125            ScType::I256 => Some("i256".to_string()),
1126            ScType::String => Some("String".to_string()),
1127            ScType::MuxedAddress => Some("MuxedAddress".to_string()),
1128            ScType::Option(val) => {
1129                let ScSpecTypeOption { value_type } = val.as_ref();
1130                let inner = self.arg_value_name(value_type.as_ref(), depth + 1)?;
1131                Some(format!("Option<{inner}>"))
1132            }
1133            ScType::Vec(val) => {
1134                let ScSpecTypeVec { element_type } = val.as_ref();
1135                let inner = self.arg_value_name(element_type.as_ref(), depth + 1)?;
1136                Some(format!("Array<{inner}>"))
1137            }
1138            ScType::Result(val) => {
1139                let ScSpecTypeResult {
1140                    ok_type,
1141                    error_type,
1142                } = val.as_ref();
1143                let ok = self.arg_value_name(ok_type.as_ref(), depth + 1)?;
1144                let error = self.arg_value_name(error_type.as_ref(), depth + 1)?;
1145                Some(format!("Result<{ok}, {error}>"))
1146            }
1147            ScType::Tuple(val) => {
1148                let ScSpecTypeTuple { value_types } = val.as_ref();
1149                let names = value_types
1150                    .iter()
1151                    .map(|t| self.arg_value_name(t, depth + 1))
1152                    .collect::<Option<Vec<_>>>()?
1153                    .join(", ");
1154                Some(format!("Tuple<{names}>"))
1155            }
1156            ScType::Map(val) => {
1157                let ScSpecTypeMap {
1158                    key_type,
1159                    value_type,
1160                } = val.as_ref();
1161                let (key, val) = (
1162                    self.arg_value_name(key_type.as_ref(), depth + 1)?,
1163                    self.arg_value_name(value_type.as_ref(), depth + 1)?,
1164                );
1165                Some(format!("Map<{key}, {val}>"))
1166            }
1167            ScType::BytesN(t) => Some(format!("{}_hex_bytes", t.n)),
1168            ScType::Udt(ScSpecTypeUdt { name }) => {
1169                match self.find(&name.to_utf8_string_lossy()).ok()? {
1170                    ScSpecEntry::UdtStructV0(ScSpecUdtStructV0 { fields, .. })
1171                        if fields
1172                            .first()
1173                            .is_some_and(|f| f.name.to_utf8_string_lossy() == "0") =>
1174                    {
1175                        let fields = fields
1176                            .iter()
1177                            .map(|t| self.arg_value_name(&t.type_, depth + 1))
1178                            .collect::<Option<Vec<_>>>()?
1179                            .join(", ");
1180                        Some(format!("[{fields}]"))
1181                    }
1182                    ScSpecEntry::UdtStructV0(strukt) => self.arg_value_udt(strukt, depth),
1183                    ScSpecEntry::UdtUnionV0(union) => self.arg_value_union(union, depth),
1184                    ScSpecEntry::UdtEnumV0(enum_) => Some(arg_value_enum(enum_)),
1185                    ScSpecEntry::FunctionV0(_)
1186                    | ScSpecEntry::UdtErrorEnumV0(_)
1187                    | ScSpecEntry::EventV0(_) => None,
1188                }
1189            }
1190            // No specific value name for these yet.
1191            ScType::Val => None,
1192        }
1193    }
1194
1195    fn arg_value_udt(&self, strukt: &ScSpecUdtStructV0, depth: usize) -> Option<String> {
1196        let inner = strukt
1197            .fields
1198            .iter()
1199            .map(|f| (f.name.to_utf8_string_lossy(), &f.type_))
1200            .map(|(name, type_)| {
1201                let type_ = self.arg_value_name(type_, depth + 1)?;
1202                Some(format!("{name}: {type_}"))
1203            })
1204            .collect::<Option<Vec<_>>>()?
1205            .join(", ");
1206        Some(format!("{{ {inner} }}"))
1207    }
1208
1209    fn arg_value_union(&self, union: &ScSpecUdtUnionV0, depth: usize) -> Option<String> {
1210        union
1211            .cases
1212            .iter()
1213            .map(|f| {
1214                Some(match f {
1215                    ScSpecUdtUnionCaseV0::VoidV0(ScSpecUdtUnionCaseVoidV0 { name, .. }) => {
1216                        name.to_utf8_string_lossy()
1217                    }
1218                    ScSpecUdtUnionCaseV0::TupleV0(ScSpecUdtUnionCaseTupleV0 {
1219                        name,
1220                        type_,
1221                        ..
1222                    }) => {
1223                        if depth > 1 {
1224                            match &type_[0] {
1225                                ScType::Vec(type_vec) => {
1226                                    let element_type = type_vec.element_type.clone();
1227                                    if let ScType::Udt(udt_type) = *element_type {
1228                                        return Some(udt_type.name.to_utf8_string_lossy());
1229                                    }
1230                                }
1231                                _ => {
1232                                    return Some(format!(
1233                                        "{}(ScSpecTypeDef::{})",
1234                                        name.to_utf8_string_lossy(),
1235                                        type_[0].name()
1236                                    ))
1237                                }
1238                            }
1239                            format!("{}({})", name.to_utf8_string_lossy(), type_[0].name())
1240                        } else {
1241                            format!(
1242                                "{}({})",
1243                                name.to_utf8_string_lossy(),
1244                                type_
1245                                    .iter()
1246                                    .map(|type_| self.arg_value_name(type_, depth + 1))
1247                                    .collect::<Option<Vec<String>>>()?
1248                                    .join(",")
1249                            )
1250                        }
1251                    }
1252                })
1253            })
1254            .collect::<Option<Vec<_>>>()
1255            .map(|v| v.join(" | "))
1256    }
1257}
1258
1259fn arg_value_enum(enum_: &ScSpecUdtEnumV0) -> String {
1260    enum_
1261        .cases
1262        .iter()
1263        .map(|case| case.value.to_string())
1264        .join(" | ")
1265}
1266
1267// Example implementation
1268impl Spec {
1269    #[must_use]
1270    pub fn example(&self, depth: usize, type_: &ScType) -> Option<String> {
1271        #[allow(clippy::match_same_arms)]
1272        match type_ {
1273            ScType::U64 => Some("1".to_string()),
1274            ScType::I64 => Some("1".to_string()),
1275            ScType::U128 => Some("\"1\"".to_string()),
1276            ScType::I128 => Some("\"1\"".to_string()),
1277            ScType::U32 => Some("1".to_string()),
1278            ScType::I32 => Some("1".to_string()),
1279            ScType::Bool => Some("true".to_string()),
1280            ScType::Symbol => Some("\"hello\"".to_string()),
1281            ScType::Error => Some("Error".to_string()),
1282            ScType::Bytes => Some("\"0000000000000000\"".to_string()),
1283            ScType::Address => {
1284                Some("\"GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF\"".to_string())
1285            }
1286            ScType::Void => Some("null".to_string()),
1287            ScType::Timepoint => Some("1743010492".to_string()),
1288            ScType::Duration => Some("1".to_string()),
1289            ScType::U256 => Some("\"1\"".to_string()),
1290            ScType::I256 => Some("\"1\"".to_string()),
1291            ScType::String => Some("\"hello world\"".to_string()),
1292            ScType::Option(val) => {
1293                let ScSpecTypeOption { value_type } = val.as_ref();
1294                self.example(depth, value_type.as_ref())
1295            }
1296            ScType::Vec(val) => {
1297                let ScSpecTypeVec { element_type } = val.as_ref();
1298                let inner = self.example(depth, element_type.as_ref())?;
1299                Some(format!("[ {inner} ]"))
1300            }
1301            ScType::Result(val) => {
1302                let ScSpecTypeResult {
1303                    ok_type,
1304                    error_type,
1305                } = val.as_ref();
1306                let ok = self.example(depth, ok_type.as_ref())?;
1307                let error = self.example(depth, error_type.as_ref())?;
1308                Some(format!("Result<{ok}, {error}>"))
1309            }
1310            ScType::Tuple(val) => {
1311                let ScSpecTypeTuple { value_types } = val.as_ref();
1312                let names = value_types
1313                    .iter()
1314                    .map(|t| self.example(depth, t))
1315                    .collect::<Option<Vec<_>>>()?
1316                    .join(", ");
1317                Some(format!("[{names}]"))
1318            }
1319            ScType::Map(map) => {
1320                let ScSpecTypeMap {
1321                    key_type,
1322                    value_type,
1323                } = map.as_ref();
1324                let (mut key, val) = (
1325                    self.example(depth, key_type.as_ref())?,
1326                    self.example(depth, value_type.as_ref())?,
1327                );
1328                if !matches!(key_type.as_ref(), ScType::Symbol) {
1329                    key = format!("\"{key}\"");
1330                }
1331                Some(format!("{{ {key}: {val} }}"))
1332            }
1333            ScType::BytesN(n) => {
1334                let n = n.n as usize;
1335                let res = "00".repeat(n);
1336                Some(format!("\"{res}\""))
1337            }
1338            ScType::Udt(ScSpecTypeUdt { name }) => {
1339                self.example_udts(depth, name.to_utf8_string_lossy().as_ref())
1340            }
1341            ScType::MuxedAddress => {
1342                Some("\"GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF\"".to_string())
1343            }
1344            // No specific value name for these yet.
1345            ScType::Val => None,
1346        }
1347    }
1348
1349    fn example_udts(&self, depth: usize, name: &str) -> Option<String> {
1350        if depth > 2 {
1351            return Some(name.to_string());
1352        }
1353
1354        let depth = depth + 1;
1355        let built = match self.find(name).ok() {
1356            Some(ScSpecEntry::UdtStructV0(strukt)) => {
1357                // Check if a tuple strukt and handle it just as a tuple going forward
1358                let build_struct = if !strukt.fields.is_empty()
1359                    && strukt.fields[0].name.to_utf8_string_lossy() == "0"
1360                {
1361                    let value_types = strukt
1362                        .fields
1363                        .iter()
1364                        .map(|f| f.type_.clone())
1365                        .collect::<Vec<_>>()
1366                        .try_into()
1367                        .ok()?;
1368                    self.example(
1369                        depth,
1370                        &ScType::Tuple(Box::new(ScSpecTypeTuple { value_types })),
1371                    )
1372                } else {
1373                    let inner = strukt
1374                        .fields
1375                        .iter()
1376                        .map(|f| (f.name.to_utf8_string_lossy(), &f.type_))
1377                        .map(|(name, type_)| {
1378                            let type_ = self.example(depth, type_)?;
1379                            let name = format!(r#""{name}""#);
1380                            Some(format!("{name}: {type_}"))
1381                        })
1382                        .collect::<Option<Vec<_>>>()?
1383                        .join(", ");
1384                    Some(format!(r"{{ {inner} }}"))
1385                };
1386                build_struct
1387            }
1388            Some(ScSpecEntry::UdtUnionV0(union)) => self.example_union(depth, union),
1389            Some(ScSpecEntry::UdtEnumV0(enum_)) => {
1390                enum_.cases.iter().next().map(|c| c.value.to_string())
1391            }
1392            Some(
1393                ScSpecEntry::FunctionV0(_)
1394                | ScSpecEntry::UdtErrorEnumV0(_)
1395                | ScSpecEntry::EventV0(_),
1396            )
1397            | None => None,
1398        };
1399
1400        built
1401    }
1402
1403    fn example_union(&self, depth: usize, union: &ScSpecUdtUnionV0) -> Option<String> {
1404        let res = union
1405            .cases
1406            .iter()
1407            .map(|case| match case {
1408                ScSpecUdtUnionCaseV0::VoidV0(ScSpecUdtUnionCaseVoidV0 { name, .. }) => {
1409                    Some(format!("\"{}\"", name.to_utf8_string_lossy()))
1410                }
1411                ScSpecUdtUnionCaseV0::TupleV0(ScSpecUdtUnionCaseTupleV0 {
1412                    name, type_, ..
1413                }) => {
1414                    if type_.len() == 1 {
1415                        let single = self.example(depth, &type_[0])?;
1416                        Some(format!("{{\"{}\":{single}}}", name.to_utf8_string_lossy()))
1417                    } else {
1418                        let names = type_
1419                            .iter()
1420                            .map(|t| self.example(depth, t))
1421                            .collect::<Option<Vec<_>>>()?
1422                            .join(", ");
1423                        Some(format!("{{\"{}\":[{names}]}}", name.to_utf8_string_lossy()))
1424                    }
1425                }
1426            })
1427            .collect::<Option<Vec<_>>>()?;
1428        Some(res.join("|"))
1429    }
1430}
1431
1432#[cfg(test)]
1433mod tests {
1434    use super::*;
1435    use stellar_xdr::curr::{Duration, ScMap, ScSpecTypeBytesN, TimePoint};
1436
1437    const CUSTOM_TYPES_WASM: &[u8] =
1438        include_bytes!("../../../../target/wasm32v1-none/test-wasms/test_custom_types.wasm");
1439
1440    fn get_custom_types_spec() -> Spec {
1441        Spec::from_wasm(CUSTOM_TYPES_WASM).unwrap()
1442    }
1443
1444    #[test]
1445    fn test_bool_conversion() {
1446        let as_str = "true";
1447        let parsed = from_string_primitive(as_str, &ScType::Bool).unwrap();
1448        let expected = ScVal::Bool(true);
1449        assert_eq!(parsed, expected);
1450        assert_eq!(to_string(&parsed).unwrap(), as_str);
1451    }
1452
1453    #[test]
1454    fn test_null_conversion() {
1455        let as_str = "null";
1456        let parsed = from_string_primitive(
1457            as_str,
1458            &ScType::Option(Box::new(ScSpecTypeOption {
1459                value_type: Box::new(ScType::Bool),
1460            })),
1461        )
1462        .unwrap();
1463        let expected = ScVal::Void;
1464        assert_eq!(parsed, expected);
1465        assert_eq!(to_string(&parsed).unwrap(), as_str);
1466    }
1467
1468    #[test]
1469    fn test_u32_conversion() {
1470        let as_str = "42";
1471        let parsed = from_string_primitive(as_str, &ScType::U32).unwrap();
1472        let expected = ScVal::U32(42);
1473        assert_eq!(parsed, expected);
1474        assert_eq!(to_string(&parsed).unwrap(), as_str);
1475    }
1476
1477    #[test]
1478    fn test_i32_conversion() {
1479        let as_str = "-42";
1480        let parsed = from_string_primitive(as_str, &ScType::I32).unwrap();
1481        let expected = ScVal::I32(-42);
1482        assert_eq!(parsed, expected);
1483        assert_eq!(to_string(&parsed).unwrap(), as_str);
1484    }
1485
1486    #[test]
1487    fn test_u64_conversion() {
1488        let as_str = "42000000000";
1489        let parsed = from_string_primitive(as_str, &ScType::U64).unwrap();
1490        let expected = ScVal::U64(42_000_000_000);
1491        assert_eq!(parsed, expected);
1492        assert_eq!(to_string(&parsed).unwrap(), as_str);
1493    }
1494
1495    #[test]
1496    #[allow(clippy::cast_possible_truncation)]
1497    fn test_u128_conversion() {
1498        let as_str = "340000000000000000000000000000000000000";
1499        let parsed = from_string_primitive(as_str, &ScType::U128).unwrap();
1500        let b = 340_000_000_000_000_000_000_000_000_000_000_000_000u128;
1501        let expected = ScVal::U128(UInt128Parts {
1502            hi: (b >> 64) as u64,
1503            lo: b as u64,
1504        });
1505        assert_eq!(parsed, expected);
1506        assert_eq!(to_string(&parsed).unwrap(), format!("\"{as_str}\""));
1507    }
1508
1509    #[test]
1510    #[allow(clippy::cast_possible_truncation)]
1511    fn test_u256_conversion() {
1512        let as_str = "340000000000000000000000000000000000000";
1513        let parsed = from_string_primitive(as_str, &ScType::U256).unwrap();
1514        let b = 340_000_000_000_000_000_000_000_000_000_000_000_000u128;
1515        let expected = ScVal::U256(UInt256Parts {
1516            hi_hi: 0,
1517            hi_lo: 0,
1518            lo_hi: (b >> 64) as u64,
1519            lo_lo: b as u64,
1520        });
1521        assert_eq!(parsed, expected);
1522        assert_eq!(to_string(&parsed).unwrap(), format!("\"{as_str}\""));
1523    }
1524
1525    #[test]
1526    #[allow(clippy::cast_possible_truncation)]
1527    #[allow(clippy::cast_sign_loss)]
1528    fn test_i128_conversion() {
1529        let as_str = "-170000000000000000000000000000000000000";
1530        let parsed = from_string_primitive(as_str, &ScType::I128).unwrap();
1531        let b = -170_000_000_000_000_000_000_000_000_000_000_000_000i128;
1532        let expected = ScVal::I128(Int128Parts {
1533            hi: (b >> 64) as i64,
1534            lo: b as u64,
1535        });
1536        assert_eq!(parsed, expected);
1537        assert_eq!(to_string(&parsed).unwrap(), format!("\"{as_str}\""));
1538    }
1539
1540    #[test]
1541    #[allow(clippy::cast_possible_truncation)]
1542    #[allow(clippy::cast_sign_loss)]
1543    fn test_i256_conversion() {
1544        let as_str = "-170000000000000000000000000000000000000";
1545        let parsed = from_string_primitive(as_str, &ScType::I256).unwrap();
1546        let b = -170_000_000_000_000_000_000_000_000_000_000_000_000i128;
1547        let expected = ScVal::I256(Int256Parts {
1548            hi_hi: -1,
1549            hi_lo: u64::MAX,
1550            lo_hi: (b >> 64) as u64,
1551            lo_lo: b as u64,
1552        });
1553        assert_eq!(parsed, expected);
1554        assert_eq!(to_string(&parsed).unwrap(), format!("\"{as_str}\""));
1555    }
1556
1557    #[test]
1558    fn test_bytes_conversion() {
1559        let as_str = "beefface";
1560        let parsed = from_string_primitive(as_str, &ScType::Bytes).unwrap();
1561        let expected = ScVal::Bytes(ScBytes(vec![0xbe, 0xef, 0xfa, 0xce].try_into().unwrap()));
1562        assert_eq!(parsed, expected);
1563        assert_eq!(to_string(&parsed).unwrap(), format!("\"{as_str}\""));
1564    }
1565
1566    #[test]
1567    fn test_bytes_conversion_when_hex_is_all_numbers() {
1568        let as_str = "4554";
1569        let parsed = from_string_primitive(as_str, &ScType::Bytes).unwrap();
1570        let expected = ScVal::Bytes(ScBytes(vec![0x45, 0x54].try_into().unwrap()));
1571        assert_eq!(parsed, expected);
1572        assert_eq!(to_string(&parsed).unwrap(), format!("\"{as_str}\""));
1573    }
1574
1575    #[test]
1576    fn test_bytesn_conversion() {
1577        let as_str = "beefface";
1578        let parsed =
1579            from_string_primitive(as_str, &ScType::BytesN(ScSpecTypeBytesN { n: 4 })).unwrap();
1580        let expected = ScVal::Bytes(ScBytes(vec![0xbe, 0xef, 0xfa, 0xce].try_into().unwrap()));
1581        assert_eq!(parsed, expected);
1582        assert_eq!(to_string(&parsed).unwrap(), format!("\"{as_str}\""));
1583    }
1584
1585    #[test]
1586    fn test_bytesn_conversion_when_hex_is_all_numbers() {
1587        let as_str = "4554";
1588        let parsed =
1589            from_string_primitive(as_str, &ScType::BytesN(ScSpecTypeBytesN { n: 2 })).unwrap();
1590        let expected = ScVal::Bytes(ScBytes(vec![0x45, 0x54].try_into().unwrap()));
1591        assert_eq!(parsed, expected);
1592        assert_eq!(to_string(&parsed).unwrap(), format!("\"{as_str}\""));
1593    }
1594
1595    #[test]
1596    fn test_bytesn_32_conversion() {
1597        let as_str = "9af73e7070f88107cf6a03d8410caecf25fd9da24521edc076c25d559e6b4c87";
1598        let parsed =
1599            from_string_primitive(as_str, &ScType::BytesN(ScSpecTypeBytesN { n: 32 })).unwrap();
1600        let expected = ScVal::Bytes(ScBytes(
1601            vec![
1602                0x9a, 0xf7, 0x3e, 0x70, 0x70, 0xf8, 0x81, 0x07, 0xcf, 0x6a, 0x03, 0xd8, 0x41, 0x0c,
1603                0xae, 0xcf, 0x25, 0xfd, 0x9d, 0xa2, 0x45, 0x21, 0xed, 0xc0, 0x76, 0xc2, 0x5d, 0x55,
1604                0x9e, 0x6b, 0x4c, 0x87,
1605            ]
1606            .try_into()
1607            .unwrap(),
1608        ));
1609        assert_eq!(parsed, expected);
1610        assert_eq!(to_string(&parsed).unwrap(), format!("\"{as_str}\""));
1611    }
1612
1613    #[test]
1614    fn test_timepoint_conversion() {
1615        let as_str = "1760501234";
1616        let parsed = from_string_primitive(as_str, &ScType::Timepoint).unwrap();
1617        let expected = ScVal::Timepoint(TimePoint::from(1_760_501_234u64));
1618        assert_eq!(parsed, expected);
1619        assert_eq!(to_string(&parsed).unwrap(), as_str);
1620    }
1621
1622    #[test]
1623    fn test_duration_conversion() {
1624        let as_str = "1234567";
1625        let parsed = from_string_primitive(as_str, &ScType::Duration).unwrap();
1626        let expected = ScVal::Duration(Duration::from(1_234_567u64));
1627        assert_eq!(parsed, expected);
1628        assert_eq!(to_string(&parsed).unwrap(), as_str);
1629    }
1630
1631    #[test]
1632    fn test_address_conversion() {
1633        let as_str = "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSC4";
1634        let parsed = from_string_primitive(as_str, &ScType::Address).unwrap();
1635        let expected = ScVal::Address(ScAddress::Contract(ContractId(Hash([0; 32]))));
1636        assert_eq!(parsed, expected);
1637        assert_eq!(to_string(&parsed).unwrap(), format!("\"{as_str}\""));
1638    }
1639
1640    #[test]
1641    fn test_symbol_conversion() {
1642        let as_str = "hello";
1643        let parsed = from_string_primitive(&format!("\"{as_str}\""), &ScType::Symbol).unwrap();
1644        let expected = ScVal::Symbol("hello".try_into().unwrap());
1645        assert_eq!(parsed, expected);
1646        assert_eq!(to_string(&parsed).unwrap(), as_str);
1647    }
1648
1649    #[test]
1650    fn test_symbol_conversion_with_no_quotation_marks() {
1651        let as_str = "hello";
1652        let parsed = from_string_primitive(as_str, &ScType::Symbol).unwrap();
1653        let expected = ScVal::Symbol("hello".try_into().unwrap());
1654        assert_eq!(parsed, expected);
1655        assert_eq!(to_string(&parsed).unwrap(), as_str);
1656    }
1657
1658    #[test]
1659    fn test_optional_symbol_conversion_with_no_quotation_marks() {
1660        let as_str = "hello";
1661        let parsed = from_string_primitive(
1662            as_str,
1663            &ScType::Option(Box::new(ScSpecTypeOption {
1664                value_type: Box::new(ScType::Symbol),
1665            })),
1666        )
1667        .unwrap();
1668        let expected = ScVal::Symbol("hello".try_into().unwrap());
1669        assert_eq!(parsed, expected);
1670        assert_eq!(to_string(&parsed).unwrap(), as_str);
1671    }
1672
1673    #[test]
1674    fn test_optional_bool_conversion() {
1675        let as_str = "true";
1676        let parsed = from_string_primitive(
1677            as_str,
1678            &ScType::Option(Box::new(ScSpecTypeOption {
1679                value_type: Box::new(ScType::Bool),
1680            })),
1681        )
1682        .unwrap();
1683        let expected = ScVal::Bool(true);
1684        assert_eq!(parsed, expected);
1685        assert_eq!(to_string(&parsed).unwrap(), as_str);
1686    }
1687
1688    #[test]
1689    fn test_vec_conversion() {
1690        let as_str = "[12345,67890,42000000000]";
1691        let parsed = from_string_primitive(
1692            as_str,
1693            &ScType::Vec(Box::new(ScSpecTypeVec {
1694                element_type: Box::new(ScType::U64),
1695            })),
1696        )
1697        .unwrap();
1698        let expected = ScVal::Vec(Some(ScVec::from(
1699            VecM::try_from(vec![
1700                ScVal::U64(12345),
1701                ScVal::U64(67890),
1702                ScVal::U64(42_000_000_000),
1703            ])
1704            .unwrap(),
1705        )));
1706        assert_eq!(parsed, expected);
1707        assert_eq!(to_string(&parsed).unwrap(), as_str);
1708    }
1709
1710    #[test]
1711    fn test_tuple_conversion() {
1712        let as_str = r#"["hello",1]"#;
1713        let parsed = from_string_primitive(
1714            as_str,
1715            &ScType::Tuple(Box::new(ScSpecTypeTuple {
1716                value_types: VecM::try_from(vec![ScType::Symbol, ScType::U64]).unwrap(),
1717            })),
1718        )
1719        .unwrap();
1720        let expected = ScVal::Vec(Some(ScVec::from(
1721            VecM::try_from(vec![
1722                ScVal::Symbol("hello".try_into().unwrap()),
1723                ScVal::U64(1),
1724            ])
1725            .unwrap(),
1726        )));
1727        assert_eq!(parsed, expected);
1728        assert_eq!(to_string(&parsed).unwrap(), as_str);
1729    }
1730
1731    #[test]
1732    fn test_udt_struct_conversion() {
1733        let spec = get_custom_types_spec();
1734        let type_ = &spec.find_function("strukt").unwrap().inputs[0].type_;
1735        let as_str = r#"{"a":42,"b":false,"c":"world"}"#;
1736        let parsed = spec.from_string(as_str, type_).unwrap();
1737        let expected = ScVal::Map(Some(
1738            ScMap::sorted_from(vec![
1739                ScMapEntry {
1740                    key: ScVal::Symbol("a".try_into().unwrap()),
1741                    val: ScVal::U32(42),
1742                },
1743                ScMapEntry {
1744                    key: ScVal::Symbol("b".try_into().unwrap()),
1745                    val: ScVal::Bool(false),
1746                },
1747                ScMapEntry {
1748                    key: ScVal::Symbol("c".try_into().unwrap()),
1749                    val: ScVal::Symbol("world".try_into().unwrap()),
1750                },
1751            ])
1752            .unwrap(),
1753        ));
1754        assert_eq!(parsed, expected);
1755        assert_eq!(to_string(&parsed).unwrap(), as_str);
1756    }
1757
1758    #[test]
1759    fn test_udt_enum_conversion() {
1760        let spec = get_custom_types_spec();
1761        let type_ = &spec.find_function("simple").unwrap().inputs[0].type_;
1762        let as_str = "Second";
1763        let parsed = spec.from_string(as_str, type_).unwrap();
1764        let expected = ScVal::Vec(Some(ScVec::from(
1765            VecM::try_from(vec![ScVal::Symbol("Second".try_into().unwrap())]).unwrap(),
1766        )));
1767        assert_eq!(parsed, expected);
1768        assert_eq!(to_string(&parsed).unwrap(), format!("[\"{as_str}\"]"));
1769    }
1770
1771    #[test]
1772    fn parse_udt_const_enum_conversion() {
1773        let spec = get_custom_types_spec();
1774        let type_ = &spec.find_function("simple").unwrap().inputs[0].type_;
1775        let as_str = "Second";
1776        let parsed = spec.from_string(as_str, type_).unwrap();
1777        let expected = ScVal::Vec(Some(ScVec::from(
1778            VecM::try_from(vec![ScVal::Symbol("Second".try_into().unwrap())]).unwrap(),
1779        )));
1780        assert_eq!(parsed, expected);
1781        assert_eq!(to_string(&parsed).unwrap(), format!("[\"{as_str}\"]"));
1782    }
1783
1784    #[test]
1785    fn test_sc_address_from_json_strkey() {
1786        // All zero contract address
1787        match sc_address_from_json("CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSC4") {
1788            Ok(addr) => assert_eq!(
1789                addr,
1790                ScVal::Address(ScAddress::Contract(ContractId(Hash([0; 32]))))
1791            ),
1792            Err(e) => panic!("Unexpected error: {e}"),
1793        }
1794
1795        // Real contract address
1796        match sc_address_from_json("CA3D5KRYM6CB7OWQ6TWYRR3Z4T7GNZLKERYNZGGA5SOAOPIFY6YQGAXE") {
1797            Ok(addr) => assert_eq!(
1798                addr,
1799                ScVal::Address(ScAddress::Contract(ContractId::from(Hash([
1800                    0x36, 0x3e, 0xaa, 0x38, 0x67, 0x84, 0x1f, 0xba, 0xd0, 0xf4, 0xed, 0x88, 0xc7,
1801                    0x79, 0xe4, 0xfe, 0x66, 0xe5, 0x6a, 0x24, 0x70, 0xdc, 0x98, 0xc0, 0xec, 0x9c,
1802                    0x07, 0x3d, 0x05, 0xc7, 0xb1, 0x03,
1803                ]))))
1804            ),
1805            Err(e) => panic!("Unexpected error: {e}"),
1806        }
1807
1808        // All zero user account address
1809        match sc_address_from_json("GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF") {
1810            Ok(addr) => assert_eq!(
1811                addr,
1812                ScVal::Address(ScAddress::Account(AccountId(
1813                    PublicKey::PublicKeyTypeEd25519([0; 32].into())
1814                )))
1815            ),
1816            Err(e) => panic!("Unexpected error: {e}"),
1817        }
1818
1819        // Real user account address
1820        match sc_address_from_json("GA3D5KRYM6CB7OWQ6TWYRR3Z4T7GNZLKERYNZGGA5SOAOPIFY6YQHES5") {
1821            Ok(addr) => assert_eq!(
1822                addr,
1823                ScVal::Address(ScAddress::Account(AccountId(
1824                    PublicKey::PublicKeyTypeEd25519(
1825                        [
1826                            0x36, 0x3e, 0xaa, 0x38, 0x67, 0x84, 0x1f, 0xba, 0xd0, 0xf4, 0xed, 0x88,
1827                            0xc7, 0x79, 0xe4, 0xfe, 0x66, 0xe5, 0x6a, 0x24, 0x70, 0xdc, 0x98, 0xc0,
1828                            0xec, 0x9c, 0x07, 0x3d, 0x05, 0xc7, 0xb1, 0x03,
1829                        ]
1830                        .into()
1831                    )
1832                )))
1833            ),
1834            Err(e) => panic!("Unexpected error: {e}"),
1835        }
1836
1837        // MuxedAddress test
1838        match sc_address_from_json(
1839            "MA5XIGA5C7QTPTWXQHY6MCJRMTRZDOSHR6EFIBNDQTCQHG262N4GGGC2XZXD7G7EWH7U6",
1840        ) {
1841            Ok(addr) => {
1842                // This should parse successfully now
1843                assert!(matches!(addr, ScVal::Address(ScAddress::MuxedAccount(_))));
1844            }
1845            Err(e) => panic!("Unexpected error parsing MuxedAddress: {e}"),
1846        }
1847    }
1848
1849    #[test]
1850    fn test_sc_address_json_strkey_muxed_roundtrip() {
1851        let muxed_address_str =
1852            "MA5XIGA5C7QTPTWXQHY6MCJRMTRZDOSHR6EFIBNDQTCQHG262N4GGGC2XZXD7G7EWH7U6";
1853
1854        // First convert from JSON strkey to ScAddress, then convert back to JSON strkey using sc_address_to_json
1855        match sc_address_from_json(muxed_address_str) {
1856            Ok(ScVal::Address(address)) => {
1857                let json_result = sc_address_to_json(&address);
1858                assert_eq!(json_result, Value::String(muxed_address_str.to_string()));
1859            }
1860            Ok(_) => panic!("Expected ScVal::Address"),
1861            Err(e) => panic!("Unexpected error: {e}"),
1862        }
1863    }
1864
1865    #[test]
1866    fn test_sc_muxed_address_from_json() {
1867        let expected_ed25519 = Uint256([
1868            0x3b, 0x74, 0x18, 0x1d, 0x17, 0xe1, 0x37, 0xce, 0xd7, 0x81, 0xf1, 0xe6, 0x09, 0x31,
1869            0x64, 0xe3, 0x91, 0xba, 0x47, 0x8f, 0x88, 0x54, 0x05, 0xa3, 0x84, 0xc5, 0x03, 0x9b,
1870            0x5e, 0xd3, 0x78, 0x63,
1871        ]);
1872        let expected_id = 1_754_924_385_537_090_737_u64;
1873
1874        // Generate the muxed address from the expected values
1875        let muxed_addr = stellar_strkey::ed25519::MuxedAccount {
1876            ed25519: expected_ed25519.0,
1877            id: expected_id,
1878        }
1879        .to_string();
1880
1881        // Test muxed address parsing
1882        match sc_address_from_json(&muxed_addr) {
1883            Ok(ScVal::Address(ScAddress::MuxedAccount(MuxedEd25519Account { ed25519, id }))) => {
1884                // Verify the actual content of the MuxedEd25519Account
1885                assert_eq!(ed25519, expected_ed25519);
1886                assert_eq!(id, expected_id);
1887            }
1888            Ok(_) => panic!("Expected ScVal::Address(ScAddress::MuxedAccount(_))"),
1889            Err(e) => panic!("Unexpected error parsing MuxedAddress: {e}"),
1890        }
1891    }
1892
1893    #[test]
1894    fn test_u128_conversions() {
1895        // Test basic positive value
1896        let val = 42u128;
1897        let json_val = Value::String(val.to_string());
1898        let scval = from_json_primitives(&json_val, &ScType::U128).unwrap();
1899        assert_eq!(to_json(&scval).unwrap(), json_val);
1900
1901        // Test zero
1902        let val = 0u128;
1903        let json_val = Value::String(val.to_string());
1904        let scval = from_json_primitives(&json_val, &ScType::U128).unwrap();
1905        assert_eq!(to_json(&scval).unwrap(), json_val);
1906
1907        // Test maximum value
1908        let val = u128::MAX;
1909        let json_val = Value::String(val.to_string());
1910        let scval = from_json_primitives(&json_val, &ScType::U128).unwrap();
1911        assert_eq!(to_json(&scval).unwrap(), json_val);
1912
1913        // Test large value
1914        let val = 340_282_366_920_938_463_463_374_607_431_768_211_455u128;
1915        let json_val = Value::String(val.to_string());
1916        let scval = from_json_primitives(&json_val, &ScType::U128).unwrap();
1917        assert_eq!(to_json(&scval).unwrap(), json_val);
1918    }
1919
1920    #[test]
1921    fn test_i128_conversions() {
1922        // Test basic positive value
1923        let val = 42i128;
1924        let json_val = Value::String(val.to_string());
1925        let scval = from_json_primitives(&json_val, &ScType::I128).unwrap();
1926        assert_eq!(to_json(&scval).unwrap(), json_val);
1927
1928        // Test basic negative value
1929        let val = -42i128;
1930        let json_val = Value::String(val.to_string());
1931        let scval = from_json_primitives(&json_val, &ScType::I128).unwrap();
1932        assert_eq!(to_json(&scval).unwrap(), json_val);
1933
1934        // Test zero
1935        let val = 0i128;
1936        let json_val = Value::String(val.to_string());
1937        let scval = from_json_primitives(&json_val, &ScType::I128).unwrap();
1938        assert_eq!(to_json(&scval).unwrap(), json_val);
1939
1940        // Test maximum value
1941        let val = i128::MAX;
1942        let json_val = Value::String(val.to_string());
1943        let scval = from_json_primitives(&json_val, &ScType::I128).unwrap();
1944        assert_eq!(to_json(&scval).unwrap(), json_val);
1945
1946        // Test minimum value
1947        let val = i128::MIN;
1948        let json_val = Value::String(val.to_string());
1949        let scval = from_json_primitives(&json_val, &ScType::I128).unwrap();
1950        assert_eq!(to_json(&scval).unwrap(), json_val);
1951
1952        // Test large negative value
1953        let val = -170_141_183_460_469_231_731_687_303_715_884_105_728i128;
1954        let json_val = Value::String(val.to_string());
1955        let scval = from_json_primitives(&json_val, &ScType::I128).unwrap();
1956        assert_eq!(to_json(&scval).unwrap(), json_val);
1957    }
1958
1959    #[test]
1960    fn test_u256_conversions() {
1961        // Test basic positive value
1962        let val = "42";
1963        let json_val = Value::String(val.to_string());
1964        let scval = from_json_primitives(&json_val, &ScType::U256).unwrap();
1965        assert_eq!(to_json(&scval).unwrap(), json_val);
1966
1967        // Test zero
1968        let val = "0";
1969        let json_val = Value::String(val.to_string());
1970        let scval = from_json_primitives(&json_val, &ScType::U256).unwrap();
1971        assert_eq!(to_json(&scval).unwrap(), json_val);
1972
1973        // Test large value
1974        let val = "115792089237316195423570985008687907853269984665640564039457584007913129639935";
1975        let json_val = Value::String(val.to_string());
1976        let scval = from_json_primitives(&json_val, &ScType::U256).unwrap();
1977        assert_eq!(to_json(&scval).unwrap(), json_val);
1978
1979        // Test hex format
1980        let val = "0xff";
1981        let json_val = Value::String(val.to_string());
1982        let scval = from_json_primitives(&json_val, &ScType::U256).unwrap();
1983        let expected = Value::String("255".to_string());
1984        assert_eq!(to_json(&scval).unwrap(), expected);
1985
1986        // Test hex format with 0x prefix
1987        let val = "0x1234567890abcdef";
1988        let json_val = Value::String(val.to_string());
1989        let scval = from_json_primitives(&json_val, &ScType::U256).unwrap();
1990        let expected = Value::String("1311768467294899695".to_string());
1991        assert_eq!(to_json(&scval).unwrap(), expected);
1992    }
1993
1994    #[test]
1995    fn test_i256_conversions() {
1996        // Test basic positive value
1997        let val = "42";
1998        let json_val = Value::String(val.to_string());
1999        let scval = from_json_primitives(&json_val, &ScType::I256).unwrap();
2000        assert_eq!(to_json(&scval).unwrap(), json_val);
2001
2002        // Test basic negative value
2003        let val = "-42";
2004        let json_val = Value::String(val.to_string());
2005        let scval = from_json_primitives(&json_val, &ScType::I256).unwrap();
2006        assert_eq!(to_json(&scval).unwrap(), json_val);
2007
2008        // Test zero
2009        let val = "0";
2010        let json_val = Value::String(val.to_string());
2011        let scval = from_json_primitives(&json_val, &ScType::I256).unwrap();
2012        assert_eq!(to_json(&scval).unwrap(), json_val);
2013
2014        // Test large positive value
2015        let val = "57896044618658097711785492504343953926634992332820282019728792003956564819967";
2016        let json_val = Value::String(val.to_string());
2017        let scval = from_json_primitives(&json_val, &ScType::I256).unwrap();
2018        assert_eq!(to_json(&scval).unwrap(), json_val);
2019
2020        // Test large negative value
2021        let val = "-57896044618658097711785492504343953926634992332820282019728792003956564819968";
2022        let json_val = Value::String(val.to_string());
2023        let scval = from_json_primitives(&json_val, &ScType::I256).unwrap();
2024        assert_eq!(to_json(&scval).unwrap(), json_val);
2025
2026        // Test hex format
2027        let val = "0xff";
2028        let json_val = Value::String(val.to_string());
2029        let scval = from_json_primitives(&json_val, &ScType::I256).unwrap();
2030        let expected = Value::String("255".to_string());
2031        assert_eq!(to_json(&scval).unwrap(), expected);
2032
2033        // Test negative hex format
2034        let val = "-0xff";
2035        let json_val = Value::String(val.to_string());
2036        let scval = from_json_primitives(&json_val, &ScType::I256).unwrap();
2037        let expected = Value::String("-255".to_string());
2038        assert_eq!(to_json(&scval).unwrap(), expected);
2039    }
2040
2041    #[test]
2042    fn test_integer_conversion_edge_cases() {
2043        // Test invalid string for U128
2044        let json_val = Value::String("not_a_number".to_string());
2045        let result = from_json_primitives(&json_val, &ScType::U128);
2046        assert!(result.is_err());
2047
2048        // Test invalid string for I128
2049        let json_val = Value::String("not_a_number".to_string());
2050        let result = from_json_primitives(&json_val, &ScType::I128);
2051        assert!(result.is_err());
2052
2053        // Test invalid string for U256
2054        let json_val = Value::String("not_a_number".to_string());
2055        let result = from_json_primitives(&json_val, &ScType::U256);
2056        assert!(result.is_err());
2057
2058        // Test invalid string for I256
2059        let json_val = Value::String("not_a_number".to_string());
2060        let result = from_json_primitives(&json_val, &ScType::I256);
2061        assert!(result.is_err());
2062
2063        // Test negative value for U128 (should fail)
2064        let json_val = Value::String("-42".to_string());
2065        let result = from_json_primitives(&json_val, &ScType::U128);
2066        assert!(result.is_err());
2067
2068        // Test negative value for U256 (should fail)
2069        let json_val = Value::String("-42".to_string());
2070        let result = from_json_primitives(&json_val, &ScType::U256);
2071        assert!(result.is_err());
2072    }
2073
2074    #[test]
2075    fn test_numeric_extremes() {
2076        // Test U32 maximum
2077        let val = u32::MAX;
2078        let json_val = Value::Number(val.into());
2079        let scval = from_json_primitives(&json_val, &ScType::U32).unwrap();
2080        assert_eq!(to_json(&scval).unwrap(), json_val);
2081
2082        // Test I32 minimum and maximum
2083        let val = i32::MIN;
2084        let json_val = Value::Number(val.into());
2085        let scval = from_json_primitives(&json_val, &ScType::I32).unwrap();
2086        assert_eq!(to_json(&scval).unwrap(), json_val);
2087
2088        let val = i32::MAX;
2089        let json_val = Value::Number(val.into());
2090        let scval = from_json_primitives(&json_val, &ScType::I32).unwrap();
2091        assert_eq!(to_json(&scval).unwrap(), json_val);
2092
2093        // Test U64 maximum
2094        let val = u64::MAX;
2095        let json_val = Value::Number(val.into());
2096        let scval = from_json_primitives(&json_val, &ScType::U64).unwrap();
2097        assert_eq!(to_json(&scval).unwrap(), json_val);
2098
2099        // Test I64 minimum and maximum
2100        let val = i64::MIN;
2101        let json_val = Value::Number(val.into());
2102        let scval = from_json_primitives(&json_val, &ScType::I64).unwrap();
2103        assert_eq!(to_json(&scval).unwrap(), json_val);
2104
2105        let val = i64::MAX;
2106        let json_val = Value::Number(val.into());
2107        let scval = from_json_primitives(&json_val, &ScType::I64).unwrap();
2108        assert_eq!(to_json(&scval).unwrap(), json_val);
2109    }
2110}