use thiserror::Error;
#[derive(Debug, Error)]
pub enum PubkeyError {
#[error("invalid base58")]
InvalidBase58,
#[error("wrong length: expected 32 bytes, got {0}")]
WrongLength(usize),
}
pub fn validate_solana_pubkey(s: &str) -> Result<String, PubkeyError> {
let bytes = bs58::decode(s)
.into_vec()
.map_err(|_| PubkeyError::InvalidBase58)?;
if bytes.len() != 32 {
return Err(PubkeyError::WrongLength(bytes.len()));
}
Ok(bs58::encode(&bytes).into_string())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn accepts_canonical_32_byte_pubkey() {
let canonical = "11111111111111111111111111111111";
let out = validate_solana_pubkey(canonical).expect("valid");
assert_eq!(out, canonical);
}
#[test]
fn rejects_empty_string() {
let err = validate_solana_pubkey("").expect_err("empty must fail");
assert!(matches!(err, PubkeyError::WrongLength(0)));
}
#[test]
fn rejects_non_base58() {
let err = validate_solana_pubkey("0OIl/+=").expect_err("invalid b58 must fail");
assert!(matches!(err, PubkeyError::InvalidBase58));
}
#[test]
fn rejects_wrong_length() {
let too_long = bs58::encode([0u8; 33]).into_string();
let err = validate_solana_pubkey(&too_long).expect_err("33 bytes must fail");
assert!(matches!(err, PubkeyError::WrongLength(33)));
}
}