Skip to main content

miden_protocol/address/
address_id.rs

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