1use crate::{
2 abi::token::{Token, TokenSeq, WordToken},
3Result, SolType, Word,
4};
5use alloc::vec::Vec;
6use alloy_primitives::{FixedBytes, Log, LogData, B256};
78mod topic;
9pub use topic::EventTopic;
1011mod topic_list;
12pub use topic_list::TopicList;
1314/// Solidity event.
15///
16/// # Implementer's Guide
17///
18/// It should not be necessary to implement this trait manually. Instead, use
19/// the [`sol!`](crate::sol!) procedural macro to parse Solidity syntax into
20/// types that implement this trait.
21pub trait SolEvent: Sized {
22/// The underlying tuple type which represents this event's non-indexed
23 /// parameters. These parameters are ABI encoded and included in the log
24 /// body.
25 ///
26 /// If this event has no non-indexed parameters, this will be the unit type
27 /// `()`.
28type DataTuple<'a>: SolType<Token<'a> = Self::DataToken<'a>>;
2930/// The [`TokenSeq`] type corresponding to the tuple.
31type DataToken<'a>: TokenSeq<'a>;
3233/// The underlying tuple type which represents this event's topics.
34 ///
35 /// These are ABI encoded and included in the log struct returned by the
36 /// RPC node.
37 ///
38 /// See the [`TopicList`] trait for more details.
39type TopicList: TopicList;
4041/// The event's ABI signature.
42 ///
43 /// For anonymous events, this is unused, but is still present.
44const SIGNATURE: &'static str;
4546/// The event's ABI signature hash, or selector: `keccak256(SIGNATURE)`
47 ///
48 /// For non-anonymous events, this will be the first topic (`topic0`).
49 /// For anonymous events, this is unused, but is still present.
50#[doc(alias = "SELECTOR")]
51const SIGNATURE_HASH: FixedBytes<32>;
5253/// Whether the event is anonymous.
54const ANONYMOUS: bool;
5556/// Convert decoded rust data to the event type.
57 ///
58 /// Does not check that `topics[0]` is the correct hash.
59 /// Use [`new_checked`](Self::new_checked) instead.
60fn new(
61 topics: <Self::TopicList as SolType>::RustType,
62 data: <Self::DataTuple<'_> as SolType>::RustType,
63 ) -> Self;
6465/// Convert decoded rust data to the event type.
66 ///
67 /// Checks that `topics[0]` is the correct hash.
68#[inline]
69fn new_checked(
70 topics: <Self::TopicList as SolType>::RustType,
71 data: <Self::DataTuple<'_> as SolType>::RustType,
72 ) -> Result<Self> {
73Self::check_signature(&topics).map(|()| Self::new(topics, data))
74 }
7576/// Check that the event's signature matches the given topics.
77#[inline]
78fn check_signature(topics: &<Self::TopicList as SolType>::RustType) -> Result<()> {
79// Overridden for non-anonymous events in `sol!`.
80let _ = topics;
81Ok(())
82 }
8384/// Tokenize the event's non-indexed parameters.
85fn tokenize_body(&self) -> Self::DataToken<'_>;
8687// TODO: avoid clones here
88/// The event's topics.
89fn topics(&self) -> <Self::TopicList as SolType>::RustType;
9091/// The size of the ABI-encoded dynamic data in bytes.
92#[inline]
93fn abi_encoded_size(&self) -> usize {
94if let Some(size) = <Self::DataTuple<'_> as SolType>::ENCODED_SIZE {
95return size;
96 }
9798self.tokenize_body().total_words() * Word::len_bytes()
99 }
100101/// ABI-encode the dynamic data of this event into the given buffer.
102#[inline]
103fn 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 }
107108/// ABI-encode the dynamic data of this event.
109#[inline]
110fn encode_data(&self) -> Vec<u8> {
111let mut out = Vec::new();
112self.encode_data_to(&mut out);
113 out
114 }
115116/// Encode the topics of this event into the given buffer.
117 ///
118 /// # Errors
119 ///
120 /// This method should return an error only if the buffer is too small.
121fn encode_topics_raw(&self, out: &mut [WordToken]) -> Result<()>;
122123/// Encode the topics of this event.
124 ///
125 /// The returned vector will have length `Self::TopicList::COUNT`.
126#[inline]
127fn encode_topics(&self) -> Vec<WordToken> {
128let mut out = vec![WordToken(B256::ZERO); Self::TopicList::COUNT];
129self.encode_topics_raw(&mut out).unwrap();
130 out
131 }
132133/// Encode the topics of this event into a fixed-size array.
134 ///
135 /// This method will not compile if `LEN` is not equal to `Self::TopicList::COUNT`.
136#[inline]
137fn encode_topics_array<const LEN: usize>(&self) -> [WordToken; LEN] {
138const { assert!(LEN == Self::TopicList::COUNT, "topic list length mismatch") };
139let mut out = [WordToken(B256::ZERO); LEN];
140self.encode_topics_raw(&mut out).unwrap();
141 out
142 }
143144/// Encode this event to a [`LogData`].
145fn encode_log_data(&self) -> LogData {
146 LogData::new_unchecked(
147self.encode_topics().into_iter().map(Into::into).collect(),
148self.encode_data().into(),
149 )
150 }
151152/// Transform ca [`Log`] containing this event into a [`Log`] containing
153 /// [`LogData`].
154fn encode_log(log: &Log<Self>) -> Log<LogData> {
155 Log { address: log.address, data: log.data.encode_log_data() }
156 }
157158/// Decode the topics of this event from the given data.
159#[inline]
160fn decode_topics<I, D>(topics: I) -> Result<<Self::TopicList as SolType>::RustType>
161where
162I: IntoIterator<Item = D>,
163 D: Into<WordToken>,
164 {
165 <Self::TopicList as TopicList>::detokenize(topics)
166 }
167168/// ABI-decodes the dynamic data of this event from the given buffer.
169#[inline]
170fn abi_decode_data<'a>(
171 data: &'a [u8],
172 validate: bool,
173 ) -> Result<<Self::DataTuple<'a> as SolType>::RustType> {
174 <Self::DataTuple<'a> as SolType>::abi_decode_sequence(data, validate)
175 }
176177/// Decode the event from the given log info.
178fn decode_raw_log<I, D>(topics: I, data: &[u8], validate: bool) -> Result<Self>
179where
180I: IntoIterator<Item = D>,
181 D: Into<WordToken>,
182 {
183let topics = Self::decode_topics(topics)?;
184// Check signature before decoding the data.
185Self::check_signature(&topics)?;
186let body = Self::abi_decode_data(data, validate)?;
187Ok(Self::new(topics, body))
188 }
189190/// Decode the event from the given log object.
191fn decode_log_data(log: &LogData, validate: bool) -> Result<Self> {
192Self::decode_raw_log(log.topics(), &log.data, validate)
193 }
194195/// Decode the event from the given log object.
196fn decode_log(log: &Log, validate: bool) -> Result<Log<Self>> {
197Self::decode_log_data(&log.data, validate).map(|data| Log { address: log.address, data })
198 }
199}