1use chrono::{DateTime, NaiveDateTime, Utc};
2use cosmwasm_std::StdResult;
3use serde::de;
4use serde::de::Visitor;
5use serde::{ser, Deserialize, Deserializer, Serialize, Serializer};
6
7use std::fmt;
8use std::str::FromStr;
9
10use prost::Message;
11#[derive(Clone, Copy, PartialEq, Eq, ::prost::Message, schemars::JsonSchema)]
12pub struct Timestamp {
13 #[prost(int64, tag = "1")]
17 pub seconds: i64,
18 #[prost(int32, tag = "2")]
23 pub nanos: i32,
24}
25
26impl Serialize for Timestamp {
27 fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
28 where
29 S: Serializer,
30 {
31 let mut ts = prost_types::Timestamp {
32 seconds: self.seconds,
33 nanos: self.nanos,
34 };
35 ts.normalize();
36 let dt = NaiveDateTime::from_timestamp_opt(ts.seconds, ts.nanos as u32).unwrap();
37 let dt: DateTime<Utc> = DateTime::from_naive_utc_and_offset(dt, Utc);
38 serializer.serialize_str(format!("{:?}", dt).as_str())
39 }
40}
41
42impl<'de> Deserialize<'de> for Timestamp {
43 fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
44 where
45 D: Deserializer<'de>,
46 {
47 struct TimestampVisitor;
48
49 impl<'de> Visitor<'de> for TimestampVisitor {
50 type Value = Timestamp;
51
52 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
53 formatter.write_str("Timestamp in RFC3339 format")
54 }
55
56 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
57 where
58 E: de::Error,
59 {
60 let utc: DateTime<Utc> = chrono::DateTime::from_str(value)
61 .map_err(|err| serde::de::Error::custom(format!("Failed to parse {} as datetime: {:?}", value, err)))?;
62 let ts = Timestamp::from(utc);
63 Ok(ts)
64 }
65 }
66 deserializer.deserialize_str(TimestampVisitor)
67 }
68}
69
70impl From<DateTime<Utc>> for Timestamp {
71 fn from(dt: DateTime<Utc>) -> Self {
72 Timestamp {
73 seconds: dt.timestamp(),
74 nanos: dt.timestamp_subsec_nanos() as i32,
75 }
76 }
77}
78#[derive(Clone, Copy, PartialEq, Eq, ::prost::Message, schemars::JsonSchema)]
79pub struct Duration {
80 #[prost(int64, tag = "1")]
84 pub seconds: i64,
85 #[prost(int32, tag = "2")]
92 pub nanos: i32,
93}
94
95impl Serialize for Duration {
96 fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
97 where
98 S: Serializer,
99 {
100 let mut d = prost_types::Duration::from(self.to_owned());
101 d.normalize();
102
103 serializer.serialize_str(d.to_string().as_str())
104 }
105}
106
107impl<'de> Deserialize<'de> for Duration {
108 fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
109 where
110 D: Deserializer<'de>,
111 {
112 struct DurationVisitor;
113
114 impl<'de> Visitor<'de> for DurationVisitor {
115 type Value = Duration;
116
117 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
118 formatter.write_str("Timestamp in RFC3339 format")
119 }
120
121 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
122 where
123 E: de::Error,
124 {
125 value.parse::<prost_types::Duration>().map(Into::into).map_err(de::Error::custom)
126 }
127 }
128 deserializer.deserialize_str(DurationVisitor)
129 }
130}
131
132#[derive(Clone, PartialEq, Eq, ::prost::Message, schemars::JsonSchema)]
133pub struct Any {
134 #[prost(string, tag = "1")]
163 pub type_url: ::prost::alloc::string::String,
164 #[prost(bytes = "vec", tag = "2")]
166 pub value: ::prost::alloc::vec::Vec<u8>,
167}
168
169macro_rules! expand_as_any {
170 ($($ty:path,)*) => {
171
172 impl Serialize for Any {
174 fn serialize<S>(
175 &self,
176 serializer: S,
177 ) -> Result<<S as ::serde::Serializer>::Ok, <S as ::serde::Serializer>::Error>
178 where
179 S: ::serde::Serializer,
180 {
181 $(
182 if self.type_url == <$ty>::TYPE_URL {
183 let value: Result<$ty, <S as ::serde::Serializer>::Error> =
184 prost::Message::decode(self.value.as_slice()).map_err(ser::Error::custom);
185
186 if let Ok(value) = value {
187 return value.serialize(serializer);
188 }
189 }
190 )*
191
192 Err(serde::ser::Error::custom(
193 "data did not match any type that supports serialization as `Any`",
194 ))
195 }
196 }
197
198 impl<'de> Deserialize<'de> for Any {
199 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
200 where
201 D: serde::Deserializer<'de>,
202 {
203 let value = match serde_cw_value::Value::deserialize(deserializer) {
204 Ok(value) => value,
205 Err(err) => {
206 return Err(err);
207 }
208 };
209
210 let type_url = if let serde_cw_value::Value::Map(m) = value.clone() {
212 m.get(&serde_cw_value::Value::String("@type".to_string()))
213 .map(|t| match t.to_owned() {
214 serde_cw_value::Value::String(s) => Ok(s),
215 _ => Err(serde::de::Error::custom("type_url must be String")),
216 })
217 .transpose()
218 } else {
219 Err(serde::de::Error::custom("data must have map structure"))
220 }?;
221
222 match type_url {
223 Some(t) => {
225 $(
226 if t == <$ty>::TYPE_URL {
227 return <$ty>::deserialize(
228 serde_cw_value::ValueDeserializer::<serde_cw_value::DeserializerError>::new(
229 value.clone(),
230 ),
231 )
232 .map(|v| Any {
233 type_url: <$ty>::TYPE_URL.to_string(),
234 value: v.encode_to_vec(),
235 })
236 .map_err(serde::de::Error::custom);
237 }
238 )*
239 }
240 None => {
242 $(
243 if let Ok(v) = <$ty>::deserialize(
244 serde_cw_value::ValueDeserializer::<serde_cw_value::DeserializerError>::new(
245 value.clone(),
246 ),
247 ) {
248 return Ok(Any {
249 type_url: <$ty>::TYPE_URL.to_string(),
250 value: v.encode_to_vec(),
251 });
252 }
253 )*
254 }
255 };
256
257 Err(serde::de::Error::custom(
258 "data did not match any type that supports deserialization as `Any`",
259 ))
260 }
261 }
262
263 $(
264 impl TryFrom<Any> for $ty {
265 type Error = prost::DecodeError;
266
267 fn try_from(value: Any) -> Result<Self, Self::Error> {
268 prost::Message::decode(value.value.as_slice())
269 }
270 }
271 )*
272 };
273}
274
275expand_as_any!(crate::types::injective::tokenfactory::v1beta1::MsgMint,);
280
281macro_rules! impl_prost_types_exact_conversion {
282 ($t:ident | $($arg:ident),*) => {
283 impl From<$t> for prost_types::$t {
284 fn from(src: $t) -> Self {
285 prost_types::$t {
286 $(
287 $arg: src.$arg,
288 )*
289 }
290 }
291 }
292
293 impl From<prost_types::$t> for $t {
294 fn from(src: prost_types::$t) -> Self {
295 $t {
296 $(
297 $arg: src.$arg,
298 )*
299 }
300 }
301 }
302 };
303}
304
305impl_prost_types_exact_conversion! { Timestamp | seconds, nanos }
306impl_prost_types_exact_conversion! { Duration | seconds, nanos }
307impl_prost_types_exact_conversion! { Any | type_url, value }
308
309impl From<cosmwasm_std::Coin> for crate::types::cosmos::base::v1beta1::Coin {
310 fn from(cosmwasm_std::Coin { denom, amount }: cosmwasm_std::Coin) -> Self {
311 crate::types::cosmos::base::v1beta1::Coin {
312 denom,
313 amount: amount.into(),
314 }
315 }
316}
317
318impl TryFrom<crate::types::cosmos::base::v1beta1::Coin> for cosmwasm_std::Coin {
319 type Error = cosmwasm_std::StdError;
320
321 fn try_from(
322 crate::types::cosmos::base::v1beta1::Coin { denom, amount }: crate::types::cosmos::base::v1beta1::Coin,
323 ) -> cosmwasm_std::StdResult<Self> {
324 Ok(cosmwasm_std::Coin {
325 denom,
326 amount: amount.parse()?,
327 })
328 }
329}
330
331pub fn try_proto_to_cosmwasm_coins(coins: impl IntoIterator<Item = crate::types::cosmos::base::v1beta1::Coin>) -> StdResult<Vec<cosmwasm_std::Coin>> {
333 coins.into_iter().map(|c| c.try_into()).collect()
334}
335
336pub fn cosmwasm_to_proto_coins(coins: impl IntoIterator<Item = cosmwasm_std::Coin>) -> Vec<crate::types::cosmos::base::v1beta1::Coin> {
338 coins.into_iter().map(|c| c.into()).collect()
339}
340
341#[cfg(test)]
342mod tests {
343 use cosmwasm_std::Uint128;
344
345 use super::*;
346
347 #[test]
348 fn test_coins_conversion() {
349 let coins = vec![
350 cosmwasm_std::Coin {
351 denom: "uatom".to_string(),
352 amount: Uint128::new(100),
353 },
354 cosmwasm_std::Coin {
355 denom: "uosmo".to_string(),
356 amount: Uint128::new(200),
357 },
358 ];
359
360 let proto_coins = cosmwasm_to_proto_coins(coins.clone());
361 let cosmwasm_coins = try_proto_to_cosmwasm_coins(proto_coins).unwrap();
362
363 assert_eq!(coins, cosmwasm_coins);
364 }
365}