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