Skip to main content

sdkt_wasm/
abi_decode.rs

1//! ABI-aware ScVal decoding helpers for .
2
3use crate::spec::{ContractEvent, ContractType};
4use stellar_xdr::ScVal;
5
6/// Human-readable label for a ScVal given ABI context.
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct DecodedValue {
9    /// The raw ScVal representation.
10    pub raw: String,
11    /// ABI-derived type name, if found.
12    pub abi_type: Option<String>,
13    /// A shorter human-readable description.
14    pub label: String,
15}
16
17/// Look up event ABI info by name.
18pub fn find_event_abi<'a>(
19    events: &'a [ContractEvent],
20    event_name: &'a str,
21) -> Option<&'a ContractEvent> {
22    events.iter().find(|e| e.name == event_name)
23}
24
25/// Look up a custom type by name.
26pub fn find_type_abi<'a>(
27    types: &'a [ContractType],
28    type_name: &'a str,
29) -> Option<&'a ContractType> {
30    types.iter().find(|t| t.name == type_name)
31}
32
33/// Format an ScVal into a human-readable string using ABI hints.
34pub fn format_scval_abi(
35    val: &ScVal,
36    event_abi: Option<&[ContractEvent]>,
37    _types_abi: Option<&[ContractType]>,
38    event_hint: Option<&str>,
39) -> DecodedValue {
40    let raw_repr = format!("{:?}", val);
41    let raw_str = raw_repr.clone();
42
43    let label = match (event_hint, event_abi) {
44        (Some(name), Some(events)) => {
45            if find_event_abi(events, name).is_some() {
46                format!("event[{}] -> value", name)
47            } else {
48                raw_repr
49            }
50        }
51        _ => raw_repr,
52    };
53
54    DecodedValue {
55        raw: raw_str,
56        abi_type: None,
57        label,
58    }
59}
60
61#[cfg(test)]
62mod abi_tests {
63    use super::*;
64    use crate::spec::ContractEvent;
65    use stellar_xdr::ScVal;
66
67    fn dummy_events() -> Vec<ContractEvent> {
68        vec![ContractEvent {
69            name: "transfer".to_string(),
70            doc: "transfer event".to_string(),
71            params: vec![],
72            prefix_topics: vec![],
73            data_format: "single_value".to_string(),
74        }]
75    }
76
77    #[test]
78    fn format_scval_abi_with_event_hint() {
79        let events = dummy_events();
80        let val = ScVal::U32(42);
81        let result = format_scval_abi(&val, Some(&events), None, Some("transfer"));
82        assert!(result.label.contains("event[transfer]"));
83    }
84
85    #[test]
86    fn find_event_abi_exists() {
87        let events = dummy_events();
88        assert!(find_event_abi(&events, "transfer").is_some());
89        assert!(find_event_abi(&events, "unknown").is_none());
90    }
91}