1use alloc::collections::BTreeMap;
12
13#[cfg(feature = "serde")]
14use serde::{Deserialize, Serialize};
15use sha3::{Digest, Keccak256};
16
17#[cfg(not(feature = "std"))]
18use crate::no_std_prelude::*;
19use crate::{
20 decode, decode_validate, encode, signature::long_signature, Error, EventParam, Hash, Log, LogParam, ParamType,
21 RawLog, RawTopicFilter, Result, Token, Topic, TopicFilter,
22};
23
24#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
26#[derive(Clone, Debug, PartialEq)]
27pub struct Event {
28 #[cfg_attr(feature = "serde", serde(deserialize_with = "crate::util::sanitize_name::deserialize"))]
30 pub name: String,
31 pub inputs: Vec<EventParam>,
33 pub anonymous: bool,
35}
36
37impl Event {
38 fn params_names(&self) -> Vec<String> {
40 self.inputs.iter().map(|p| p.name.clone()).collect()
41 }
42
43 fn param_types(&self) -> Vec<ParamType> {
45 self.inputs.iter().map(|p| p.kind.clone()).collect()
46 }
47
48 fn indexed_params(&self, indexed: bool) -> Vec<EventParam> {
50 self.inputs.iter().filter(|p| p.indexed == indexed).cloned().collect()
51 }
52
53 pub fn signature(&self) -> Hash {
55 long_signature(&self.name, &self.param_types())
56 }
57
58 pub fn filter(&self, raw: RawTopicFilter) -> Result<TopicFilter> {
60 fn convert_token(token: Token, kind: &ParamType) -> Result<Hash> {
61 if !token.type_check(kind) {
62 return Err(Error::InvalidData);
63 }
64 let encoded = encode(&[token]);
65 if encoded.len() == 32 {
66 let mut data = [0u8; 32];
67 data.copy_from_slice(&encoded);
68 Ok(data.into())
69 } else {
70 Ok(Hash::from_slice(Keccak256::digest(&encoded).as_slice()))
71 }
72 }
73
74 fn convert_topic(topic: Topic<Token>, kind: Option<&ParamType>) -> Result<Topic<Hash>> {
75 match topic {
76 Topic::Any => Ok(Topic::Any),
77 Topic::OneOf(tokens) => match kind {
78 None => Err(Error::InvalidData),
79 Some(kind) => {
80 let topics =
81 tokens.into_iter().map(|token| convert_token(token, kind)).collect::<Result<Vec<_>>>()?;
82 Ok(Topic::OneOf(topics))
83 }
84 },
85 Topic::This(token) => match kind {
86 None => Err(Error::InvalidData),
87 Some(kind) => Ok(Topic::This(convert_token(token, kind)?)),
88 },
89 }
90 }
91
92 let kinds: Vec<_> = self.indexed_params(true).into_iter().map(|param| param.kind).collect();
93 let result = if self.anonymous {
94 TopicFilter {
95 topic0: convert_topic(raw.topic0, kinds.get(0))?,
96 topic1: convert_topic(raw.topic1, kinds.get(1))?,
97 topic2: convert_topic(raw.topic2, kinds.get(2))?,
98 topic3: Topic::Any,
99 }
100 } else {
101 TopicFilter {
102 topic0: Topic::This(self.signature()),
103 topic1: convert_topic(raw.topic0, kinds.get(0))?,
104 topic2: convert_topic(raw.topic1, kinds.get(1))?,
105 topic3: convert_topic(raw.topic2, kinds.get(2))?,
106 }
107 };
108
109 Ok(result)
110 }
111
112 fn convert_topic_param_type(&self, kind: &ParamType) -> ParamType {
117 match kind {
118 ParamType::String
119 | ParamType::Bytes
120 | ParamType::Array(_)
121 | ParamType::FixedArray(_, _)
122 | ParamType::Tuple(_) => ParamType::FixedBytes(32),
123 _ => kind.clone(),
124 }
125 }
126
127 fn parse_log_inner<F: Fn(&[ParamType], &[u8]) -> Result<Vec<Token>>>(&self, log: RawLog, decode: F) -> Result<Log> {
128 let topics = log.topics;
129 let data = log.data;
130 let topics_len = topics.len();
131 let topic_params = self.indexed_params(true);
133 let data_params = self.indexed_params(false);
134 let to_skip = if self.anonymous {
136 0
137 } else {
138 let event_signature = topics.get(0).ok_or(Error::InvalidData)?;
140 if event_signature != &self.signature() {
141 return Err(Error::InvalidData);
142 }
143 1
144 };
145
146 let topic_types =
147 topic_params.iter().map(|p| self.convert_topic_param_type(&p.kind)).collect::<Vec<ParamType>>();
148
149 let flat_topics = topics.into_iter().skip(to_skip).flat_map(|t| t.as_ref().to_vec()).collect::<Vec<u8>>();
150
151 let topic_tokens = decode(&topic_types, &flat_topics)?;
152
153 if topic_tokens.len() != topics_len - to_skip {
155 return Err(Error::InvalidData);
156 }
157
158 let topics_named_tokens = topic_params.into_iter().map(|p| p.name).zip(topic_tokens.into_iter());
159
160 let data_types = data_params.iter().map(|p| p.kind.clone()).collect::<Vec<ParamType>>();
161
162 let data_tokens = decode(&data_types, &data)?;
163
164 let data_named_tokens = data_params.into_iter().map(|p| p.name).zip(data_tokens.into_iter());
165
166 let named_tokens = topics_named_tokens.chain(data_named_tokens).collect::<BTreeMap<String, Token>>();
167
168 let decoded_params = self
169 .params_names()
170 .into_iter()
171 .map(|name| LogParam { name: name.clone(), value: named_tokens[&name].clone() })
172 .collect();
173
174 let result = Log { params: decoded_params };
175
176 Ok(result)
177 }
178
179 pub fn parse_log_validate(&self, log: RawLog) -> Result<Log> {
182 self.parse_log_inner(log, decode_validate)
183 }
184
185 pub fn parse_log(&self, log: RawLog) -> Result<Log> {
187 self.parse_log_inner(log, decode)
188 }
189}
190
191#[cfg(test)]
192mod tests {
193 use hex_literal::hex;
194
195 #[cfg(not(feature = "std"))]
196 use crate::no_std_prelude::*;
197 use crate::{
198 log::{Log, RawLog},
199 signature::long_signature,
200 token::Token,
201 Event, EventParam, LogParam, ParamType,
202 };
203
204 #[test]
205 fn test_decoding_event() {
206 let event = Event {
207 name: "foo".to_owned(),
208 inputs: vec![
209 EventParam { name: "a".to_owned(), kind: ParamType::Int(256), indexed: false },
210 EventParam { name: "b".to_owned(), kind: ParamType::Int(256), indexed: true },
211 EventParam { name: "c".to_owned(), kind: ParamType::Address, indexed: false },
212 EventParam { name: "d".to_owned(), kind: ParamType::Address, indexed: true },
213 EventParam { name: "e".to_owned(), kind: ParamType::String, indexed: true },
214 EventParam {
215 name: "f".to_owned(),
216 kind: ParamType::Array(Box::new(ParamType::Int(256))),
217 indexed: true,
218 },
219 EventParam {
220 name: "g".to_owned(),
221 kind: ParamType::FixedArray(Box::new(ParamType::Address), 5),
222 indexed: true,
223 },
224 ],
225 anonymous: false,
226 };
227
228 let log = RawLog {
229 topics: vec![
230 long_signature(
231 "foo",
232 &[
233 ParamType::Int(256),
234 ParamType::Int(256),
235 ParamType::Address,
236 ParamType::Address,
237 ParamType::String,
238 ParamType::Array(Box::new(ParamType::Int(256))),
239 ParamType::FixedArray(Box::new(ParamType::Address), 5),
240 ],
241 ),
242 hex!("0000000000000000000000000000000000000000000000000000000000000002").into(),
243 hex!("0000000000000000000000001111111111111111111111111111111111111111").into(),
244 hex!("00000000000000000aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").into(),
245 hex!("00000000000000000bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb").into(),
246 hex!("00000000000000000ccccccccccccccccccccccccccccccccccccccccccccccc").into(),
247 ],
248 data: hex!(
249 "
250 0000000000000000000000000000000000000000000000000000000000000003
251 0000000000000000000000002222222222222222222222222222222222222222
252 "
253 )
254 .into(),
255 };
256 let result = event.parse_log(log).unwrap();
257
258 assert_eq!(
259 result,
260 Log {
261 params: [
262 ("a", Token::Int(hex!("0000000000000000000000000000000000000000000000000000000000000003").into()),),
263 ("b", Token::Int(hex!("0000000000000000000000000000000000000000000000000000000000000002").into()),),
264 ("c", Token::Address(hex!("2222222222222222222222222222222222222222").into())),
265 ("d", Token::Address(hex!("1111111111111111111111111111111111111111").into())),
266 (
267 "e",
268 Token::FixedBytes(
269 hex!("00000000000000000aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").into()
270 )
271 ),
272 (
273 "f",
274 Token::FixedBytes(
275 hex!("00000000000000000bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb").into()
276 )
277 ),
278 (
279 "g",
280 Token::FixedBytes(
281 hex!("00000000000000000ccccccccccccccccccccccccccccccccccccccccccccccc").into()
282 )
283 ),
284 ]
285 .iter()
286 .cloned()
287 .map(|(name, value)| LogParam { name: name.to_string(), value })
288 .collect::<Vec<_>>()
289 }
290 );
291 }
292
293 #[test]
294 fn parse_log_whole() {
295 let correct_event = Event {
296 name: "Test".into(),
297 inputs: vec![
298 EventParam {
299 name: "tuple".into(),
300 kind: ParamType::Tuple(vec![ParamType::Address, ParamType::Address]),
301 indexed: false,
302 },
303 EventParam { name: "addr".into(), kind: ParamType::Address, indexed: true },
304 ],
305 anonymous: false,
306 };
307 let mut wrong_event = correct_event.clone();
309 wrong_event.inputs[0].indexed = true;
310 wrong_event.inputs[1].indexed = false;
311
312 let log = RawLog {
313 topics: vec![
314 hex!("cf74b4e62f836eeedcd6f92120ffb5afea90e6fa490d36f8b81075e2a7de0cf7").into(),
315 hex!("0000000000000000000000000000000000000000000000000000000000012321").into(),
316 ],
317 data: hex!(
318 "
319 0000000000000000000000000000000000000000000000000000000000012345
320 0000000000000000000000000000000000000000000000000000000000054321
321 "
322 )
323 .into(),
324 };
325
326 assert!(wrong_event.parse_log(log.clone()).is_ok());
327 assert!(wrong_event.parse_log_validate(log.clone()).is_err());
328 assert!(correct_event.parse_log_validate(log).is_ok());
329 }
330}