nym_contracts_common/signing/
mod.rs1use cosmwasm_std::{Addr, Coin, MessageInfo, StdResult, from_json, to_json_vec};
5use schemars::JsonSchema;
6use serde::de::DeserializeOwned;
7use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
8use std::fmt::{Display, Formatter};
9use std::str::FromStr;
10pub use verifier::Verifier;
11
12pub mod verifier;
13
14pub type Nonce = u32;
15
16#[derive(Clone, Debug, PartialEq, Eq, JsonSchema)]
19pub struct MessageSignature(Vec<u8>);
20
21impl MessageSignature {
22 pub fn as_bs58_string(&self) -> String {
23 bs58::encode(&self.0).into_string()
24 }
25}
26
27impl<'a> From<&'a [u8]> for MessageSignature {
28 fn from(value: &'a [u8]) -> Self {
29 MessageSignature(value.to_vec())
30 }
31}
32
33impl From<Vec<u8>> for MessageSignature {
34 fn from(value: Vec<u8>) -> Self {
35 MessageSignature(value)
36 }
37}
38
39impl<'a> TryFrom<&'a str> for MessageSignature {
40 type Error = bs58::decode::Error;
41
42 fn try_from(value: &'a str) -> Result<Self, Self::Error> {
43 Ok(MessageSignature(bs58::decode(value).into_vec()?))
44 }
45}
46
47impl TryFrom<String> for MessageSignature {
48 type Error = bs58::decode::Error;
49
50 fn try_from(value: String) -> Result<Self, Self::Error> {
51 Self::try_from(value.as_str())
52 }
53}
54
55impl AsRef<[u8]> for MessageSignature {
56 #[inline]
57 fn as_ref(&self) -> &[u8] {
58 &self.0
59 }
60}
61
62impl<'de> Deserialize<'de> for MessageSignature {
63 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
64 where
65 D: Deserializer<'de>,
66 {
67 let inner = String::deserialize(deserializer)?;
68 let bytes = bs58::decode(inner).into_vec().map_err(de::Error::custom)?;
69 Ok(MessageSignature(bytes))
70 }
71}
72
73impl Serialize for MessageSignature {
74 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
75 where
76 S: Serializer,
77 {
78 let bs58_encoded = self.as_bs58_string();
79 bs58_encoded.serialize(serializer)
80 }
81}
82
83impl Display for MessageSignature {
84 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
85 write!(f, "{}", self.as_bs58_string())
86 }
87}
88
89impl FromStr for MessageSignature {
90 type Err = bs58::decode::Error;
91
92 fn from_str(s: &str) -> Result<Self, Self::Err> {
93 Self::try_from(s)
94 }
95}
96
97pub trait SigningPurpose {
98 fn message_type() -> MessageType;
99}
100
101#[derive(Serialize, Deserialize)]
102#[serde(transparent)]
103pub struct MessageType(String);
104
105impl MessageType {
106 pub fn new<S: Into<String>>(typ: S) -> Self {
107 MessageType(typ.into())
108 }
109}
110
111impl<T> From<T> for MessageType
112where
113 T: ToString,
114{
115 fn from(value: T) -> Self {
116 MessageType(value.to_string())
117 }
118}
119
120#[derive(Default, Debug, Serialize, Deserialize, Copy, Clone)]
121#[serde(rename_all = "lowercase")]
122pub enum SigningAlgorithm {
123 #[default]
124 Ed25519,
125 Secp256k1,
126}
127
128impl SigningAlgorithm {
129 pub fn is_ed25519(&self) -> bool {
130 matches!(self, SigningAlgorithm::Ed25519)
131 }
132}
133
134#[derive(Serialize, Deserialize)]
137pub struct SignableMessage<T> {
138 pub nonce: u32,
139 pub algorithm: SigningAlgorithm,
140 pub message_type: MessageType,
141
142 pub content: T,
143}
144
145impl<T> SignableMessage<T>
146where
147 T: SigningPurpose,
148{
149 pub fn new(nonce: u32, content: T) -> Self {
150 SignableMessage {
151 nonce,
152 algorithm: SigningAlgorithm::Ed25519,
153 message_type: T::message_type(),
154 content,
155 }
156 }
157
158 pub fn with_signing_algorithm(mut self, algorithm: SigningAlgorithm) -> Self {
159 self.algorithm = algorithm;
160 self
161 }
162
163 pub fn to_plaintext(&self) -> StdResult<Vec<u8>>
164 where
165 T: Serialize,
166 {
167 to_json_vec(self)
168 }
169
170 pub fn to_sha256_plaintext_digest(&self) -> StdResult<Vec<u8>>
171 where
172 T: Serialize,
173 {
174 unimplemented!()
175 }
176
177 pub fn to_json_string(&self) -> StdResult<String>
178 where
179 T: Serialize,
180 {
181 self.to_plaintext()
184 .map(|s| String::from_utf8(s).unwrap_or(String::from("SERIALIZATION FAILURE")))
185 }
186
187 pub fn to_base58_string(&self) -> StdResult<String>
188 where
189 T: Serialize,
190 {
191 self.to_plaintext().map(|s| bs58::encode(s).into_string())
192 }
193
194 pub fn try_from_bytes(bytes: &[u8]) -> StdResult<SignableMessage<T>>
195 where
196 T: DeserializeOwned,
197 {
198 from_json(bytes)
199 }
200
201 pub fn try_from_string(raw: &str) -> StdResult<SignableMessage<T>>
202 where
203 T: DeserializeOwned,
204 {
205 Self::try_from_bytes(raw.as_bytes())
206 }
207
208 pub fn try_from_base58_string(raw: &str) -> bs58::decode::Result<StdResult<SignableMessage<T>>>
209 where
210 T: DeserializeOwned,
211 {
212 bs58::decode(raw)
213 .into_vec()
214 .map(|d| Self::try_from_bytes(&d))
215 }
216}
217
218#[derive(Serialize)]
219pub struct ContractMessageContent<T> {
220 pub sender: Addr,
221 pub funds: Vec<Coin>,
222 pub data: T,
223}
224
225impl<T> SigningPurpose for ContractMessageContent<T>
226where
227 T: SigningPurpose,
228{
229 fn message_type() -> MessageType {
230 T::message_type()
231 }
232}
233
234impl<T> ContractMessageContent<T> {
235 pub fn new(sender: Addr, funds: Vec<Coin>, data: T) -> Self {
236 ContractMessageContent {
237 sender,
238 funds,
239 data,
240 }
241 }
242
243 pub fn new_with_info(info: MessageInfo, signer: Addr, data: T) -> Self {
244 ContractMessageContent {
245 sender: signer,
246 funds: info.funds,
247 data,
248 }
249 }
250}
251
252impl<T> From<ContractMessageContent<T>> for LegacyContractMessageContent<T> {
253 fn from(value: ContractMessageContent<T>) -> Self {
254 LegacyContractMessageContent {
255 sender: value.sender,
256 proxy: None,
257 funds: value.funds,
258 data: value.data,
259 }
260 }
261}
262
263#[derive(Serialize)]
264pub struct LegacyContractMessageContent<T> {
265 pub sender: Addr,
266 pub proxy: Option<Addr>,
267 pub funds: Vec<Coin>,
268 pub data: T,
269}
270
271impl<T> SigningPurpose for LegacyContractMessageContent<T>
272where
273 T: SigningPurpose,
274{
275 fn message_type() -> MessageType {
276 T::message_type()
277 }
278}