1use std::fmt::Display;
2use std::str::FromStr;
3
4use bech32::Hrp;
5use enum_dispatch::enum_dispatch;
6use serde::{Deserialize, Serialize};
7use tendermint::account::Id;
8#[cfg(all(feature = "wasm-bindgen", target_arch = "wasm32"))]
9use wasm_bindgen::prelude::*;
10
11use crate::consts::appconsts;
12use crate::consts::cosmos::*;
13use crate::{Error, Result};
14
15pub use k256::ecdsa::VerifyingKey;
16
17#[enum_dispatch(Address)]
19pub trait AddressTrait: FromStr + Display + private::Sealed {
20 fn id_ref(&self) -> &Id;
22 fn kind(&self) -> AddressKind;
24
25 #[inline]
27 fn id(&self) -> Id {
28 *self.id_ref()
29 }
30
31 #[inline]
33 fn as_bytes(&self) -> &[u8] {
34 self.id_ref().as_bytes()
35 }
36
37 #[inline]
39 fn prefix(&self) -> &'static str {
40 self.kind().prefix()
41 }
42}
43
44mod private {
45 pub trait Sealed {}
46}
47
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
50pub enum AddressKind {
51 Account,
53 Validator,
55 Consensus,
57}
58
59#[enum_dispatch]
61#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
62#[serde(try_from = "Raw", into = "Raw")]
63pub enum Address {
64 AccAddress,
66 ValAddress,
68 ConsAddress,
70}
71
72impl Address {
73 pub fn from_account_veryfing_key(key: VerifyingKey) -> Self {
75 Address::AccAddress(key.into())
76 }
77
78 pub fn from_validator_veryfing_key(key: VerifyingKey) -> Self {
80 Address::ValAddress(key.into())
81 }
82
83 pub fn from_consensus_veryfing_key(key: VerifyingKey) -> Self {
85 Address::ConsAddress(key.into())
86 }
87}
88
89#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
91#[serde(try_from = "Raw", into = "Raw")]
92#[cfg_attr(
93 all(feature = "wasm-bindgen", target_arch = "wasm32"),
94 wasm_bindgen(inspectable)
95)]
96#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
97pub struct AccAddress {
98 id: Id,
99}
100
101#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
103#[serde(try_from = "Raw", into = "Raw")]
104#[cfg_attr(
105 all(feature = "wasm-bindgen", target_arch = "wasm32"),
106 wasm_bindgen(inspectable)
107)]
108pub struct ValAddress {
109 id: Id,
110}
111
112#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
114#[serde(try_from = "Raw", into = "Raw")]
115#[cfg_attr(
116 all(feature = "wasm-bindgen", target_arch = "wasm32"),
117 wasm_bindgen(inspectable)
118)]
119pub struct ConsAddress {
120 id: Id,
121}
122
123#[derive(Debug, Clone, Serialize, Deserialize)]
124#[serde(transparent)]
125struct Raw {
126 #[serde(with = "tendermint_proto::serializers::from_str")]
127 addr: String,
128}
129
130impl AddressKind {
131 pub fn prefix(&self) -> &'static str {
133 match self {
134 AddressKind::Account => BECH32_PREFIX_ACC_ADDR,
135 AddressKind::Validator => BECH32_PREFIX_VAL_ADDR,
136 AddressKind::Consensus => BECH32_PREFIX_CONS_ADDR,
137 }
138 }
139}
140
141impl FromStr for AddressKind {
142 type Err = Error;
143
144 fn from_str(s: &str) -> Result<Self, Self::Err> {
145 match s {
146 BECH32_PREFIX_ACC_ADDR => Ok(AddressKind::Account),
147 BECH32_PREFIX_VAL_ADDR => Ok(AddressKind::Validator),
148 BECH32_PREFIX_CONS_ADDR => Ok(AddressKind::Consensus),
149 _ => Err(Error::InvalidAddressPrefix(s.to_owned())),
150 }
151 }
152}
153
154impl private::Sealed for Address {}
155
156impl Display for Address {
157 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
158 match self {
159 Address::AccAddress(v) => <AccAddress as Display>::fmt(v, f),
160 Address::ValAddress(v) => <ValAddress as Display>::fmt(v, f),
161 Address::ConsAddress(v) => <ConsAddress as Display>::fmt(v, f),
162 }
163 }
164}
165
166impl FromStr for Address {
167 type Err = Error;
168
169 fn from_str(s: &str) -> Result<Self, Self::Err> {
170 let (kind, id) = string_to_kind_and_id(s)?;
171
172 match kind {
173 AddressKind::Account => Ok(AccAddress::new(id).into()),
174 AddressKind::Validator => Ok(ValAddress::new(id).into()),
175 AddressKind::Consensus => Ok(ConsAddress::new(id).into()),
176 }
177 }
178}
179
180impl TryFrom<Raw> for Address {
181 type Error = Error;
182
183 fn try_from(value: Raw) -> Result<Self, Self::Error> {
184 value.addr.parse()
185 }
186}
187
188impl From<Address> for Raw {
189 fn from(value: Address) -> Self {
190 let addr = value.to_string();
191 Raw { addr }
192 }
193}
194
195macro_rules! impl_address_type {
196 ($name:ident, $kind:ident) => {
197 impl $name {
198 pub fn new(id: Id) -> Self {
200 $name { id }
201 }
202 }
203
204 impl AddressTrait for $name {
205 #[inline]
206 fn id_ref(&self) -> &Id {
207 &self.id
208 }
209
210 #[inline]
211 fn kind(&self) -> AddressKind {
212 AddressKind::$kind
213 }
214 }
215
216 impl private::Sealed for $name {}
217
218 impl Display for $name {
219 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
220 let s = address_to_string(self);
221 f.write_str(&s)
222 }
223 }
224
225 impl FromStr for $name {
226 type Err = Error;
227
228 fn from_str(s: &str) -> Result<Self, Self::Err> {
229 let (kind, id) = string_to_kind_and_id(s)?;
230
231 match kind {
232 AddressKind::$kind => Ok($name::new(id)),
233 _ => Err(Error::InvalidAddressPrefix(kind.prefix().to_owned())),
234 }
235 }
236 }
237
238 impl TryFrom<Raw> for $name {
239 type Error = Error;
240
241 fn try_from(value: Raw) -> Result<Self, Self::Error> {
242 value.addr.parse()
243 }
244 }
245
246 impl From<$name> for Raw {
247 fn from(value: $name) -> Self {
248 let addr = value.to_string();
249 Raw { addr }
250 }
251 }
252
253 impl From<[u8; appconsts::SIGNER_SIZE]> for $name {
254 fn from(value: [u8; appconsts::SIGNER_SIZE]) -> Self {
255 Self::new(Id::new(value))
256 }
257 }
258
259 impl From<VerifyingKey> for $name {
260 fn from(value: VerifyingKey) -> Self {
261 Self::new(Id::from(value))
262 }
263 }
264
265 impl TryFrom<&[u8]> for $name {
266 type Error = Error;
267
268 fn try_from(value: &[u8]) -> Result<Self> {
269 let id = value
270 .try_into()
271 .map_err(|_| Error::InvalidAddressSize(value.len()))?;
272 Ok(Self::new(Id::new(id)))
273 }
274 }
275
276 impl TryFrom<Vec<u8>> for $name {
277 type Error = Error;
278
279 fn try_from(value: Vec<u8>) -> Result<Self> {
280 let len = value.len();
281 let id = value
282 .try_into()
283 .map_err(|_| Error::InvalidAddressSize(len))?;
284 Ok(Self::new(id))
285 }
286 }
287 };
288}
289
290impl_address_type!(AccAddress, Account);
291impl_address_type!(ValAddress, Validator);
292impl_address_type!(ConsAddress, Consensus);
293
294fn address_to_string(addr: &impl AddressTrait) -> String {
295 let hrp = Hrp::parse(addr.prefix()).expect("Invalid prefix");
297 bech32::encode::<bech32::Bech32>(hrp, addr.as_bytes()).expect("Invalid address length")
298}
299
300fn string_to_kind_and_id(s: &str) -> Result<(AddressKind, Id)> {
301 let (hrp, data) = bech32::decode(s).map_err(|_| Error::InvalidAddress(s.to_owned()))?;
302
303 let kind = hrp.as_str().parse()?;
304 let bytes = data[..]
305 .try_into()
306 .map_err(|_| Error::InvalidAddressSize(data.len()))?;
307
308 Ok((kind, Id::new(bytes)))
309}
310
311#[cfg(feature = "uniffi")]
313pub(crate) mod uniffi_types {
314 use super::{Address, Id};
315 use uniffi::Record;
316
317 use crate::error::UniffiConversionError;
318
319 uniffi::custom_type!(Address, String, {
320 remote,
321 try_lift: |address| Ok(address.parse()?),
322 lower: |address| format!("{address}")
323 });
324
325 #[derive(Record, Clone)]
327 pub struct AccountId {
328 pub id: Vec<u8>,
330 }
331
332 impl From<Id> for AccountId {
333 fn from(value: Id) -> Self {
334 AccountId {
335 id: value.as_ref().to_vec(),
336 }
337 }
338 }
339
340 impl TryFrom<AccountId> for Id {
341 type Error = UniffiConversionError;
342
343 fn try_from(value: AccountId) -> std::result::Result<Self, Self::Error> {
344 Id::try_from(value.id).map_err(|_| UniffiConversionError::InvalidAccountIdLength)
345 }
346 }
347
348 uniffi::custom_type!(Id, AccountId, {
349 remote,
350 try_lift: |value| Ok(value.try_into()?),
351 lower: |value| value.into()
352 });
353}
354
355#[cfg(test)]
356mod tests {
357 use super::*;
358
359 #[cfg(target_arch = "wasm32")]
360 use wasm_bindgen_test::wasm_bindgen_test as test;
361
362 const ADDR1: [u8; 20] = [
363 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
364 ];
365 const ADDR1_ACC_STR: &str = "celestia1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5wgawu3";
366 const ADDR1_VAL_STR: &str = "celestiavaloper1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5thlh2h";
367 const ADDR1_CONS_STR: &str = "celestiavalcons1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lyvtxk";
368
369 #[test]
370 fn parse_acc_addr() {
371 let addr: Address = ADDR1_ACC_STR.parse().unwrap();
372 assert_eq!(addr.kind(), AddressKind::Account);
373 assert_eq!(addr.as_bytes(), ADDR1);
374 assert_eq!(&addr.to_string(), ADDR1_ACC_STR);
375
376 let addr: AccAddress = ADDR1_ACC_STR.parse().unwrap();
377 assert_eq!(addr.as_bytes(), ADDR1);
378 assert_eq!(&addr.to_string(), ADDR1_ACC_STR);
379
380 ADDR1_ACC_STR.parse::<ValAddress>().unwrap_err();
381 ADDR1_ACC_STR.parse::<ConsAddress>().unwrap_err();
382 }
383
384 #[test]
385 fn serde_acc_addr() {
386 let addr_json = format!("\"{ADDR1_ACC_STR}\"");
387
388 let addr: Address = serde_json::from_str(&addr_json).unwrap();
389 assert_eq!(addr.kind(), AddressKind::Account);
390 assert_eq!(addr.as_bytes(), ADDR1);
391
392 let addr: AccAddress = serde_json::from_str(&addr_json).unwrap();
393 assert_eq!(addr.as_bytes(), ADDR1);
394
395 serde_json::from_str::<ValAddress>(&addr_json).unwrap_err();
396 serde_json::from_str::<ConsAddress>(&addr_json).unwrap_err();
397 }
398
399 #[test]
400 fn parse_val_addr() {
401 let addr: Address = ADDR1_VAL_STR.parse().unwrap();
402 assert_eq!(addr.kind(), AddressKind::Validator);
403 assert_eq!(addr.as_bytes(), ADDR1);
404 assert_eq!(&addr.to_string(), ADDR1_VAL_STR);
405
406 let addr: ValAddress = ADDR1_VAL_STR.parse().unwrap();
407 assert_eq!(addr.as_bytes(), ADDR1);
408 assert_eq!(&addr.to_string(), ADDR1_VAL_STR);
409
410 ADDR1_VAL_STR.parse::<AccAddress>().unwrap_err();
411 ADDR1_VAL_STR.parse::<ConsAddress>().unwrap_err();
412 }
413
414 #[test]
415 fn serde_val_addr() {
416 let addr_json = format!("\"{ADDR1_VAL_STR}\"");
417
418 let addr: Address = serde_json::from_str(&addr_json).unwrap();
419 assert_eq!(addr.kind(), AddressKind::Validator);
420 assert_eq!(addr.as_bytes(), ADDR1);
421
422 let addr: ValAddress = serde_json::from_str(&addr_json).unwrap();
423 assert_eq!(addr.as_bytes(), ADDR1);
424
425 serde_json::from_str::<AccAddress>(&addr_json).unwrap_err();
426 serde_json::from_str::<ConsAddress>(&addr_json).unwrap_err();
427 }
428
429 #[test]
430 fn parse_cons_addr() {
431 let addr: Address = ADDR1_CONS_STR.parse().unwrap();
432 assert_eq!(addr.kind(), AddressKind::Consensus);
433 assert_eq!(addr.as_bytes(), ADDR1);
434 assert_eq!(&addr.to_string(), ADDR1_CONS_STR);
435
436 let addr: ConsAddress = ADDR1_CONS_STR.parse().unwrap();
437 assert_eq!(addr.as_bytes(), ADDR1);
438 assert_eq!(&addr.to_string(), ADDR1_CONS_STR);
439
440 ADDR1_CONS_STR.parse::<AccAddress>().unwrap_err();
441 ADDR1_CONS_STR.parse::<ValAddress>().unwrap_err();
442 }
443
444 #[test]
445 fn serde_cons_addr() {
446 let addr_json = format!("\"{ADDR1_CONS_STR}\"");
447
448 let addr: Address = serde_json::from_str(&addr_json).unwrap();
449 assert_eq!(addr.kind(), AddressKind::Consensus);
450 assert_eq!(addr.as_bytes(), ADDR1);
451
452 let addr: ConsAddress = serde_json::from_str(&addr_json).unwrap();
453 assert_eq!(addr.as_bytes(), ADDR1);
454
455 serde_json::from_str::<AccAddress>(&addr_json).unwrap_err();
456 serde_json::from_str::<ValAddress>(&addr_json).unwrap_err();
457 }
458
459 #[test]
460 fn parse_invalid_addr() {
461 let addr = "celestia1qyu009tf";
463 addr.parse::<Address>().unwrap_err();
464 addr.parse::<AccAddress>().unwrap_err();
465 addr.parse::<ValAddress>().unwrap_err();
466 addr.parse::<ConsAddress>().unwrap_err();
467
468 let addr = "celestiavaloper1qy2jc8nq";
470 addr.parse::<Address>().unwrap_err();
471 addr.parse::<AccAddress>().unwrap_err();
472 addr.parse::<ValAddress>().unwrap_err();
473 addr.parse::<ConsAddress>().unwrap_err();
474
475 let addr = "celestiavalcons1qy2zlull";
477 addr.parse::<Address>().unwrap_err();
478 addr.parse::<AccAddress>().unwrap_err();
479 addr.parse::<ValAddress>().unwrap_err();
480 addr.parse::<ConsAddress>().unwrap_err();
481
482 let addr = "foobar1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5avgsnn";
484 addr.parse::<Address>().unwrap_err();
485 addr.parse::<AccAddress>().unwrap_err();
486 addr.parse::<ValAddress>().unwrap_err();
487 addr.parse::<ConsAddress>().unwrap_err();
488
489 let addr = "asdsdfsdgsfd";
491 addr.parse::<Address>().unwrap_err();
492 addr.parse::<AccAddress>().unwrap_err();
493 addr.parse::<ValAddress>().unwrap_err();
494 addr.parse::<ConsAddress>().unwrap_err();
495 }
496
497 #[test]
498 fn convert() {
499 let addr: Address = ADDR1_ACC_STR.parse().unwrap();
500 let acc_addr: AccAddress = addr.try_into().unwrap();
501 let _addr: Address = acc_addr.into();
502
503 let addr: Address = ADDR1_VAL_STR.parse().unwrap();
504 let val_addr: ValAddress = addr.try_into().unwrap();
505 let _addr: Address = val_addr.into();
506
507 let addr: Address = ADDR1_CONS_STR.parse().unwrap();
508 let cons_addr: ConsAddress = addr.try_into().unwrap();
509 let _addr: Address = cons_addr.into();
510 }
511}