Skip to main content

miden_protocol/address/
address_id.rs

1use alloc::string::ToString;
2
3use bech32::Bech32m;
4use bech32::primitives::decode::CheckedHrpstring;
5
6use crate::account::AccountId;
7use crate::address::{AddressType, NetworkId};
8use crate::errors::{AddressError, Bech32Error};
9use crate::utils::serde::{
10    ByteReader,
11    ByteWriter,
12    Deserializable,
13    DeserializationError,
14    Serializable,
15};
16
17/// The identifier of an [`Address`](super::Address).
18///
19/// See the address docs for more details.
20#[non_exhaustive]
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
22pub enum AddressId {
23    AccountId(AccountId),
24}
25
26impl AddressId {
27    /// Returns the [`AddressType`] of this ID.
28    pub fn address_type(&self) -> AddressType {
29        match self {
30            AddressId::AccountId(_) => AddressType::AccountId,
31        }
32    }
33
34    /// Decodes a bech32 string into an identifier.
35    pub(crate) fn decode(bech32_string: &str) -> Result<(NetworkId, Self), AddressError> {
36        // We use CheckedHrpString with an explicit checksum algorithm so we don't allow the
37        // `Bech32` or `NoChecksum` algorithms.
38        let checked_string = CheckedHrpstring::new::<Bech32m>(bech32_string).map_err(|source| {
39            // The CheckedHrpStringError does not implement core::error::Error, only
40            // std::error::Error, so for now we convert it to a String. Even if it will
41            // implement the trait in the future, we should include it as an opaque
42            // error since the crate does not have a stable release yet.
43            AddressError::Bech32DecodeError(Bech32Error::DecodeError(source.to_string().into()))
44        })?;
45
46        let hrp = checked_string.hrp();
47        let network_id = NetworkId::from_hrp(hrp);
48
49        let mut byte_iter = checked_string.byte_iter();
50
51        // We only know the expected length once we know the address type, but to get the
52        // address type, the length must be at least one.
53        let address_byte = byte_iter.next().ok_or_else(|| {
54            AddressError::Bech32DecodeError(Bech32Error::InvalidDataLength {
55                expected: 1,
56                actual: byte_iter.len(),
57            })
58        })?;
59
60        let address_type = AddressType::try_from(address_byte)?;
61
62        let identifier = match address_type {
63            AddressType::AccountId => AccountId::from_bech32_byte_iter(byte_iter)
64                .map_err(AddressError::AccountIdDecodeError)
65                .map(AddressId::AccountId)?,
66        };
67
68        Ok((network_id, identifier))
69    }
70}
71
72impl From<AccountId> for AddressId {
73    fn from(id: AccountId) -> Self {
74        Self::AccountId(id)
75    }
76}
77
78impl Serializable for AddressId {
79    fn write_into<W: ByteWriter>(&self, target: &mut W) {
80        target.write_u8(self.address_type() as u8);
81        match self {
82            AddressId::AccountId(id) => {
83                id.write_into(target);
84            },
85        }
86    }
87}
88
89impl Deserializable for AddressId {
90    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
91        let address_type: u8 = source.read_u8()?;
92        let address_type = AddressType::try_from(address_type)
93            .map_err(|err| DeserializationError::InvalidValue(err.to_string()))?;
94
95        match address_type {
96            AddressType::AccountId => {
97                let id: AccountId = source.read()?;
98                Ok(AddressId::AccountId(id))
99            },
100        }
101    }
102}