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 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 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 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 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 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 pub fn from_string_primitive(s: &str, t: &ScType) -> Result<ScVal, Error> {
229 Self::default().from_string(s, t)
230 }
231
232 #[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 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 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 #[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 (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 (ScType::Map(map), Value::Object(raw)) => self.parse_map(map, raw)?,
328
329 (ScType::Option(_), Value::Null) => ScVal::Void,
331 (ScType::Option(elem), v) => self.from_json(v, &elem.value_type)?,
332
333 (ScType::Tuple(elem), Value::Array(raw)) => self.parse_tuple(t, elem, raw)?,
335
336 (ScType::Udt(ScSpecTypeUdt { name }), _) => self.parse_udt(name, v)?,
338
339 (_, 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 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 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 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 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 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 (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 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 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 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
754pub 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#[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 (ScType::Bool, Value::Bool(true)) => ScVal::Bool(true),
782 (ScType::Bool, Value::Bool(false)) => ScVal::Bool(false),
783
784 (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 (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 (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 @ 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 if let Ok(key) = sc_address_from_json(s) {
873 return Ok(key);
874 }
875 }
876 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 (_, raw) => serde_json::from_value(raw.clone())?,
911 };
912 Ok(val)
913}
914
915pub fn to_string(v: &ScVal) -> Result<String, Error> {
919 #[allow(clippy::match_same_arms)]
920 Ok(match v {
921 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#[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 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 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 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 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
1267impl 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 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 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 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 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 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 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 match sc_address_from_json(
1839 "MA5XIGA5C7QTPTWXQHY6MCJRMTRZDOSHR6EFIBNDQTCQHG262N4GGGC2XZXD7G7EWH7U6",
1840 ) {
1841 Ok(addr) => {
1842 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 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 let muxed_addr = stellar_strkey::ed25519::MuxedAccount {
1876 ed25519: expected_ed25519.0,
1877 id: expected_id,
1878 }
1879 .to_string();
1880
1881 match sc_address_from_json(&muxed_addr) {
1883 Ok(ScVal::Address(ScAddress::MuxedAccount(MuxedEd25519Account { ed25519, id }))) => {
1884 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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}