radix_common/address/
decoder.rs

1use super::hrpset::HrpSet;
2use crate::address::AddressBech32DecodeError;
3use crate::network::NetworkDefinition;
4use crate::types::EntityType;
5use bech32::{self, FromBase32, Variant};
6use sbor::rust::prelude::*;
7
8/// Represents a decoder which understands how to decode Scrypto addresses in Bech32.
9pub struct AddressBech32Decoder {
10    pub hrp_set: HrpSet,
11}
12
13impl AddressBech32Decoder {
14    pub fn for_simulator() -> Self {
15        Self::new(&NetworkDefinition::simulator())
16    }
17
18    /// Instantiates a new AddressBech32Decoder with the HRP corresponding to the passed network.
19    pub fn new(network: &NetworkDefinition) -> Self {
20        Self {
21            hrp_set: network.into(),
22        }
23    }
24
25    pub fn validate_and_decode_ignore_hrp(
26        address: &str,
27    ) -> Result<(String, EntityType, Vec<u8>), AddressBech32DecodeError> {
28        // Decode the address string
29        let (hrp, data, variant) = bech32::decode(address)
30            .map_err(|err| AddressBech32DecodeError::Bech32mDecodingError(err))?;
31
32        // Validate the Bech32 variant to ensure that is is Bech32m
33        match variant {
34            Variant::Bech32m => {}
35            _ => return Err(AddressBech32DecodeError::InvalidVariant(variant)),
36        };
37
38        // Convert the data to u8 from u5.
39        let data = Vec::<u8>::from_base32(&data)
40            .map_err(|err| AddressBech32DecodeError::Bech32mDecodingError(err))?;
41
42        // Obtain the HRP based on the entity byte in the data
43        let entity_type = if let Some(entity_type_id) = data.get(0) {
44            EntityType::from_repr(*entity_type_id).ok_or(
45                AddressBech32DecodeError::InvalidEntityTypeId(*entity_type_id),
46            )?
47        } else {
48            return Err(AddressBech32DecodeError::MissingEntityTypeByte);
49        };
50
51        // Validation complete, return data bytes
52        Ok((hrp, entity_type, data))
53    }
54
55    /// Low level method which performs the Bech32 validation and decoding of the data.
56    pub fn validate_and_decode(
57        &self,
58        address: &str,
59    ) -> Result<(EntityType, Vec<u8>), AddressBech32DecodeError> {
60        let (actual_hrp, entity_type, data) = Self::validate_and_decode_ignore_hrp(address)?;
61        let expected_hrp = self.hrp_set.get_entity_hrp(&entity_type);
62
63        // Validate that the decoded HRP matches that corresponding to the entity byte
64        if actual_hrp != expected_hrp {
65            return Err(AddressBech32DecodeError::InvalidHrp);
66        }
67
68        // Validation complete, return data bytes
69        Ok((entity_type, data))
70    }
71}