cosm_utils/chain/
response.rs

1use cosmrs::proto::cosmos::base::abci::v1beta1::TxResponse as CosmosResponse;
2
3use cosmrs::rpc::endpoint::{
4    abci_query::AbciQuery, broadcast::tx_async::Response as AsyncTendermintResponse,
5    broadcast::tx_sync::Response as SyncTendermintResponse,
6};
7use cosmrs::tendermint::abci::Code as TendermintCode;
8use schemars::JsonSchema;
9use serde::{Deserialize, Serialize};
10
11use super::error::DeserializeError;
12
13#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Eq, PartialEq, Default)]
14pub struct ChainResponse {
15    pub code: Code,
16    pub data: Option<Vec<u8>>,
17    pub log: String,
18}
19
20impl ChainResponse {
21    pub fn data<'a, T: Deserialize<'a>>(&'a self) -> Result<T, DeserializeError> {
22        let r: T = serde_json::from_slice(
23            self.data
24                .as_ref()
25                .ok_or(DeserializeError::EmptyResponse)?
26                .as_slice(),
27        )?;
28        Ok(r)
29    }
30}
31
32impl From<AbciQuery> for ChainResponse {
33    fn from(res: AbciQuery) -> ChainResponse {
34        ChainResponse {
35            code: res.code.into(),
36            data: Some(res.value),
37            log: res.log,
38        }
39    }
40}
41
42// impl From<TxResult> for ChainResponse {
43//     fn from(res: TxResult) -> ChainResponse {
44//         ChainResponse {
45//             code: res.code.into(),
46//             data: res.data.map(|d| d.into()),
47//             log: res.log.to_string(),
48//         }
49//     }
50// }
51
52/// AsyncChainTxResponse is returned from the async `tx_broadcast()` api.
53#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Eq, PartialEq, Default)]
54pub struct AsyncChainTxResponse {
55    pub res: ChainResponse,
56    pub tx_hash: String,
57}
58
59impl AsRef<ChainResponse> for AsyncChainTxResponse {
60    fn as_ref(&self) -> &ChainResponse {
61        &self.res
62    }
63}
64
65impl From<CosmosResponse> for AsyncChainTxResponse {
66    fn from(res: CosmosResponse) -> Self {
67        Self {
68            res: ChainResponse {
69                code: res.code.into(),
70                data: Some(res.data.into()), // TODO
71                log: res.raw_log,
72            },
73            tx_hash: res.txhash,
74        }
75    }
76}
77
78impl From<AsyncTendermintResponse> for AsyncChainTxResponse {
79    fn from(res: AsyncTendermintResponse) -> Self {
80        Self {
81            res: ChainResponse {
82                code: res.code.into(),
83                data: Some(res.data.into()),
84                log: res.log.to_string(),
85            },
86            tx_hash: res.hash.to_string(),
87        }
88    }
89}
90
91impl From<SyncTendermintResponse> for AsyncChainTxResponse {
92    fn from(res: SyncTendermintResponse) -> Self {
93        Self {
94            res: ChainResponse {
95                code: res.code.into(),
96                data: Some(res.data.into()),
97                log: res.log.to_string(),
98            },
99            tx_hash: res.hash.to_string(),
100        }
101    }
102}
103
104// /// ChainTxResponse is returned from the blocking `tx_broadcast_block()` api.
105// /// Since we wait for the tx to be commited in the next block, we get the full tx data.
106// #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Eq, PartialEq, Default)]
107// pub struct ChainTxResponse {
108//     pub res: ChainResponse,
109//     pub events: Vec<Event>,
110//     pub gas_wanted: u64,
111//     pub gas_used: u64,
112//     pub tx_hash: String,
113//     pub height: u64,
114// }
115
116// impl AsRef<ChainResponse> for ChainTxResponse {
117//     fn as_ref(&self) -> &ChainResponse {
118//         &self.res
119//     }
120// }
121
122// impl From<BlockingTendermintResponse> for ChainTxResponse {
123//     fn from(res: BlockingTendermintResponse) -> Self {
124//         ChainTxResponse {
125//             res: ChainResponse {
126//                 code: res.deliver_tx.code.into(),
127//                 data: Some(res.deliver_tx.data.to_vec()),
128//                 log: res.deliver_tx.log.to_string(),
129//             },
130//             events: res.deliver_tx.events.into_iter().map(Into::into).collect(),
131//             gas_used: res.deliver_tx.gas_used.into(),
132//             gas_wanted: res.deliver_tx.gas_wanted.into(),
133//             tx_hash: res.hash.to_string(),
134//             height: res.height.into(),
135//         }
136//     }
137// }
138
139// impl TryFrom<CosmosResponse> for ChainTxResponse {
140//     type Error = ChainError;
141
142//     fn try_from(res: CosmosResponse) -> Result<Self, Self::Error> {
143//         Ok(ChainTxResponse {
144//             res: ChainResponse {
145//                 code: res.code.into(),
146//                 data: Some(res.data.into()), // TODO
147//                 log: res.raw_log,
148//             },
149//             events: res
150//                 .events
151//                 .into_iter()
152//                 .map(TryInto::try_into)
153//                 .collect::<Result<Vec<_>, _>>()?,
154//             gas_wanted: res.gas_wanted as u64,
155//             gas_used: res.gas_used as u64,
156//             tx_hash: res.txhash,
157//             height: res.height as u64,
158//         })
159//     }
160// }
161
162#[derive(
163    Copy,
164    Clone,
165    Debug,
166    Default,
167    Eq,
168    Hash,
169    PartialEq,
170    PartialOrd,
171    Ord,
172    Serialize,
173    Deserialize,
174    JsonSchema,
175)]
176pub enum Code {
177    #[default]
178    Ok,
179    Err(u32),
180}
181
182impl Code {
183    pub fn is_ok(self) -> bool {
184        match self {
185            Code::Ok => true,
186            Code::Err(_) => false,
187        }
188    }
189
190    pub fn is_err(self) -> bool {
191        !self.is_ok()
192    }
193
194    pub fn value(self) -> u32 {
195        u32::from(self)
196    }
197}
198
199impl From<u32> for Code {
200    fn from(value: u32) -> Code {
201        match value {
202            0 => Code::Ok,
203            err => Code::Err(err),
204        }
205    }
206}
207
208impl From<Code> for u32 {
209    fn from(code: Code) -> u32 {
210        match code {
211            Code::Ok => 0,
212            Code::Err(err) => err,
213        }
214    }
215}
216
217impl From<u16> for Code {
218    fn from(value: u16) -> Code {
219        match value {
220            0 => Code::Ok,
221            err => Code::Err(err.into()),
222        }
223    }
224}
225
226impl From<u8> for Code {
227    fn from(value: u8) -> Code {
228        match value {
229            0 => Code::Ok,
230            err => Code::Err(err.into()),
231        }
232    }
233}
234
235impl From<TendermintCode> for Code {
236    fn from(value: TendermintCode) -> Code {
237        match value {
238            TendermintCode::Ok => Code::Ok,
239            TendermintCode::Err(err) => Code::Err(err.into()),
240        }
241    }
242}
243
244// #[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)]
245// pub struct Event {
246//     pub kind: String,
247//     pub attributes: Vec<EventAttribute>,
248// }
249
250// impl From<TendermintEvent> for Event {
251//     fn from(e: TendermintEvent) -> Self {
252//         Self {
253//             kind: e.type_str,
254//             attributes: e.attributes.into_iter().map(Into::into).collect(),
255//         }
256//     }
257// }
258
259// impl TryFrom<Event> for TendermintEvent {
260//     type Error = ChainError;
261
262//     fn try_from(e: Event) -> Result<Self, Self::Error> {
263//         Ok(Self {
264//             kind: e.kind,
265//             attributes: e
266//                 .attributes
267//                 .into_iter()
268//                 .map(TryInto::try_into)
269//                 .collect::<Result<Vec<_>, _>>()?,
270//         })
271//     }
272// }
273
274// impl TryFrom<ProtoEvent> for Event {
275//     type Error = ChainError;
276
277//     fn try_from(e: ProtoEvent) -> Result<Self, Self::Error> {
278//         Ok(Self {
279//             kind: e.r#type,
280//             attributes: e
281//                 .attributes
282//                 .into_iter()
283//                 .map(TryInto::try_into)
284//                 .collect::<Result<Vec<_>, _>>()?,
285//         })
286//     }
287// }
288
289// impl From<Event> for ProtoEvent {
290//     fn from(e: Event) -> Self {
291//         Self {
292//             r#type: e.kind,
293//             attributes: e.attributes.into_iter().map(Into::into).collect(),
294//         }
295//     }
296// }
297
298// #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Eq, PartialEq, Hash)]
299// pub struct Tag {
300//     pub key: String,
301//     pub value: String,
302// }
303
304// impl From<TendermintProtoTag> for Tag {
305//     fn from(tag: TendermintProtoTag) -> Self {
306//         Self {
307//             key: tag.key.to_string(),
308//             value: tag.value.to_string(),
309//         }
310//     }
311// }
312
313// impl TryFrom<Tag> for TendermintProtoTag {
314//     type Error = ChainError;
315
316//     fn try_from(tag: Tag) -> Result<Self, Self::Error> {
317//         Ok(Self {
318//             key: Key::from_str(&tag.key)?,
319//             value: Value::from_str(&tag.value)?,
320//         })
321//     }
322// }
323
324// impl From<Tag> for EventAttribute {
325//     fn from(tag: Tag) -> Self {
326//         Self {
327//             key: tag.key.into_bytes().into(),
328//             value: tag.value.into_bytes().into(),
329//             index: true,
330//         }
331//     }
332// }
333
334// impl TryFrom<EventAttribute> for Tag {
335//     type Error = ChainError;
336
337//     fn try_from(attr: EventAttribute) -> Result<Self, Self::Error> {
338//         Ok(Self {
339//             key: String::from_utf8(attr.key.into()).map_err(|e| ChainError::ProtoDecoding {
340//                 message: e.to_string(),
341//             })?,
342//             value: String::from_utf8(attr.value.into()).map_err(|e| ChainError::ProtoDecoding {
343//                 message: e.to_string(),
344//             })?,
345//         })
346//     }
347// }