1use super::types::AbiType;
2
3use fe_common::utils::keccak;
4use serde::Serialize;
5
6#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
7pub struct AbiEvent {
8 #[serde(rename = "type")]
9 pub ty: &'static str,
10 pub name: String,
11 pub inputs: Vec<AbiEventField>,
12 pub anonymous: bool,
13}
14
15impl AbiEvent {
16 pub fn new(name: String, fields: Vec<AbiEventField>, anonymous: bool) -> Self {
17 Self {
18 ty: "event",
19 name,
20 inputs: fields,
21 anonymous,
22 }
23 }
24
25 pub fn signature(&self) -> AbiEventSignature {
26 AbiEventSignature::new(self)
27 }
28}
29
30pub struct AbiEventSignature {
31 sig: String,
32}
33
34impl AbiEventSignature {
35 pub fn signature(&self) -> &str {
36 &self.sig
37 }
38
39 pub fn hash_hex(&self) -> String {
40 keccak::full(self.sig.as_bytes())
41 }
42
43 pub fn hash_raw(&self) -> [u8; 32] {
44 keccak::full_as_bytes(self.sig.as_bytes())
45 }
46
47 fn new(event: &AbiEvent) -> Self {
48 let sig = format!(
49 "{}({})",
50 event.name,
51 event
52 .inputs
53 .iter()
54 .map(|input| input.ty.selector_type_name())
55 .collect::<Vec<_>>()
56 .join(",")
57 );
58
59 Self { sig }
60 }
61}
62
63#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
64pub struct AbiEventField {
65 pub name: String,
66 #[serde(flatten)]
67 pub ty: AbiType,
68 pub indexed: bool,
69}
70
71impl AbiEventField {
72 pub fn new(name: String, ty: impl Into<AbiType>, indexed: bool) -> Self {
73 Self {
74 name,
75 ty: ty.into(),
76 indexed,
77 }
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 use serde_test::{assert_ser_tokens, Token};
86
87 fn test_event() -> AbiEvent {
88 let i32_ty = AbiType::Int(32);
89 let u32_ty = AbiType::UInt(32);
90 let field1 = AbiEventField::new("x".into(), i32_ty, true);
91 let field2 = AbiEventField::new("y".into(), u32_ty, false);
92
93 AbiEvent::new("MyEvent".into(), vec![field1, field2], false)
94 }
95
96 #[test]
97 fn serialize_event() {
98 let event = test_event();
99
100 assert_ser_tokens(
101 &event,
102 &[
103 Token::Struct {
104 name: "AbiEvent",
105 len: 4,
106 },
107 Token::Str("type"),
108 Token::Str("event"),
109 Token::String("name"),
110 Token::String("MyEvent"),
111 Token::Str("inputs"),
112 Token::Seq { len: Some(2) },
113 Token::Map { len: None },
114 Token::String("name"),
115 Token::String("x"),
116 Token::String("type"),
117 Token::String("int32"),
118 Token::Str("indexed"),
119 Token::Bool(true),
120 Token::MapEnd,
121 Token::Map { len: None },
122 Token::String("name"),
123 Token::String("y"),
124 Token::String("type"),
125 Token::String("uint32"),
126 Token::Str("indexed"),
127 Token::Bool(false),
128 Token::MapEnd,
129 Token::SeqEnd,
130 Token::Str("anonymous"),
131 Token::Bool(false),
132 Token::StructEnd,
133 ],
134 )
135 }
136
137 #[test]
138 fn event_signature() {
139 let event = test_event();
140
141 let sig = event.signature();
142 debug_assert_eq!(sig.signature(), "MyEvent(int32,uint32)");
143 debug_assert_eq!(
144 sig.hash_hex(),
145 "ec835d5150565cb216f72ba07d715e875b0738b1ac3f412e103839e5157b7ee6"
146 );
147 }
148}