1use alloy_sol_types::{sol, SolType};
2use hex::decode;
3use serde::Deserialize;
4use std::collections::HashMap;
5use std::error::Error;
6use std::fs;
7
8#[derive(Deserialize)]
9struct FunctionInfo {
10 abi: Vec<String>,
11 r#type: String,
12}
13
14type FunctionSelectorMap = HashMap<String, FunctionInfo>;
15
16pub fn decode_calldata(data: &str) -> Result<(String, String, String), Box<dyn Error>> {
17 let file_content = fs::read_to_string("./src/wallet-sig-map.json")?;
19 let selectors: FunctionSelectorMap = serde_json::from_str(&file_content)?;
20
21 let data_bytes = decode(data)?;
23
24 let method_selector = &data_bytes[..4];
26 let selector_str = format!("0x{}", hex::encode(method_selector));
27
28 if let Some(function_info) = selectors.get(&selector_str) {
30 if function_info.r#type == "simple"
32 && function_info.abi == vec!["address", "uint256", "bytes"]
33 {
34 type MyTuple = sol!((address, uint256, bytes));
36
37 let param_bytes = &data_bytes[4..];
39 let decoded = MyTuple::abi_decode_params(param_bytes, false)?;
40
41 let target = decoded.0.to_string();
43 let value = decoded.1.to_string();
44 let calldata = decoded.2.to_string();
45
46 return Ok((target, value, calldata));
48 }
49 }
51
52 Err("Unsupported method selector or ABI structure".into())
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59
60 #[test]
61 fn test_decode_abi() {
62 let calldata = "b61d27f6000000000000000000000000b382daf7230b73f71a766c96707cf9ec6316b360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000144e555c489000000000000000000000000efb80041d435d26d397bba4d4138b8232ea82d5400000000000000000000000081cc3c9c23ba6ce4dcf10b116079710f15336fd30000000000000000000000000000000000000000000035c900000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009581cc3c9c23ba6ce4dcf10b116079710f15336fd30000000000000000000000000000000000000000000000000000000066c97cdd0000000000000000000000000000000000000000000000000000000066c975d5d78c691a386ed33f24c0611b5021cd9a5231e763bc1127a66840231d97f599a7792bc42640ca19bf7c6f1d04a27095decf66a8dd13ea52f0c221e821965004981c000000000000000000000000000000000000000000000000000000000000000000000000000000";
63
64 let (target, address, bytes_data) = decode_calldata(calldata).unwrap();
65
66 assert_eq!(
67 target.to_ascii_lowercase(),
68 "0xb382daf7230b73f71a766c96707cf9ec6316b360"
69 );
70 assert_eq!(address, "0");
71 assert!(bytes_data.to_ascii_lowercase().contains("0xe555c489"));
72 }
73}