Skip to main content

acta_maker_sdk/types/
address.rs

1//! Chain-independent 32-byte account address.
2
3use std::fmt;
4
5use serde::{Deserialize, Serialize};
6
7#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
8pub struct Address32(pub [u8; 32]);
9
10impl Address32 {
11    pub const ZERO: Self = Self([0; 32]);
12
13    #[must_use]
14    pub const fn new(bytes: [u8; 32]) -> Self {
15        Self(bytes)
16    }
17
18    #[must_use]
19    pub const fn as_bytes(&self) -> &[u8; 32] {
20        &self.0
21    }
22
23    /// Parse the base58 representation used by Solana account addresses.
24    ///
25    /// # Errors
26    /// Returns an error when the value is not canonical 32-byte base58.
27    pub fn from_base58(value: &str) -> Result<Self, AddressError> {
28        let bytes = bs58::decode(value)
29            .into_vec()
30            .map_err(|_| AddressError::InvalidBase58)?;
31        let bytes: [u8; 32] = bytes
32            .try_into()
33            .map_err(|bytes: Vec<u8>| AddressError::InvalidLength(bytes.len()))?;
34        Ok(Self(bytes))
35    }
36
37    #[must_use]
38    pub fn to_base58(self) -> String {
39        bs58::encode(self.0).into_string()
40    }
41}
42
43impl fmt::Debug for Address32 {
44    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
45        formatter
46            .debug_tuple("Address32")
47            .field(&self.to_base58())
48            .finish()
49    }
50}
51
52impl fmt::Display for Address32 {
53    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
54        formatter.write_str(&self.to_base58())
55    }
56}
57
58impl Serialize for Address32 {
59    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
60    where
61        S: serde::Serializer,
62    {
63        serializer.serialize_str(&self.to_base58())
64    }
65}
66
67impl<'de> Deserialize<'de> for Address32 {
68    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
69    where
70        D: serde::Deserializer<'de>,
71    {
72        let value = String::deserialize(deserializer)?;
73        Self::from_base58(&value).map_err(serde::de::Error::custom)
74    }
75}
76
77impl AsRef<[u8]> for Address32 {
78    fn as_ref(&self) -> &[u8] {
79        &self.0
80    }
81}
82
83impl AsRef<[u8; 32]> for Address32 {
84    fn as_ref(&self) -> &[u8; 32] {
85        &self.0
86    }
87}
88
89impl From<[u8; 32]> for Address32 {
90    fn from(bytes: [u8; 32]) -> Self {
91        Self(bytes)
92    }
93}
94
95impl From<Address32> for [u8; 32] {
96    fn from(address: Address32) -> Self {
97        address.0
98    }
99}
100
101#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
102pub enum AddressError {
103    #[error("invalid base58 address")]
104    InvalidBase58,
105    #[error("invalid address length: expected 32 bytes, got {0}")]
106    InvalidLength(usize),
107}
108
109impl From<solana_pubkey::Pubkey> for Address32 {
110    fn from(value: solana_pubkey::Pubkey) -> Self {
111        Self(value.to_bytes())
112    }
113}
114impl From<Address32> for solana_pubkey::Pubkey {
115    fn from(value: Address32) -> Self {
116        Self::new_from_array(value.0)
117    }
118}