use bech32::{FromBase32, ToBase32};
pub use bech32::{Variant, Variant::*};
use serde::{Deserialize, Deserializer, Serializer};
pub fn decode(
string: &str,
expected_hrp: &str,
expected_variant: Variant,
) -> anyhow::Result<Vec<u8>> {
let (hrp, data, variant) = bech32::decode(string)?;
if variant != expected_variant {
anyhow::bail!(
"wrong bech32 variant {:?}, expected {:?}",
variant,
expected_variant
);
}
if hrp != expected_hrp {
anyhow::bail!(
"wrong bech32 human readable part {}, expected {}",
hrp,
expected_hrp
);
}
Ok(Vec::from_base32(&data).expect("bech32 decoding produces valid base32"))
}
pub fn encode(data: &[u8], hrp: &str, variant: Variant) -> String {
bech32::encode(hrp, data.to_base32(), variant).expect("HRP should be valid")
}
fn deserialize_bech32<'de, D>(
deserializer: D,
expected_hrp: &str,
expected_variant: Variant,
) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
{
decode(
&Option::<String>::deserialize(deserializer)?.unwrap_or_default(),
expected_hrp,
expected_variant,
)
.map_err(serde::de::Error::custom)
}
fn serialize_bech32<S, T>(
value: &T,
serializer: S,
hrp: &str,
variant: Variant,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: AsRef<[u8]>,
{
serializer.serialize_str(&encode(value.as_ref(), hrp, variant))
}
pub mod validator_identity_key {
use super::*;
pub const BECH32_PREFIX: &str = "penumbravalid";
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
{
deserialize_bech32(deserializer, BECH32_PREFIX, Variant::Bech32m)
}
pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: AsRef<[u8]>,
{
serialize_bech32(value, serializer, BECH32_PREFIX, Variant::Bech32m)
}
}
pub mod validator_governance_key {
use super::*;
pub const BECH32_PREFIX: &str = "penumbragovern";
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
{
deserialize_bech32(deserializer, BECH32_PREFIX, Variant::Bech32m)
}
pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: AsRef<[u8]>,
{
serialize_bech32(value, serializer, BECH32_PREFIX, Variant::Bech32m)
}
}
pub mod address {
use super::*;
pub const BECH32_PREFIX: &str = "penumbra";
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
{
deserialize_bech32(deserializer, BECH32_PREFIX, Variant::Bech32m)
}
pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: AsRef<[u8]>,
{
serialize_bech32(value, serializer, BECH32_PREFIX, Variant::Bech32m)
}
}
pub mod compat_address {
use super::*;
pub const BECH32_PREFIX: &str = "penumbracompat1";
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
{
deserialize_bech32(deserializer, BECH32_PREFIX, Variant::Bech32)
}
pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: AsRef<[u8]>,
{
serialize_bech32(value, serializer, BECH32_PREFIX, Variant::Bech32)
}
}
pub mod asset_id {
use super::*;
pub const BECH32_PREFIX: &str = "passet";
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
{
deserialize_bech32(deserializer, BECH32_PREFIX, Variant::Bech32m)
}
pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: AsRef<[u8]>,
{
serialize_bech32(value, serializer, BECH32_PREFIX, Variant::Bech32m)
}
}
pub mod full_viewing_key {
use super::*;
pub const BECH32_PREFIX: &str = "penumbrafullviewingkey";
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
{
deserialize_bech32(deserializer, BECH32_PREFIX, Variant::Bech32m)
}
pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: AsRef<[u8]>,
{
serialize_bech32(value, serializer, BECH32_PREFIX, Variant::Bech32m)
}
}
pub mod wallet_id {
use super::*;
pub const BECH32_PREFIX: &str = "penumbrawalletid";
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
{
deserialize_bech32(deserializer, BECH32_PREFIX, Bech32m)
}
pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: AsRef<[u8]>,
{
serialize_bech32(value, serializer, BECH32_PREFIX, Bech32m)
}
}
pub mod spend_key {
use super::*;
pub const BECH32_PREFIX: &str = "penumbraspendkey";
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
{
deserialize_bech32(deserializer, BECH32_PREFIX, Variant::Bech32m)
}
pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: AsRef<[u8]>,
{
serialize_bech32(value, serializer, BECH32_PREFIX, Variant::Bech32m)
}
}
pub mod lp_id {
use super::*;
pub const BECH32_PREFIX: &str = "plpid";
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
{
deserialize_bech32(deserializer, BECH32_PREFIX, Variant::Bech32m)
}
pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: AsRef<[u8]>,
{
serialize_bech32(value, serializer, BECH32_PREFIX, Variant::Bech32m)
}
}
pub mod auction_id {
use super::*;
pub const BECH32_PREFIX: &str = "pauctid";
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
{
deserialize_bech32(deserializer, BECH32_PREFIX, Variant::Bech32m)
}
pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: AsRef<[u8]>,
{
serialize_bech32(value, serializer, BECH32_PREFIX, Variant::Bech32m)
}
}