1use crate::std::BTreeMap;
12use crate::std::Vec;
13use tiny_keccak::{Hasher, Keccak};
14
15use crate::{decode, Error, Param, ParamKind, Token, H256};
16
17
18#[derive(Clone, Debug, PartialEq)]
20pub struct Event<'a> {
21 pub signature: &'a str,
23 pub inputs: &'a [Param],
25 pub anonymous: bool,
27}
28
29impl<'a> Event<'a> {
30 fn signature_keccak256(&self) -> H256 {
31 let mut result = [0u8; 32];
32 let mut sponge = Keccak::v256();
33 sponge.update(self.signature.as_ref());
34 sponge.finalize(&mut result);
35 result.into()
36 }
37
38 fn indexed_params(&self, indexed: bool) -> Vec<Param> {
40 self.inputs.iter().filter(|p| p.indexed == indexed).cloned().collect()
41 }
42
43 fn indices(&self, indexed: bool) -> Vec<usize> {
45 self.inputs.iter().enumerate().filter(|(_, p)| p.indexed == indexed).map(|(i, _)| i).collect()
46 }
47
48 fn convert_topic_param_type(&self, kind: &ParamKind) -> ParamKind {
53 match kind {
54 ParamKind::String
55 | ParamKind::Bytes
56 | ParamKind::Array(_)
57 | ParamKind::FixedArray(_, _)
58 | ParamKind::Tuple(_) => ParamKind::FixedBytes(32),
59 _ => kind.clone(),
60 }
61 }
62
63 pub fn decode(&self, topics: Vec<H256>, data: Vec<u8>) -> Result<Vec<Token>, Error> {
64
65 let to_skip = if self.anonymous {
67 0
68 } else {
69 let event_signature = topics.get(0).ok_or(Error::InvalidData)?;
71 if event_signature != &self.signature_keccak256() {
72 return Err(Error::InvalidData.into());
73 }
74 1
75 };
76
77 let topics_len = topics.len();
78
79 let topic_params = self.indexed_params(true);
81 let data_params = self.indexed_params(false);
82 let topic_params_indices = self.indices(true);
83 let data_params_indices = self.indices(false);
84
85
86 let topic_types =
87 topic_params.iter().map(|p| self.convert_topic_param_type(&p.kind)).collect::<Vec<ParamKind>>();
88
89 let flat_topics = topics.into_iter().skip(to_skip).flat_map(|t| t.as_ref().to_vec()).collect::<Vec<u8>>();
90
91 let topic_tokens = decode(&topic_types, &flat_topics)?;
92
93 if topic_tokens.len() != topics_len - to_skip {
95 return Err(Error::InvalidData);
96 }
97
98 let topics_named_tokens = topic_params_indices.into_iter().zip(topic_tokens.into_iter());
99
100 let data_types = data_params.iter().map(|p| p.kind.clone()).collect::<Vec<ParamKind>>();
101 let data_tokens = decode(&data_types, &data)?;
102 let data_named_tokens = data_params_indices.into_iter().zip(data_tokens.into_iter());
103
104 let named_tokens = topics_named_tokens.chain(data_named_tokens).collect::<BTreeMap<usize, Token>>();
105
106 let tokens: Vec<Token> =
107 self.inputs.iter().enumerate().map(|t| t.0).map(|i| named_tokens[&i].clone()).collect();
108
109 Ok(tokens)
110 }
111}
112
113#[cfg(test)]
114mod tests {
115
116 use crate::{token::Token, Event, Param, ParamKind, H256};
117 use hex::FromHex;
118 use tiny_keccak::{Hasher, Keccak};
119
120 fn keccak256(data: &str) -> H256 {
121 let mut result = [0u8; 32];
122 let mut sponge = Keccak::v256();
123 sponge.update(data.as_ref());
124 sponge.finalize(&mut result);
125 result.into()
126 }
127
128 #[test]
129 fn test_decoding_event() {
130 let event = Event {
131 signature: "foo(int256,int256,address,address,string,int256[],address[5])",
132 inputs: &[Param { kind: ParamKind::Int(256), indexed: false },
133 Param { kind: ParamKind::Int(256), indexed: true },
134 Param { kind: ParamKind::Address, indexed: false },
135 Param { kind: ParamKind::Address, indexed: true },
136 Param { kind: ParamKind::String, indexed: true },
137 Param { kind: ParamKind::Array(Box::new(ParamKind::Int(256))), indexed: true },
138 Param { kind: ParamKind::FixedArray(Box::new(ParamKind::Address), 5), indexed: true },
139 ],
140 anonymous: false,
141 };
142
143 let topics: Vec<H256> = vec![
144 keccak256("foo(int256,int256,address,address,string,int256[],address[5])"),
145 "0000000000000000000000000000000000000000000000000000000000000002".parse().unwrap(),
146 "0000000000000000000000001111111111111111111111111111111111111111".parse().unwrap(),
147 "00000000000000000aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".parse().unwrap(),
148 "00000000000000000bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb".parse().unwrap(),
149 "00000000000000000ccccccccccccccccccccccccccccccccccccccccccccccc".parse().unwrap(),
150 ];
151
152 let data = concat!(
153 "0000000000000000000000000000000000000000000000000000000000000003",
154 "0000000000000000000000002222222222222222222222222222222222222222"
155 )
156 .from_hex()
157 .unwrap();
158
159 let tokens = event.decode(topics, data).unwrap();
160
161 assert_eq!(
162 tokens,
163 vec![
164 Token::Int("0000000000000000000000000000000000000000000000000000000000000003".into()),
165 Token::Int("0000000000000000000000000000000000000000000000000000000000000002".into()),
166 Token::Address("2222222222222222222222222222222222222222".parse().unwrap()),
167 Token::Address("1111111111111111111111111111111111111111".parse().unwrap()),
168 Token::FixedBytes(
169 "00000000000000000aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".from_hex().unwrap()
170 ),
171 Token::FixedBytes(
172 "00000000000000000bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb".from_hex().unwrap()
173 ),
174 Token::FixedBytes(
175 "00000000000000000ccccccccccccccccccccccccccccccccccccccccccccccc".from_hex().unwrap()
176 ),
177 ]
178 )
179 }
180}