1mod constants;
2mod ibc;
3pub use constants::*;
4pub use ibc::*;
5
6use crate::prelude::*;
7
8pub enum CosmosTxEvents<'a> {
12 TxResponseRef(&'a layer_climb_proto::abci::TxResponse),
13 TxResponseOwned(Box<layer_climb_proto::abci::TxResponse>),
14 Tendermint2ListRef(&'a [tendermint::abci::Event]),
16 Tendermint2ListOwned(Box<Vec<tendermint::abci::Event>>),
17 CosmWasmRef(&'a [cosmwasm_std::Event]),
18 CosmWasmOwned(Box<Vec<cosmwasm_std::Event>>),
19}
20
21impl<'a> From<&'a layer_climb_proto::abci::TxResponse> for CosmosTxEvents<'a> {
22 fn from(resp: &'a layer_climb_proto::abci::TxResponse) -> Self {
23 CosmosTxEvents::TxResponseRef(resp)
24 }
25}
26
27impl From<layer_climb_proto::abci::TxResponse> for CosmosTxEvents<'static> {
28 fn from(resp: layer_climb_proto::abci::TxResponse) -> Self {
29 CosmosTxEvents::TxResponseOwned(Box::new(resp))
30 }
31}
32
33impl<'a> From<&'a [tendermint::abci::Event]> for CosmosTxEvents<'a> {
34 fn from(events: &'a [tendermint::abci::Event]) -> Self {
35 CosmosTxEvents::Tendermint2ListRef(events)
36 }
37}
38
39impl From<Vec<cosmwasm_std::Event>> for CosmosTxEvents<'static> {
40 fn from(events: Vec<cosmwasm_std::Event>) -> Self {
41 CosmosTxEvents::CosmWasmOwned(Box::new(events))
42 }
43}
44
45impl<'a> From<&'a [cosmwasm_std::Event]> for CosmosTxEvents<'a> {
46 fn from(events: &'a [cosmwasm_std::Event]) -> Self {
47 CosmosTxEvents::CosmWasmRef(events)
48 }
49}
50
51impl From<Vec<tendermint::abci::Event>> for CosmosTxEvents<'static> {
52 fn from(events: Vec<tendermint::abci::Event>) -> Self {
53 CosmosTxEvents::Tendermint2ListOwned(Box::new(events))
54 }
55}
56
57#[derive(Clone)]
59pub enum Event<'a> {
60 String(&'a layer_climb_proto::abci::StringEvent),
61 Tendermint(&'a layer_climb_proto::tendermint::Event),
63 Tendermint2(&'a tendermint::abci::Event),
65 CosmWasm(&'a cosmwasm_std::Event),
66}
67
68impl<'a> From<&'a layer_climb_proto::abci::StringEvent> for Event<'a> {
69 fn from(event: &'a layer_climb_proto::abci::StringEvent) -> Self {
70 Event::String(event)
71 }
72}
73
74impl<'a> From<&'a layer_climb_proto::tendermint::Event> for Event<'a> {
75 fn from(event: &'a layer_climb_proto::tendermint::Event) -> Self {
76 Event::Tendermint(event)
77 }
78}
79
80impl<'a> From<&'a tendermint::abci::Event> for Event<'a> {
81 fn from(event: &'a tendermint::abci::Event) -> Self {
82 Event::Tendermint2(event)
83 }
84}
85
86impl<'a> From<&'a cosmwasm_std::Event> for Event<'a> {
87 fn from(event: &'a cosmwasm_std::Event) -> Self {
88 Event::CosmWasm(event)
89 }
90}
91
92impl<'a> From<Event<'a>> for cosmwasm_std::Event {
93 fn from(event: Event<'a>) -> cosmwasm_std::Event {
94 cosmwasm_std::Event::new(event.ty()).add_attributes(event.attributes())
95 }
96}
97
98impl std::fmt::Debug for Event<'_> {
99 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100 if f.alternate() {
101 match self {
102 Event::String(e) => write!(f, "{e:#?}"),
103 Event::Tendermint(e) => write!(f, "{e:#?}"),
104 Event::Tendermint2(e) => write!(f, "{e:#?}"),
105 Event::CosmWasm(e) => write!(f, "{e:#?}"),
106 }
107 } else {
108 match self {
109 Event::String(e) => write!(f, "{e:?}"),
110 Event::Tendermint(e) => write!(f, "{e:?}"),
111 Event::Tendermint2(e) => write!(f, "{e:?}"),
112 Event::CosmWasm(e) => write!(f, "{e:?}"),
113 }
114 }
115 }
116}
117
118pub enum Attribute<'a> {
119 String(&'a layer_climb_proto::abci::Attribute),
120 Tendermint(&'a layer_climb_proto::tendermint::EventAttribute),
122 Tendermint2(&'a tendermint::abci::EventAttribute),
124 CosmWasm(&'a cosmwasm_std::Attribute),
125}
126
127impl<'a> From<Attribute<'a>> for cosmwasm_std::Attribute {
128 fn from(attr: Attribute<'a>) -> Self {
129 cosmwasm_std::Attribute {
130 key: attr.key().to_string(),
131 value: attr.value().to_string(),
132 }
133 }
134}
135
136impl<'a> Event<'a> {
137 pub fn ty(&self) -> &str {
138 match self {
139 Event::String(e) => &e.r#type,
140 Event::Tendermint(e) => &e.r#type,
141 Event::Tendermint2(e) => &e.kind,
142 Event::CosmWasm(e) => &e.ty,
143 }
144 }
145
146 pub fn attributes(&self) -> Box<dyn Iterator<Item = Attribute<'a>> + 'a> {
147 match self {
148 Event::String(e) => Box::new(e.attributes.iter().map(Attribute::String)),
149 Event::Tendermint(e) => Box::new(e.attributes.iter().map(Attribute::Tendermint)),
150 Event::Tendermint2(e) => Box::new(e.attributes.iter().map(Attribute::Tendermint2)),
151 Event::CosmWasm(e) => Box::new(e.attributes.iter().map(Attribute::CosmWasm)),
152 }
153 }
154
155 pub fn is_type(&self, ty: &str) -> bool {
156 let self_ty = self.ty();
157
158 if self_ty == ty {
159 true
160 } else {
161 self_ty == format!("wasm-{ty}")
162 }
163 }
164}
165
166impl Attribute<'_> {
167 pub fn key(&self) -> &str {
168 match self {
169 Attribute::String(a) => &a.key,
170 Attribute::Tendermint(a) => &a.key,
171 Attribute::Tendermint2(a) => a.key_str().unwrap(),
172 Attribute::CosmWasm(a) => &a.key,
173 }
174 }
175
176 pub fn value(&self) -> &str {
177 match self {
178 Attribute::String(a) => &a.value,
179 Attribute::Tendermint(a) => &a.value,
180 Attribute::Tendermint2(a) => a.value_str().unwrap(),
181 Attribute::CosmWasm(a) => &a.value,
182 }
183 }
184}
185
186impl<'a> CosmosTxEvents<'a> {
187 pub fn events_iter(&'a self) -> Box<dyn Iterator<Item = Event<'a>> + 'a> {
188 match &self {
189 Self::TxResponseRef(resp) => {
190 if resp.logs.len() > 1 {
191 Box::new(
192 resp.logs
193 .iter()
194 .flat_map(|log| log.events.iter().map(Event::String)),
195 )
196 } else {
197 Box::new(resp.events.iter().map(Event::Tendermint))
198 }
199 }
200 Self::TxResponseOwned(resp) => {
201 if resp.logs.len() > 1 {
202 Box::new(
203 resp.logs
204 .iter()
205 .flat_map(|log| log.events.iter().map(Event::String)),
206 )
207 } else {
208 Box::new(resp.events.iter().map(Event::Tendermint))
209 }
210 }
211 Self::Tendermint2ListRef(events) => Box::new(events.iter().map(Event::Tendermint2)),
212 Self::Tendermint2ListOwned(events) => Box::new(events.iter().map(Event::Tendermint2)),
213 Self::CosmWasmRef(events) => Box::new(events.iter().map(Event::CosmWasm)),
214 Self::CosmWasmOwned(events) => Box::new(events.iter().map(Event::CosmWasm)),
215 }
216 }
217
218 pub fn filter_events_by_type<'b: 'a>(
219 &'a self,
220 ty: &'b str,
221 ) -> impl Iterator<Item = Event<'a>> + 'a {
222 self.events_iter().filter(move |e| e.is_type(ty))
223 }
224
225 pub fn filter_events_by_attr_key<'b: 'a>(
226 &'a self,
227 ty: &'b str,
228 key: &'b str,
229 ) -> impl Iterator<Item = Event<'a>> + 'a {
230 self.events_iter().filter(move |e| {
231 if e.is_type(ty) {
232 e.attributes().any(|a| a.key() == key)
233 } else {
234 false
235 }
236 })
237 }
238
239 pub fn filter_attrs<'b: 'a>(
240 &'a self,
241 ty: &'b str,
242 key: &'b str,
243 ) -> impl Iterator<Item = Attribute<'a>> + 'a {
244 self.events_iter().filter_map(move |e| {
245 if e.is_type(ty) {
246 e.attributes().find(|a| a.key() == key)
247 } else {
248 None
249 }
250 })
251 }
252
253 pub fn filter_map_attrs<'b: 'a, T, F>(
254 &'a self,
255 ty: &'b str,
256 key: &'b str,
257 f: F,
258 ) -> impl Iterator<Item = T> + 'a
259 where
260 F: Clone + Fn(Attribute<'a>) -> Option<T> + 'a,
261 T: 'static,
262 {
263 self.events_iter().filter_map(move |e| {
264 if e.is_type(ty) {
265 e.attributes().find(|a| a.key() == key).and_then(f.clone())
266 } else {
267 None
268 }
269 })
270 }
271
272 pub fn event_first_by_type<'b: 'a>(&'a self, ty: &'b str) -> Result<Event<'a>> {
273 self.filter_events_by_type(ty)
274 .next()
275 .ok_or_else(|| anyhow!("couldn't find event for {}", ty))
276 }
277
278 pub fn event_first_by_attr_key<'b: 'a>(
279 &'a self,
280 ty: &'b str,
281 key: &'b str,
282 ) -> Result<Event<'a>> {
283 self.filter_events_by_attr_key(ty, key)
284 .next()
285 .ok_or_else(|| anyhow!("couldn't find event for {}.{}", ty, key))
286 }
287
288 pub fn attr_first<'b: 'a>(&'a self, ty: &'b str, key: &'b str) -> Result<Attribute<'a>> {
289 self.filter_attrs(ty, key)
290 .next()
291 .ok_or_else(|| anyhow!("couldn't find event attribute for {}.{}", ty, key))
292 }
293
294 pub fn map_attr_first<'b: 'a, T, F>(&'a self, ty: &'b str, key: &'b str, f: F) -> Result<T>
295 where
296 F: Clone + Fn(Attribute<'a>) -> Option<T> + 'a,
297 T: 'static,
298 {
299 self.filter_map_attrs(ty, key, f)
300 .next()
301 .ok_or_else(|| anyhow!("couldn't find attribute for {}.{}", ty, key))
302 }
303
304 pub fn event_last_by_type<'b: 'a>(&'a self, ty: &'b str) -> Result<Event<'a>> {
305 self.filter_events_by_type(ty)
306 .last()
307 .ok_or_else(|| anyhow!("couldn't find event for {}", ty))
308 }
309
310 pub fn event_last_by_attr_key<'b: 'a>(
311 &'a self,
312 ty: &'b str,
313 key: &'b str,
314 ) -> Result<Event<'a>> {
315 self.filter_events_by_attr_key(ty, key)
316 .last()
317 .ok_or_else(|| anyhow!("couldn't find event for {}.{}", ty, key))
318 }
319
320 pub fn attr_last<'b: 'a>(&'a self, ty: &'b str, key: &'b str) -> Result<Attribute<'a>> {
321 self.filter_attrs(ty, key)
322 .last()
323 .ok_or_else(|| anyhow!("couldn't find event attribute for {}.{}", ty, key))
324 }
325
326 pub fn map_attr_last<'b: 'a, T, F>(&'a self, ty: &'b str, key: &'b str, f: F) -> Result<T>
327 where
328 F: Clone + Fn(Attribute<'a>) -> Option<T> + 'a,
329 T: 'static,
330 {
331 self.filter_map_attrs(ty, key, f)
332 .last()
333 .ok_or_else(|| anyhow!("couldn't find attribute for {}.{}", ty, key))
334 }
335}