Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions cmd/crates/soroban-spec-tools/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,11 @@ impl Spec {
(val, ScType::Result(inner)) => self.xdr_to_json(val, &inner.ok_type)?,

(val, ScType::Option(inner)) => self.xdr_to_json(val, &inner.value_type)?,

// ScType::Val is the generic Soroban value type that can hold any ScVal.
// Delegate to to_json which handles all ScVal variants without type info.
(val, ScType::Val) => to_json(val)?,

(ScVal::Map(Some(_)) | ScVal::Vec(Some(_)) | ScVal::U32(_), type_) => {
self.sc_object_to_json(val, type_)?
}
Expand Down Expand Up @@ -2450,4 +2455,63 @@ mod tests {
let json = spec.sc_map_to_json(&sc_map, &map_type).unwrap();
assert_eq!(json.to_string(), r#"{"foo":2}"#);
}

#[test]
fn test_xdr_to_json_bytes_with_val_type() {
// Regression test for https://github.com/stellar/stellar-cli/issues/2469
// When a contract function returns ScType::Val and the runtime value is
// ScVal::Bytes (e.g. BytesN<32>), xdr_to_json should succeed instead of
// panicking with "doesn't have a matching Val".
let spec = Spec(None);
let bytes_val = ScVal::Bytes(ScBytes(
vec![
0x05, 0x5e, 0xf8, 0x16, 0x22, 0x3e, 0xe5, 0x21, 0x6b, 0x18, 0xc2, 0xdf, 0x00, 0xd6,
0x15, 0xee, 0x08, 0x9a, 0x8e, 0xf1, 0x1b, 0x92, 0x7a, 0x76, 0x4e, 0x4f, 0x5d, 0x6c,
0x0c, 0xb4, 0xf4, 0xc7,
]
.try_into()
.unwrap(),
));
let result = spec.xdr_to_json(&bytes_val, &ScType::Val);
assert_eq!(
result.unwrap(),
Value::String(
"055ef816223ee5216b18c2df00d615ee089a8ef11b927a764e4f5d6c0cb4f4c7".to_string()
)
);
}

#[test]
fn test_xdr_to_json_map_with_val_type() {
// ScVal::Map with ScType::Val should delegate to to_json, not sc_object_to_json.
let spec = Spec(None);
let map_val = ScVal::Map(Some(
ScMap::sorted_from(vec![ScMapEntry {
key: ScVal::Symbol(ScSymbol("key".try_into().unwrap())),
val: ScVal::U32(42),
}])
.unwrap(),
));
let result = spec.xdr_to_json(&map_val, &ScType::Val);
assert!(result.is_ok(), "Map with ScType::Val should not error");
}

#[test]
fn test_xdr_to_json_vec_with_val_type() {
// ScVal::Vec with ScType::Val should delegate to to_json, not sc_object_to_json.
let spec = Spec(None);
let vec_val = ScVal::Vec(Some(
ScVec::try_from(vec![ScVal::U32(1), ScVal::U32(2)]).unwrap(),
));
let result = spec.xdr_to_json(&vec_val, &ScType::Val);
assert!(result.is_ok(), "Vec with ScType::Val should not error");
}

#[test]
fn test_xdr_to_json_u32_with_val_type() {
// ScVal::U32 with ScType::Val should delegate to to_json, not sc_object_to_json.
let spec = Spec(None);
let result = spec.xdr_to_json(&ScVal::U32(100), &ScType::Val);
assert_eq!(result.unwrap(), Value::Number(100.into()));
}
}
Loading