blueprint_evm_extra/extract/
event.rs1use alloy_rpc_types::Log;
7use alloy_sol_types::SolEvent;
8use blueprint_core::{
9 __composite_rejection as composite_rejection, __define_rejection as define_rejection,
10 __impl_deref as impl_deref, __impl_deref_vec as impl_deref_vec, __impl_from as impl_from,
11 FromJobCallParts, job::call::Parts as JobCallParts,
12};
13
14#[derive(Debug, Clone)]
16pub struct BlockEvents(pub Vec<Log>);
17
18impl_deref!(BlockEvents: Vec<Log>);
19impl_from!(Vec<Log>, BlockEvents);
20
21define_rejection! {
22 #[body = "No events found in the extensions"]
23 pub struct MissingBlockEvents;
26}
27
28impl TryFrom<&mut JobCallParts> for BlockEvents {
29 type Error = MissingBlockEvents;
30
31 fn try_from(parts: &mut JobCallParts) -> Result<Self, Self::Error> {
32 let events = parts
33 .extensions
34 .get::<Vec<Log>>()
35 .ok_or(MissingBlockEvents)?;
36 Ok(BlockEvents(events.clone()))
37 }
38}
39
40impl<Ctx> FromJobCallParts<Ctx> for BlockEvents
41where
42 Ctx: Send + Sync,
43{
44 type Rejection = MissingBlockEvents;
45
46 async fn from_job_call_parts(
47 parts: &mut JobCallParts,
48 _: &Ctx,
49 ) -> Result<Self, Self::Rejection> {
50 Self::try_from(parts)
51 }
52}
53
54#[derive(Debug)]
56pub struct Events<T>(pub Vec<T>);
57
58impl_deref_vec!(Events);
59
60define_rejection! {
61 #[body = "Failed to decode events"]
62 pub struct EventDecodingError;
64}
65
66composite_rejection! {
67 pub enum EventRejection {
69 MissingBlockEvents,
70 EventDecodingError,
71 }
72}
73
74impl<T> TryFrom<&mut JobCallParts> for Events<T>
75where
76 T: SolEvent + Clone,
77{
78 type Error = EventRejection;
79
80 fn try_from(parts: &mut JobCallParts) -> Result<Self, Self::Error> {
81 let logs = parts
82 .extensions
83 .get::<Vec<Log>>()
84 .ok_or(MissingBlockEvents)?;
85
86 let events = logs
87 .iter()
88 .filter(|log| T::SIGNATURE_HASH == log.topics()[0])
89 .filter_map(|log| T::decode_log(&log.inner, true).ok())
90 .map(|event| event.data)
91 .collect();
92
93 Ok(Events(events))
94 }
95}
96
97impl<Ctx, T> FromJobCallParts<Ctx> for Events<T>
98where
99 Ctx: Send + Sync,
100 T: SolEvent + Clone + Send + Sync,
101{
102 type Rejection = EventRejection;
103
104 async fn from_job_call_parts(
105 parts: &mut JobCallParts,
106 _: &Ctx,
107 ) -> Result<Self, Self::Rejection> {
108 Self::try_from(parts)
109 }
110}
111
112#[derive(Debug, Clone)]
114pub struct FirstEvent<T>(pub T);
115
116impl_deref!(FirstEvent);
117
118impl<T: SolEvent + Clone> TryFrom<&mut JobCallParts> for FirstEvent<T> {
119 type Error = EventRejection;
120
121 fn try_from(parts: &mut JobCallParts) -> Result<Self, Self::Error> {
122 let logs = parts
123 .extensions
124 .get::<Vec<Log>>()
125 .ok_or(MissingBlockEvents)?;
126
127 let first_t = logs
128 .iter()
129 .find_map(|log| {
130 if Some(&T::SIGNATURE_HASH) == log.topic0() {
131 T::decode_log(&log.inner, true).ok()
132 } else {
133 None
134 }
135 })
136 .ok_or(EventDecodingError)?;
137
138 Ok(FirstEvent(first_t.data))
139 }
140}
141
142impl<Ctx, T> FromJobCallParts<Ctx> for FirstEvent<T>
143where
144 Ctx: Send + Sync,
145 T: SolEvent + Clone + Send + Sync,
146{
147 type Rejection = EventRejection;
148
149 async fn from_job_call_parts(
150 parts: &mut JobCallParts,
151 _: &Ctx,
152 ) -> Result<Self, Self::Rejection> {
153 Self::try_from(parts)
154 }
155}
156
157#[derive(Debug, Clone)]
159pub struct LastEvent<T>(pub T);
160
161impl_deref!(LastEvent);
162
163impl<T: SolEvent + Clone> TryFrom<&mut JobCallParts> for LastEvent<T> {
164 type Error = EventRejection;
165
166 fn try_from(parts: &mut JobCallParts) -> Result<Self, Self::Error> {
167 let logs = parts
168 .extensions
169 .get::<Vec<Log>>()
170 .ok_or(MissingBlockEvents)?;
171
172 let last_t = logs
173 .iter()
174 .rev()
175 .find_map(|log| {
176 if Some(&T::SIGNATURE_HASH) == log.topic0() {
177 T::decode_log(&log.inner, true).ok()
178 } else {
179 None
180 }
181 })
182 .ok_or(EventDecodingError)?;
183
184 Ok(LastEvent(last_t.data))
185 }
186}
187
188impl<Ctx, T> FromJobCallParts<Ctx> for LastEvent<T>
189where
190 Ctx: Send + Sync,
191 T: SolEvent + Clone + Send + Sync,
192{
193 type Rejection = EventRejection;
194
195 async fn from_job_call_parts(
196 parts: &mut JobCallParts,
197 _: &Ctx,
198 ) -> Result<Self, Self::Rejection> {
199 Self::try_from(parts)
200 }
201}