1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use std::str::FromStr;

use core::fmt::Debug;
use cosmwasm_std::{Event, StdError, StdResult, SubMsgResponse};

/// Parse an attribute string from an [`Event`]
pub fn parse_attribute_value<T: FromStr<Err = E>, E: Debug>(
    event: &Event,
    attr_key: &str,
) -> StdResult<T> {
    T::from_str(
        event
            .attributes
            .iter()
            .find(|attr| attr.key == attr_key)
            .ok_or_else(|| {
                StdError::generic_err(format!(
                    "Event {} event does not contain {} attribute",
                    event.ty, attr_key
                ))
            })?
            .value
            .as_str(),
    )
    .map_err(|e| {
        StdError::generic_err(format!(
            "Failed to parse attribute value from string. Error: {:?}",
            e
        ))
    })
}

/// Find event from SubMsg response
///
/// Returns a [`StdResult`] containing reference to the event if found otherwise
/// [`StdError`]
pub fn find_event<'a>(res: &'a SubMsgResponse, event_type: &str) -> StdResult<&'a Event> {
    res.events
        .iter()
        .find(|event| event.ty == event_type)
        .ok_or(StdError::generic_err(format!(
            "No `{}` event found",
            event_type
        )))
}

#[cfg(test)]
mod tests {
    use std::num::ParseIntError;

    use cosmwasm_std::Attribute;

    use super::*;

    #[test]
    fn test_find_event_success() {
        let event1 = Event::new("event_type_1");
        let event2 = Event::new("event_type_2");
        let events = vec![event1, event2];
        let res = SubMsgResponse { events, data: None };
        let result = find_event(&res, "event_type_1");
        assert!(result.is_ok());
        let found_event = result.unwrap();
        assert_eq!(found_event.ty, "event_type_1");
    }

    #[test]
    fn test_find_event_not_found() {
        let event1 = Event::new("event_type_1");
        let event2 = Event::new("event_type_2");
        let events = vec![event1, event2];
        let res = SubMsgResponse { events, data: None };
        let result = find_event(&res, "event_type_3");
        assert!(result.is_err());
        let err = result.unwrap_err();
        assert_eq!(
            err.to_string(),
            "Generic error: No `event_type_3` event found"
        );
    }

    #[test]
    fn test_parse_attribute_value_success() {
        let attr1 = Attribute::new("key_1", "value_1");
        let attr2 = Attribute::new("key_2", "2");
        let attributes = vec![attr1, attr2];
        let event = Event::new("event_type").add_attributes(attributes);

        let result = parse_attribute_value::<i32, ParseIntError>(&event, "key_2");
        assert!(result.is_ok());
        let parsed_value = result.unwrap();
        assert_eq!(parsed_value, 2);
    }

    #[test]
    fn test_parse_attribute_value_not_found() {
        let attr1 = Attribute::new("key_1", "value_1");
        let attr2 = Attribute::new("key_2", "2");
        let attributes = vec![attr1, attr2];
        let event = Event::new("event_type").add_attributes(attributes);

        let result = parse_attribute_value::<i32, ParseIntError>(&event, "key_3");
        assert!(result.is_err());
        let err = result.unwrap_err();
        assert_eq!(
            err.to_string(),
            "Generic error: Event event_type event does not contain key_3 attribute"
        );
    }

    #[test]
    fn test_parse_attribute_value_parse_error() {
        let attr1 = Attribute::new("key_1", "value_1");
        let attr2 = Attribute::new("key_2", "not_a_number");
        let attributes = vec![attr1, attr2];
        let event = Event::new("event_type").add_attributes(attributes);

        let result = parse_attribute_value::<i32, ParseIntError>(&event, "key_2");
        assert!(result.is_err());
        let err = result.unwrap_err();
        assert_eq!(
            err.to_string(),
            "Generic error: Failed to parse attribute value from string. Error: ParseIntError { kind: InvalidDigit }"
        );
    }
}