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// }