1use crate::consts::{
9 ADDRESS_TYPE_BUILTIN, ADDRESS_TYPE_CONTRACT, ADDRESS_TYPE_NULL,
10 ADDRESS_TYPE_UNKNOWN, ADDRESS_TYPE_USER, MAINNET_PREFIX, NETWORK_ID_PREFIX,
11 RESERVED_NETWORK_IDS, TESTNET_PREFIX,
12};
13use cfx_types::{
14 address_util::{self, AddressUtil},
15 Address,
16};
17use core::fmt;
18
19#[cfg(feature = "std")]
20use std::error::Error;
21
22#[cfg(not(feature = "std"))]
23use alloc::{
24 format,
25 string::{String, ToString},
26 vec::Vec,
27};
28
29#[derive(PartialEq, Eq, Clone, Debug, Hash)]
31pub struct DecodedRawAddress {
32 pub input_base32_address: String,
34 pub parsed_address_bytes: Vec<u8>,
36 pub hex_address: Option<Address>,
38 pub network: Network,
40}
41
42#[derive(Copy, Clone)]
43pub enum EncodingOptions {
44 Simple,
45 QrCode,
46}
47
48#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
49pub enum Network {
50 Main,
52 Test,
54 Id(u64),
56}
57
58impl Network {
59 pub fn to_prefix(&self) -> Result<String, EncodingError> {
60 match self {
61 Network::Main => Ok(MAINNET_PREFIX.into()),
62 Network::Test => Ok(TESTNET_PREFIX.into()),
63 Network::Id(network_id) => {
64 if RESERVED_NETWORK_IDS.contains(network_id) {
65 Err(EncodingError::InvalidNetworkId(*network_id))
66 } else {
67 Ok(format!("net{}", network_id))
68 }
69 }
70 }
71 }
72
73 pub fn from_prefix(prefix: &str) -> Result<Self, DecodingError> {
74 match prefix {
75 MAINNET_PREFIX => Ok(Network::Main),
76 TESTNET_PREFIX => Ok(Network::Test),
77 _ => {
78 let maybe_network_id = if !prefix.starts_with(NETWORK_ID_PREFIX)
79 {
80 None
81 } else {
82 match prefix[NETWORK_ID_PREFIX.len()..].parse::<u64>() {
83 Err(_) => None,
84 Ok(network_id) => {
85 if RESERVED_NETWORK_IDS.contains(&network_id) {
87 None
88 } else {
89 Some(network_id)
90 }
91 }
92 }
93 };
94
95 match maybe_network_id {
96 None => {
97 Err(DecodingError::InvalidPrefix(prefix.to_string()))
98 }
99 Some(network_id) => Ok(Network::Id(network_id)),
100 }
101 }
102 }
103 }
104}
105
106impl fmt::Display for Network {
107 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108 match self.to_prefix() {
109 Err(EncodingError::InvalidNetworkId(network_id)) => {
110 write!(f, "invalid network prefix net{}", network_id)
111 }
112 Err(_) => unreachable!(),
113 Ok(prefix) => write!(f, "{}", prefix),
114 }
115 }
116}
117
118#[derive(Debug, PartialEq, Eq, Clone)]
119pub enum AddressType {
120 Builtin,
121 Contract,
122 Null,
123 User,
124 Unknown,
125}
126
127impl AddressType {
128 const BUILTIN: &'static str = ADDRESS_TYPE_BUILTIN;
129 const CONTRACT: &'static str = ADDRESS_TYPE_CONTRACT;
130 const NULL: &'static str = ADDRESS_TYPE_NULL;
131 const UNKNOWN: &'static str = ADDRESS_TYPE_UNKNOWN;
132 const USER: &'static str = ADDRESS_TYPE_USER;
133
134 pub fn parse(text: &str) -> Result<Self, DecodingError> {
135 if text == Self::BUILTIN {
136 Ok(Self::Builtin)
137 } else if text == Self::CONTRACT {
138 Ok(Self::Contract)
139 } else if text == Self::NULL {
140 Ok(Self::Null)
141 } else if text == Self::USER {
142 Ok(Self::User)
143 } else {
144 Ok(Self::Unknown)
145 }
146 }
147
148 pub fn from_address<T: AddressUtil>(
149 address_hex: &T,
150 ) -> Result<Self, EncodingError> {
151 match address_hex.address_type_bits() {
152 address_util::TYPE_BITS_BUILTIN => {
153 if address_hex.is_null_address() {
154 Ok(Self::Null)
155 } else {
156 Ok(Self::Builtin)
157 }
158 }
159 address_util::TYPE_BITS_CONTRACT => Ok(Self::Contract),
160 address_util::TYPE_BITS_USER_ACCOUNT => Ok(Self::User),
161 _ => Ok(Self::Unknown),
162 }
163 }
164
165 pub fn to_str(&self) -> &'static str {
166 match self {
167 Self::Builtin => Self::BUILTIN,
168 Self::Contract => Self::CONTRACT,
169 Self::Null => Self::NULL,
170 Self::User => Self::USER,
171 Self::Unknown => Self::UNKNOWN,
172 }
173 }
174}
175
176impl fmt::Display for AddressType {
177 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
178 write!(f, "{}", self.to_str())
179 }
180}
181
182#[derive(Debug, PartialEq, Eq, Clone)]
184pub enum EncodingError {
185 InvalidAddressType(u8),
186 InvalidLength(usize),
187 InvalidNetworkId(u64),
188}
189
190impl fmt::Display for EncodingError {
191 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
192 match self {
193 Self::InvalidAddressType(type_byte) => {
194 write!(f, "unrecognized type bits 0x{:02x}", type_byte)
195 }
196 Self::InvalidLength(length) => {
197 write!(f, "invalid length ({})", length)
198 }
199 Self::InvalidNetworkId(network_id) => {
200 write!(f, "invalid network_id (reserved: {})", network_id)
201 }
202 }
203 }
204}
205
206#[cfg(feature = "std")]
207impl Error for EncodingError {
208 fn cause(&self) -> Option<&dyn Error> { None }
209
210 fn description(&self) -> &str { "invalid length" }
211}
212
213#[derive(Debug, PartialEq, Eq, Clone)]
215pub enum DecodingError {
216 InvalidLength(usize),
218 NoPrefix,
220 InvalidPrefix(String),
222 InvalidOption(OptionError),
224 ChecksumFailed(u64),
226 InvalidChar(char),
228 InvalidPadding {
231 from_bits: u8,
232 padding_bits: u8,
233 padding: u16,
234 },
235 VersionNotRecognized(u8),
237 MixedCase,
239}
240
241#[derive(Debug, PartialEq, Eq, Clone)]
242pub enum OptionError {
243 ParseError(String),
245 AddressTypeMismatch {
249 expected: AddressType,
250 got: Result<AddressType, ()>,
251 },
252 InvalidAddressType(String),
254}
255
256impl fmt::Display for DecodingError {
257 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
258 match self {
259 DecodingError::ChecksumFailed(actual) => {
260 write!(f, "invalid checksum (actual {} != 0)", actual)
261 }
262 DecodingError::InvalidChar(index) => {
263 write!(f, "invalid char ({})", index)
264 }
265 DecodingError::InvalidLength(length) => {
266 write!(f, "invalid length ({})", length)
267 }
268 DecodingError::InvalidPadding {
269 from_bits,
270 padding_bits,
271 padding,
272 } => {
273 write!(f, "invalid padding (")?;
274 if padding_bits >= from_bits {
275 write!(
276 f,
277 "padding_bits({}) >= from_bits({})",
278 padding_bits, from_bits
279 )?;
280 if *padding != 0 {
281 write!(f, ", padding({:#b}) is non-zero)", padding)?;
282 }
283 } else {
284 write!(f, "padding({:#b}) is non-zero)", padding)?;
285 }
286 Ok(())
287 }
288 DecodingError::InvalidPrefix(prefix) => {
289 write!(f, "invalid prefix ({})", prefix)
290 }
291 DecodingError::InvalidOption(option_error) => match option_error {
292 OptionError::AddressTypeMismatch { expected, got } => {
293 write!(f, "expected address type specified in option {:?}, decoded address type {:?}", expected, got)
294 }
295 OptionError::ParseError(option_str) => {
296 write!(f, "invalid option string ({})", option_str)
297 }
298 OptionError::InvalidAddressType(type_str) => {
299 write!(f, "invalid address type ({})", type_str)
300 }
301 },
302 DecodingError::NoPrefix => write!(f, "zero or multiple prefixes"),
303 DecodingError::MixedCase => write!(f, "mixed case string"),
304 DecodingError::VersionNotRecognized(c) => {
305 write!(f, "version byte ({}) not recognized", c)
306 }
307 }
308 }
309}
310
311#[cfg(feature = "std")]
312impl Error for DecodingError {
313 fn cause(&self) -> Option<&dyn Error> { None }
314
315 fn description(&self) -> &str {
316 match self {
317 DecodingError::ChecksumFailed { .. } => "invalid checksum",
318 DecodingError::InvalidChar(_) => "invalid char",
319 DecodingError::InvalidLength(_) => "invalid length",
320 DecodingError::InvalidOption(option_error) => match option_error {
321 OptionError::AddressTypeMismatch { .. } => {
322 "decoded address does not match address type in option"
323 }
324 OptionError::ParseError(_) => "invalid option",
325 OptionError::InvalidAddressType(_) => "invalid address type",
326 },
327 DecodingError::InvalidPadding { .. } => "invalid padding",
328 DecodingError::InvalidPrefix(_) => "invalid prefix",
329 DecodingError::NoPrefix => "zero or multiple prefixes",
330 DecodingError::MixedCase => "mixed case string",
331 DecodingError::VersionNotRecognized(_) => {
332 "version byte not recognized"
333 }
334 }
335 }
336}