foundry_evm_traces/decoder/
vm.rs1use alloy_json_abi::{Function, Param};
7use foundry_cheatcodes_spec::{Cheatcodes, Enum, Struct};
8
9pub(super) fn functions() -> Vec<Function> {
11 let Cheatcodes { structs, enums, cheatcodes, .. } = Cheatcodes::new();
12 cheatcodes
13 .iter()
14 .map(|cheatcode| {
15 let declaration = cheatcode.func.declaration.trim_end_matches(';');
16 let mut func = Function::parse(declaration)
17 .unwrap_or_else(|e| panic!("invalid cheatcode `{declaration}`: {e}"));
18 for param in func.inputs.iter_mut().chain(&mut func.outputs) {
19 resolve(param, &structs, &enums);
20 }
21 func
22 })
23 .collect()
24}
25
26fn resolve(param: &mut Param, structs: &[Struct<'_>], enums: &[Enum<'_>]) {
29 let (root, suffix) = param.ty.split_at(param.ty.find('[').unwrap_or(param.ty.len()));
30 if let Some(strukt) = structs.iter().find(|s| s.name == root) {
31 param.components = strukt
32 .fields
33 .iter()
34 .map(|field| {
35 let mut component = Param::parse(&format!("{} {}", field.ty, field.name))
36 .unwrap_or_else(|e| {
37 panic!("invalid field `{}.{}`: {e}", strukt.name, field.name)
38 });
39 resolve(&mut component, structs, enums);
40 component
41 })
42 .collect();
43 param.ty = format!("tuple{suffix}");
44 } else if enums.iter().any(|e| e.name == root) {
45 param.ty = format!("uint8{suffix}");
46 }
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52
53 #[test]
54 fn selectors_match_spec() {
55 let cheatcodes = Cheatcodes::new().cheatcodes;
56 let functions = functions();
57 assert_eq!(functions.len(), cheatcodes.len());
58 for (func, cheatcode) in functions.iter().zip(cheatcodes.iter()) {
59 assert_eq!(func.selector().0, cheatcode.func.selector_bytes, "{}", func.signature());
60 }
61 }
62}