1use thiserror::Error;
2
3pub fn deserialize_required_option<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
5where
6 D: serde::Deserializer<'de>,
7 T: serde::Deserialize<'de>,
8{
9 <Option<T> as serde::Deserialize>::deserialize(deserializer)
10}
11
12#[derive(Debug, Error)]
13pub enum WireError {
14 #[error("invalid hex: {0}")]
15 InvalidHex(String),
16 #[error("invalid base58: {0}")]
17 InvalidBase58(String),
18 #[error("invalid length: expected {expected}, got {actual}")]
19 InvalidLength { expected: usize, actual: usize },
20}
21
22pub fn decode_hex_32(hex_str: &str) -> Result<[u8; 32], WireError> {
23 let trimmed = hex_str.strip_prefix("0x").unwrap_or(hex_str);
24 let bytes = hex::decode(trimmed).map_err(|err| WireError::InvalidHex(err.to_string()))?;
25 if bytes.len() != 32 {
26 return Err(WireError::InvalidLength {
27 expected: 32,
28 actual: bytes.len(),
29 });
30 }
31 let mut out = [0u8; 32];
32 out.copy_from_slice(&bytes);
33 Ok(out)
34}
35
36pub fn decode_base58_32(value: &str) -> Result<[u8; 32], WireError> {
37 decode_base58_fixed::<32>(value)
38}
39
40pub fn decode_base58_64(value: &str) -> Result<[u8; 64], WireError> {
41 decode_base58_fixed::<64>(value)
42}
43
44pub fn encode_base58(bytes: &[u8]) -> String {
45 bs58::encode(bytes).into_string()
46}
47
48pub fn encode_hex(bytes: &[u8]) -> String {
49 hex::encode(bytes)
50}
51
52fn decode_base58_fixed<const N: usize>(value: &str) -> Result<[u8; N], WireError> {
53 let bytes = bs58::decode(value)
54 .into_vec()
55 .map_err(|err| WireError::InvalidBase58(err.to_string()))?;
56 if bytes.len() != N {
57 return Err(WireError::InvalidLength {
58 expected: N,
59 actual: bytes.len(),
60 });
61 }
62 let mut out = [0u8; N];
63 out.copy_from_slice(&bytes);
64 Ok(out)
65}