alloy_sol_types/types/event/
mod.rs1use crate::{
2 abi::token::{Token, TokenSeq, WordToken},
3 Result, SolType, Word,
4};
5use alloc::vec::Vec;
6use alloy_primitives::{FixedBytes, Log, LogData, B256};
7
8mod topic;
9pub use topic::EventTopic;
10
11mod topic_list;
12pub use topic_list::TopicList;
13
14pub trait SolEvent: Sized {
22 type DataTuple<'a>: SolType<Token<'a> = Self::DataToken<'a>>;
29
30 type DataToken<'a>: TokenSeq<'a>;
32
33 type TopicList: TopicList;
40
41 const SIGNATURE: &'static str;
45
46 #[doc(alias = "SELECTOR")]
51 const SIGNATURE_HASH: FixedBytes<32>;
52
53 const ANONYMOUS: bool;
55
56 fn new(
61 topics: <Self::TopicList as SolType>::RustType,
62 data: <Self::DataTuple<'_> as SolType>::RustType,
63 ) -> Self;
64
65 #[inline]
69 fn new_checked(
70 topics: <Self::TopicList as SolType>::RustType,
71 data: <Self::DataTuple<'_> as SolType>::RustType,
72 ) -> Result<Self> {
73 Self::check_signature(&topics).map(|()| Self::new(topics, data))
74 }
75
76 #[inline]
78 fn check_signature(topics: &<Self::TopicList as SolType>::RustType) -> Result<()> {
79 let _ = topics;
81 Ok(())
82 }
83
84 fn tokenize_body(&self) -> Self::DataToken<'_>;
86
87 fn topics(&self) -> <Self::TopicList as SolType>::RustType;
90
91 #[inline]
93 fn abi_encoded_size(&self) -> usize {
94 if let Some(size) = <Self::DataTuple<'_> as SolType>::ENCODED_SIZE {
95 return size;
96 }
97
98 self.tokenize_body().total_words() * Word::len_bytes()
99 }
100
101 #[inline]
103 fn encode_data_to(&self, out: &mut Vec<u8>) {
104 out.reserve(self.abi_encoded_size());
105 out.extend(crate::abi::encode_sequence(&self.tokenize_body()));
106 }
107
108 #[inline]
110 fn encode_data(&self) -> Vec<u8> {
111 let mut out = Vec::new();
112 self.encode_data_to(&mut out);
113 out
114 }
115
116 fn encode_topics_raw(&self, out: &mut [WordToken]) -> Result<()>;
122
123 #[inline]
127 fn encode_topics(&self) -> Vec<WordToken> {
128 let mut out = vec![WordToken(B256::ZERO); Self::TopicList::COUNT];
129 self.encode_topics_raw(&mut out).unwrap();
130 out
131 }
132
133 #[inline]
137 fn encode_topics_array<const LEN: usize>(&self) -> [WordToken; LEN] {
138 const { assert!(LEN == Self::TopicList::COUNT, "topic list length mismatch") };
139 let mut out = [WordToken(B256::ZERO); LEN];
140 self.encode_topics_raw(&mut out).unwrap();
141 out
142 }
143
144 fn encode_log_data(&self) -> LogData {
146 LogData::new_unchecked(
147 self.encode_topics().into_iter().map(Into::into).collect(),
148 self.encode_data().into(),
149 )
150 }
151
152 fn encode_log(log: &Log<Self>) -> Log<LogData> {
155 Log { address: log.address, data: log.data.encode_log_data() }
156 }
157
158 #[inline]
160 fn decode_topics<I, D>(topics: I) -> Result<<Self::TopicList as SolType>::RustType>
161 where
162 I: IntoIterator<Item = D>,
163 D: Into<WordToken>,
164 {
165 <Self::TopicList as TopicList>::detokenize(topics)
166 }
167
168 #[inline]
170 fn abi_decode_data<'a>(data: &'a [u8]) -> Result<<Self::DataTuple<'a> as SolType>::RustType> {
171 <Self::DataTuple<'a> as SolType>::abi_decode_sequence(data)
172 }
173
174 #[inline]
179 fn abi_decode_data_validate<'a>(
180 data: &'a [u8],
181 ) -> Result<<Self::DataTuple<'a> as SolType>::RustType> {
182 <Self::DataTuple<'a> as SolType>::abi_decode_sequence_validate(data)
183 }
184
185 fn decode_raw_log<I, D>(topics: I, data: &[u8]) -> Result<Self>
187 where
188 I: IntoIterator<Item = D>,
189 D: Into<WordToken>,
190 {
191 let topics = Self::decode_topics(topics)?;
192 Self::check_signature(&topics)?;
194 let body = Self::abi_decode_data(data)?;
195 Ok(Self::new(topics, body))
196 }
197
198 fn decode_raw_log_validate<I, D>(topics: I, data: &[u8]) -> Result<Self>
203 where
204 I: IntoIterator<Item = D>,
205 D: Into<WordToken>,
206 {
207 let topics = Self::decode_topics(topics)?;
208 Self::check_signature(&topics)?;
210 let body = Self::abi_decode_data_validate(data)?;
211 Ok(Self::new(topics, body))
212 }
213
214 fn decode_log_data(log: &LogData) -> Result<Self> {
216 Self::decode_raw_log(log.topics(), &log.data)
217 }
218
219 fn decode_log(log: &Log) -> Result<Log<Self>> {
221 Self::decode_log_data(&log.data).map(|data| Log { address: log.address, data })
222 }
223}