1use crate::log::Log;
2use crate::types::{Address, BigInt};
3
4use alloy::dyn_abi::EventExt;
5use alloy::dyn_abi::DynSolValue;
6use alloy::json_abi::Event;
7use alloy::primitives::LogData;
8
9#[derive(Debug, Clone)]
11pub enum DecodedParam {
12 Address(Address),
13 Uint(BigInt),
14 Int(BigInt),
15 Bool(bool),
16 String(String),
17 Bytes(Vec<u8>),
18 Array(Vec<DecodedParam>),
19}
20
21impl DecodedParam {
22 pub fn to_address(&self) -> Address {
23 match self {
24 DecodedParam::Address(a) => a.clone(),
25 DecodedParam::Bytes(b) if b.len() >= 20 => {
26 let mut addr = [0u8; 20];
27 addr.copy_from_slice(&b[..20]);
28 Address(addr)
29 }
30 _ => Address::zero(),
31 }
32 }
33
34 pub fn to_big_int(&self) -> BigInt {
35 match self {
36 DecodedParam::Uint(v) | DecodedParam::Int(v) => v.clone(),
37 _ => BigInt::zero(),
38 }
39 }
40
41 pub fn to_bool(&self) -> bool {
42 match self {
43 DecodedParam::Bool(v) => *v,
44 _ => false,
45 }
46 }
47
48 pub fn to_string(&self) -> String {
49 match self {
50 DecodedParam::String(s) => s.clone(),
51 _ => String::new(),
52 }
53 }
54
55 pub fn to_bytes(&self) -> Vec<u8> {
56 match self {
57 DecodedParam::Bytes(b) => b.clone(),
58 _ => Vec::new(),
59 }
60 }
61
62 pub fn to_array(&self) -> Vec<DecodedParam> {
63 match self {
64 DecodedParam::Array(a) => a.clone(),
65 _ => Vec::new(),
66 }
67 }
68}
69
70pub fn decode_event_params(log: &Log, event_abi: &str) -> Vec<DecodedParam> {
82 let abi_with_anon = if event_abi.contains("\"anonymous\"") {
85 event_abi.to_string()
86 } else {
87 let mut s = event_abi.to_string();
89 if let Some(pos) = s.rfind('}') {
90 s.insert_str(pos, ",\"anonymous\":false");
91 }
92 s
93 };
94
95 let event: Event = match serde_json::from_str(&abi_with_anon) {
96 Ok(e) => e,
97 Err(e) => {
98 eprintln!(
99 "[graph-native] ERROR: failed to parse event ABI JSON: {e} — abi: {event_abi}"
100 );
101 return Vec::new();
102 }
103 };
104
105 let topics: Vec<alloy::primitives::B256> = log
107 .topics
108 .iter()
109 .map(|t| {
110 let mut bytes = [0u8; 32];
111 let len = t.len().min(32);
112 bytes[32 - len..].copy_from_slice(&t[..len]);
113 alloy::primitives::B256::from(bytes)
114 })
115 .collect();
116
117 let log_data = LogData::new_unchecked(topics, log.data.clone().into());
119
120 let decoded = match EventExt::decode_log(&event, &log_data) {
122 Ok(d) => d,
123 Err(e) => {
124 eprintln!("[graph-native] ERROR: alloy failed to decode log: {e} — abi: {event_abi}");
125 return Vec::new();
126 }
127 };
128
129 let mut indexed_iter = decoded.indexed.into_iter();
131 let mut body_iter = decoded.body.into_iter();
132
133 let mut result = Vec::with_capacity(event.inputs.len());
134 for input in &event.inputs {
135 let value = if input.indexed {
136 indexed_iter.next()
137 } else {
138 body_iter.next()
139 };
140
141 match value {
142 Some(v) => result.push(dyn_sol_to_decoded(v)),
143 None => result.push(DecodedParam::Bytes(Vec::new())),
144 }
145 }
146
147 result
148}
149
150pub fn abi_decode(signature: &str, data: &[u8]) -> Option<DecodedParam> {
156 use alloy::dyn_abi::DynSolType;
157 let sol_type = DynSolType::parse(signature).ok()?;
158 let decoded = sol_type.abi_decode(data).ok()?;
159 Some(dyn_sol_to_decoded(decoded))
160}
161
162fn dyn_sol_to_decoded(value: DynSolValue) -> DecodedParam {
164 match value {
165 DynSolValue::Address(a) => DecodedParam::Address(Address(a.0 .0)),
166 DynSolValue::Uint(v, _bits) => {
167 let bytes = v.to_be_bytes::<32>();
168 DecodedParam::Uint(BigInt::from_unsigned_be_bytes(&bytes))
169 }
170 DynSolValue::Int(v, _bits) => {
171 let bytes = v.to_be_bytes::<32>();
172 DecodedParam::Int(BigInt::from_be_bytes(&bytes))
173 }
174 DynSolValue::Bool(b) => DecodedParam::Bool(b),
175 DynSolValue::String(s) => DecodedParam::String(s),
176 DynSolValue::Bytes(b) => DecodedParam::Bytes(b),
177 DynSolValue::FixedBytes(b, size) => DecodedParam::Bytes(b.0[..size].to_vec()),
178 DynSolValue::Array(arr) | DynSolValue::Tuple(arr) | DynSolValue::FixedArray(arr) => {
179 DecodedParam::Array(arr.into_iter().map(dyn_sol_to_decoded).collect())
180 }
181 DynSolValue::Function(f) => DecodedParam::Bytes(f.0.to_vec()),
182 other => {
184 eprintln!("Warning: unexpected DynSolValue variant in ABI decoding: {:?}", other);
185 DecodedParam::Bytes(Vec::new())
186 }
187 }
188}