Skip to main content

bullet_exchange_interface/
address.rs

1//! Base58 address.
2#[derive(
3    Clone, Eq, Hash, Ord, PartialEq, PartialOrd, borsh::BorshDeserialize, borsh::BorshSerialize,
4)]
5#[cfg_attr(feature = "schema", derive(sov_universal_wallet::UniversalWallet))]
6pub struct Address(#[cfg_attr(feature = "schema", sov_wallet(display = "base58"))] pub [u8; 32]);
7
8impl Copy for Address {}
9
10impl serde::Serialize for Address {
11    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
12        if serializer.is_human_readable() {
13            serializer.serialize_str(&self.to_string())
14        } else {
15            serde::Serialize::serialize(&self.0, serializer)
16        }
17    }
18}
19
20impl<'de> serde::Deserialize<'de> for Address {
21    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
22    where
23        D: serde::Deserializer<'de>,
24    {
25        if deserializer.is_human_readable() {
26            let s = <String as serde::Deserialize<'_>>::deserialize(deserializer)?;
27            s.parse().map_err(serde::de::Error::custom)
28        } else {
29            let bytes = <[u8; 32] as serde::Deserialize<'_>>::deserialize(deserializer)?;
30            Ok(Self(bytes))
31        }
32    }
33}
34
35impl std::fmt::Display for Address {
36    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37        let mut res = String::default();
38        // keep at least 32-chars
39        bullet_bs58::encode32_append(&self.0, 32, &mut res);
40        write!(f, "{res}")
41    }
42}
43
44impl schemars::JsonSchema for Address {
45    fn schema_name() -> String {
46        "Address".to_string()
47    }
48
49    fn json_schema(_gen: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema {
50        // a new version of schemars has a json_schema! macro which would simplify this
51        serde_json::from_value(serde_json::json!({
52            "type": "string",
53            "pattern": "[1-9A-HJ-NP-Za-km-z]{32,44}",
54            "description": "Address",
55        }))
56        .unwrap()
57    }
58}
59
60impl std::fmt::Debug for Address {
61    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62        write!(f, "{self}")
63    }
64}
65impl AsRef<[u8]> for Address {
66    fn as_ref(&self) -> &[u8] {
67        &self.0
68    }
69}
70
71impl TryFrom<&[u8]> for Address {
72    type Error = String;
73
74    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
75        let key: [u8; 32] = value.try_into().map_err(|_| {
76            format!("Invalid base58 address. Got {} instead of 32 bytes.", value.len())
77        })?;
78        Ok(Self(key))
79    }
80}
81
82impl std::str::FromStr for Address {
83    type Err = String;
84
85    fn from_str(s: &str) -> Result<Self, Self::Err> {
86        let Some(x) = bullet_bs58::parse32(s.as_bytes()) else {
87            return Err(format!("Invalid base58 address `{s}`."));
88        };
89        Ok(Self(x))
90    }
91}