1use alloy_core::dyn_abi::{DynSolType, DynSolValue};
9
10pub const PANIC_SELECTOR: [u8; 4] = [0x4e, 0x48, 0x7b, 0x71];
12
13pub fn decode_panic(data: &[u8]) -> Option<(u64, &'static str)> {
17 if data.len() < 4 {
18 return None;
19 }
20 if &data[..4] != PANIC_SELECTOR {
21 return None;
22 }
23 let payload = &data[4..];
24 let ty = DynSolType::Uint(256);
25 match ty.abi_decode(payload) {
26 Ok(DynSolValue::Uint(v, _)) => {
27 let code = v.to::<u64>();
28 Some((code, panic_meaning(code)))
29 }
30 _ => None,
31 }
32}
33
34pub fn panic_meaning(code: u64) -> &'static str {
36 match code {
37 0x00 => "generic compiler-inserted panic",
38 0x01 => "assert() called with false condition",
39 0x11 => "arithmetic overflow or underflow",
40 0x12 => "division or modulo by zero",
41 0x21 => "invalid enum value",
42 0x22 => "corrupted storage byte array",
43 0x31 => ".pop() on empty array",
44 0x32 => "out-of-bounds array access",
45 0x41 => "too much memory allocated (out of memory)",
46 0x51 => "called zero-initialized internal function pointer",
47 _ => "unknown panic code",
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 const PANIC_OVERFLOW_HEX: &str =
57 "4e487b710000000000000000000000000000000000000000000000000000000000000011";
58
59 const PANIC_DIV_ZERO_HEX: &str =
61 "4e487b710000000000000000000000000000000000000000000000000000000000000012";
62
63 #[test]
64 fn decode_panic_overflow() {
65 let data = hex::decode(PANIC_OVERFLOW_HEX).unwrap();
66 let (code, meaning) = decode_panic(&data).unwrap();
67 assert_eq!(code, 0x11);
68 assert!(meaning.contains("overflow"));
69 }
70
71 #[test]
72 fn decode_panic_div_zero() {
73 let data = hex::decode(PANIC_DIV_ZERO_HEX).unwrap();
74 let (code, meaning) = decode_panic(&data).unwrap();
75 assert_eq!(code, 0x12);
76 assert!(meaning.contains("division"));
77 }
78
79 #[test]
80 fn decode_panic_wrong_selector() {
81 let data = hex::decode("08c379a000").unwrap();
82 assert!(decode_panic(&data).is_none());
83 }
84
85 #[test]
86 fn panic_meaning_known_codes() {
87 assert_eq!(panic_meaning(0x01), "assert() called with false condition");
88 assert_eq!(panic_meaning(0x32), "out-of-bounds array access");
89 assert_eq!(panic_meaning(0x99), "unknown panic code");
90 }
91}