use cometbft::CometbftKey;
use serde::{Deserialize, Serialize};
use subtle_encoding::{base64, bech32};
const ED25519_TYPE_URL: &str = "/cosmos.crypto.ed25519.PubKey";
const SECP256K1_TYPE_URL: &str = "/cosmos.crypto.secp256k1.PubKey";
#[derive(Clone, Debug, Deserialize)]
#[serde(tag = "type")]
pub enum Format {
#[serde(rename = "bech32")]
Bech32 {
account_key_prefix: String,
consensus_key_prefix: String,
},
#[serde(rename = "cosmos-json")]
CosmosJson,
#[serde(rename = "hex")]
Hex,
}
impl Format {
pub fn serialize(&self, public_key: CometbftKey) -> String {
match self {
Format::Bech32 {
account_key_prefix,
consensus_key_prefix,
} => match public_key {
CometbftKey::AccountKey(pk) => {
bech32::encode(account_key_prefix, cometbft::account::Id::from(pk))
}
CometbftKey::ConsensusKey(pk) => pk.to_bech32(consensus_key_prefix),
},
Format::CosmosJson => {
let pk = match public_key {
CometbftKey::AccountKey(pk) => PublicKeyJson::from(&pk),
CometbftKey::ConsensusKey(pk) => PublicKeyJson::from(&pk),
};
serde_json::to_string(&pk).expect("JSON serialization error")
}
Format::Hex => match public_key {
CometbftKey::AccountKey(pk) => pk.to_hex(),
CometbftKey::ConsensusKey(pk) => pk.to_hex(),
},
}
}
}
#[derive(Deserialize, Serialize)]
struct PublicKeyJson {
#[serde(rename = "@type")]
type_url: String,
key: String,
}
impl From<&cometbft::PublicKey> for PublicKeyJson {
fn from(public_key: &cometbft::PublicKey) -> PublicKeyJson {
let type_url = match public_key {
cometbft::PublicKey::Ed25519(_) => ED25519_TYPE_URL,
cometbft::PublicKey::Secp256k1(_) => SECP256K1_TYPE_URL,
_ => unreachable!("unknown pubic key type"),
}
.to_owned();
let key = String::from_utf8(base64::encode(public_key.to_bytes())).expect("UTF-8 error");
PublicKeyJson { type_url, key }
}
}