nibiru_std/proto/
traits.rs

1//! nibiru-std::proto - traits.rs : Implements extensions for prost::Message
2//! types for easy conversion to types needed for CosmWasm smart contracts.
3
4use cosmwasm_std::{Binary, CosmosMsg, QueryRequest};
5
6use crate::errors::{NibiruError, NibiruResult};
7
8use crate::proto::cosmos;
9
10pub trait NibiruProstMsg: prost::Message {
11    /// Serialize this protobuf message as a byte vector
12    fn to_bytes(&self) -> Vec<u8>;
13    fn to_binary(&self) -> Binary;
14    /// A type implementing prost::Message is not guaranteed to implement
15    /// prost::Name and have a `Name.type_url()` function. This method attempts
16    /// to downcast the message to prost::Name, and if successful, constructs a
17    /// `CosmosMsg::Stargate` object corresponding to the type.
18    fn try_into_stargate_msg(&self, type_url: &str) -> CosmosMsg {
19        let value = self.to_binary();
20        CosmosMsg::Stargate {
21            type_url: type_url.to_string(),
22            value,
23        }
24    }
25
26    /// Parse into this protobuf type from `prost_types::Any`.
27    fn from_any(any: &prost_types::Any) -> Result<Self, prost::DecodeError>
28    where
29        Self: Default + prost::Name + Sized,
30    {
31        any.to_msg()
32    }
33}
34
35impl<M> NibiruProstMsg for M
36where
37    M: prost::Message,
38{
39    fn to_bytes(&self) -> Vec<u8> {
40        self.encode_to_vec()
41    }
42
43    fn to_binary(&self) -> Binary {
44        Binary::from(self.encode_to_vec())
45    }
46}
47
48pub trait NibiruStargateMsg: prost::Message + prost::Name {
49    #![allow(clippy::wrong_self_convention)]
50    fn into_stargate_msg(&self) -> CosmosMsg;
51
52    fn type_url(&self) -> String;
53}
54
55impl<M> NibiruStargateMsg for M
56where
57    M: prost::Message + prost::Name,
58{
59    /// Returns the `prost::Message` as a `CosmosMsg::Stargate` object.
60    fn into_stargate_msg(&self) -> CosmosMsg {
61        CosmosMsg::Stargate {
62            type_url: self.type_url(),
63            value: self.to_binary(),
64        }
65    }
66
67    /// The "type URL" in the context of protobuf is used with a feature
68    /// called "Any", a type that allows one to serialize and embed proto
69    /// message (prost::Message) objects without as opaque values without having
70    /// to predefine the type in the original message declaration.
71    ///
72    /// For example, a protobuf definition like:
73    /// ```proto
74    /// message CustomProtoMsg { string name = 1; }
75    /// ```
76    /// might have a type URL like "googleapis.com/package.name.CustomProtoMsg".
77    /// Usage of `Any` with type URLs enables dynamic message composition and
78    /// flexibility.
79    ///
80    /// We use these type URLs in CosmWasm and the Cosmos-SDK to classify
81    /// gRPC messages for transactions and queries because Tendermint ABCI
82    /// messages are protobuf objects.
83    fn type_url(&self) -> String {
84        format!("/{}.{}", Self::PACKAGE, Self::NAME)
85    }
86}
87
88pub trait NibiruStargateQuery: prost::Message + prost::Name {
89    #![allow(clippy::wrong_self_convention)]
90    fn into_stargate_query(
91        &self,
92    ) -> NibiruResult<QueryRequest<cosmwasm_std::Empty>>;
93
94    fn path(&self) -> String;
95}
96
97impl<M> NibiruStargateQuery for M
98where
99    M: prost::Message + prost::Name,
100{
101    /// Returns the `prost::Message` as a `QueryRequest::Stargate` object.
102    /// Errors if the `prost::Name::type_url` does not indicate the type is a
103    /// query.
104    fn into_stargate_query(
105        &self,
106    ) -> NibiruResult<QueryRequest<cosmwasm_std::Empty>> {
107        if !self.type_url().contains("Query") {
108            return Err(NibiruError::ProstNameisNotQuery {
109                type_url: self.type_url(),
110            });
111        }
112        Ok(QueryRequest::Stargate {
113            path: self.path(),
114            data: self.to_binary(),
115        })
116    }
117
118    /// Fully qualified gRPC service path used for routing.
119    /// Ex.: "/cosmos.bank.v1beta1.Query/SupplyOf"
120    fn path(&self) -> String {
121        let service_name = format!(
122            "Query/{}",
123            Self::NAME
124                .trim_start_matches("Query")
125                .trim_end_matches("Request")
126        );
127        format!("/{}.{}", Self::PACKAGE, service_name)
128    }
129}
130
131impl From<cosmwasm_std::Coin> for cosmos::base::v1beta1::Coin {
132    fn from(cw_coin: cosmwasm_std::Coin) -> Self {
133        cosmos::base::v1beta1::Coin {
134            denom: cw_coin.denom,
135            amount: cw_coin.amount.to_string(),
136        }
137    }
138}