chainerrors_evm/
revert.rs1use alloy_core::dyn_abi::{DynSolValue, DynSolType};
9
10pub const ERROR_STRING_SELECTOR: [u8; 4] = [0x08, 0xc3, 0x79, 0xa0];
12
13pub fn decode_error_string(data: &[u8]) -> Option<String> {
18 if data.len() < 4 {
19 return None;
20 }
21 if &data[..4] != ERROR_STRING_SELECTOR {
22 return None;
23 }
24 let payload = &data[4..];
25 let ty = DynSolType::String;
27 match ty.abi_decode(payload) {
28 Ok(DynSolValue::String(s)) => Some(s.trim_end_matches('\0').to_string()),
29 _ => None,
30 }
31}
32
33#[cfg(test)]
34mod tests {
35 use super::*;
36
37 const REVERT_HEX: &str = "08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001e4e6f7420656e6f75676820746f6b656e7320746f207472616e73666572000000";
39
40 #[test]
41 fn decode_error_string_basic() {
42 let data = hex::decode(REVERT_HEX).unwrap();
43 let msg = decode_error_string(&data).unwrap();
44 assert_eq!(msg, "Not enough tokens to transfer");
45 }
46
47 #[test]
48 fn decode_error_string_wrong_selector() {
49 let data = hex::decode("4e487b710000000000000000000000000000000000000000000000000000000000000011").unwrap();
50 assert!(decode_error_string(&data).is_none());
51 }
52
53 #[test]
54 fn decode_error_string_too_short() {
55 assert!(decode_error_string(&[0x08, 0xc3]).is_none());
56 }
57
58 #[test]
59 fn decode_error_string_empty_message() {
60 let data = hex::decode(
62 "08c379a0\
63 0000000000000000000000000000000000000000000000000000000000000020\
64 0000000000000000000000000000000000000000000000000000000000000000",
65 )
66 .unwrap();
67 let msg = decode_error_string(&data).unwrap();
68 assert_eq!(msg, "");
69 }
70}