anvil_zksync_traces/
abi_utils.rs1use alloy::dyn_abi::{DynSolType, DynSolValue, FunctionExt, JsonAbiExt};
12use alloy::json_abi::{Error, Event, Function, Param};
13use alloy::primitives::hex;
14use anvil_zksync_types::traces::{DecodedValue, LogData};
15use eyre::{Context, Result};
16
17use crate::decode::decode_value;
18
19pub fn encode_args<I, S>(inputs: &[Param], args: I) -> Result<Vec<DynSolValue>>
20where
21 I: IntoIterator<Item = S>,
22 S: AsRef<str>,
23{
24 std::iter::zip(inputs, args)
25 .map(|(input, arg)| coerce_value(&input.selector_type(), arg.as_ref()))
26 .collect()
27}
28
29pub fn encode_function_args<I, S>(func: &Function, args: I) -> Result<Vec<u8>>
32where
33 I: IntoIterator<Item = S>,
34 S: AsRef<str>,
35{
36 Ok(func.abi_encode_input(&encode_args(&func.inputs, args)?)?)
37}
38
39pub fn encode_function_args_packed<I, S>(func: &Function, args: I) -> Result<Vec<u8>>
42where
43 I: IntoIterator<Item = S>,
44 S: AsRef<str>,
45{
46 let params: Vec<Vec<u8>> = std::iter::zip(&func.inputs, args)
47 .map(|(input, arg)| coerce_value(&input.selector_type(), arg.as_ref()))
48 .collect::<Result<Vec<_>>>()?
49 .into_iter()
50 .map(|v| v.abi_encode_packed())
51 .collect();
52
53 Ok(params.concat())
54}
55
56pub fn abi_decode_calldata(
58 sig: &str,
59 calldata: &str,
60 input: bool,
61 fn_selector: bool,
62) -> Result<Vec<DecodedValue>> {
63 let func = get_func(sig)?;
64 let calldata = hex::decode(calldata)?;
65
66 let mut calldata = calldata.as_slice();
67 if input && fn_selector && calldata.len() >= 4 {
69 calldata = &calldata[4..];
70 }
71
72 let res = if input {
73 func.abi_decode_input(calldata, false)
74 } else {
75 func.abi_decode_output(calldata, false)
76 }?;
77
78 if res.is_empty() {
80 eyre::bail!("no data was decoded")
81 } else {
82 Ok(res.into_iter().map(decode_value).collect())
83 }
84}
85
86pub fn get_func(sig: &str) -> Result<Function> {
88 Function::parse(sig).wrap_err("could not parse function signature")
89}
90
91pub fn get_event(sig: &str) -> Result<Event> {
93 Event::parse(sig).wrap_err("could not parse event signature")
94}
95
96pub fn get_error(sig: &str) -> Result<Error> {
98 Error::parse(sig).wrap_err("could not parse event signature")
99}
100
101pub fn get_indexed_event(mut event: Event, raw_log: &LogData) -> Event {
104 if !event.anonymous && raw_log.topics().len() > 1 {
105 let indexed_params = raw_log.topics().len() - 1;
106 let num_inputs = event.inputs.len();
107 let num_address_params = event.inputs.iter().filter(|p| p.ty == "address").count();
108
109 event
110 .inputs
111 .iter_mut()
112 .enumerate()
113 .for_each(|(index, param)| {
114 if param.name.is_empty() {
115 param.name = format!("param{index}");
116 }
117 if num_inputs == indexed_params
118 || (num_address_params == indexed_params && param.ty == "address")
119 {
120 param.indexed = true;
121 }
122 })
123 }
124 event
125}
126
127pub fn coerce_value(ty: &str, arg: &str) -> Result<DynSolValue> {
129 let ty = DynSolType::parse(ty)?;
130 Ok(DynSolType::coerce_str(&ty, arg)?)
131}
132
133#[cfg(test)]
134mod tests {
135 use crate::decode::{get_indexed_event_from_vm_event, vm_event_to_log_data};
136
137 use super::*;
138 use alloy::dyn_abi::EventExt;
139 use alloy::primitives::{Address, B256, U256};
140 use zksync_multivm::interface::VmEvent;
141 use zksync_types::H256;
142
143 #[test]
144 fn test_get_func() {
145 let func = get_func("function foo(uint256 a, uint256 b) returns (uint256)");
146 assert!(func.is_ok());
147 let func = func.unwrap();
148 assert_eq!(func.name, "foo");
149 assert_eq!(func.inputs.len(), 2);
150 assert_eq!(func.inputs[0].ty, "uint256");
151 assert_eq!(func.inputs[1].ty, "uint256");
152
153 let func = get_func("foo(bytes4 a, uint8 b)(bytes4)");
155 assert!(func.is_ok());
156 let func = func.unwrap();
157 assert_eq!(func.name, "foo");
158 assert_eq!(func.inputs.len(), 2);
159 assert_eq!(func.inputs[0].ty, "bytes4");
160 assert_eq!(func.inputs[1].ty, "uint8");
161 assert_eq!(func.outputs[0].ty, "bytes4");
162 }
163
164 #[test]
165 fn test_indexed_only_address_vm() {
166 let event = get_event("event Ev(address,uint256,address)").unwrap();
167
168 let param0 = B256::new([0u8; 32]);
169 let param2 = B256::new([0u8; 32]);
170 let param1_data = vec![3u8; 32];
171
172 let vm_event = VmEvent {
173 indexed_topics: vec![
174 H256::from_slice(&event.selector().0),
175 H256::from_slice(¶m0.0),
176 H256::from_slice(¶m2.0),
177 ],
178 value: param1_data.clone(),
179 ..Default::default()
180 };
181
182 let updated_event = get_indexed_event_from_vm_event(event, &vm_event);
184 assert_eq!(updated_event.inputs.len(), 3);
185
186 let log_data = vm_event_to_log_data(&vm_event);
188 let decoded = updated_event.decode_log(&log_data, false).unwrap();
189
190 assert_eq!(
191 updated_event
192 .inputs
193 .iter()
194 .filter(|param| param.indexed)
195 .count(),
196 2
197 );
198 assert_eq!(
199 decoded.indexed[0],
200 DynSolValue::Address(Address::from_word(param0))
201 );
202 assert_eq!(
203 decoded.body[0],
204 DynSolValue::Uint(U256::from_be_bytes([3u8; 32]), 256)
205 );
206 assert_eq!(
207 decoded.indexed[1],
208 DynSolValue::Address(Address::from_word(param2))
209 );
210 }
211}