use bech32::{decode, encode, FromBase32, ToBase32, Variant};
use cosmwasm_std::testing::MockApi;
use cosmwasm_std::{
Addr, Api, CanonicalAddr, RecoverPubkeyError, StdError, StdResult, VerificationError,
};
use sha2::{Digest, Sha256};
pub struct MockApiBech32 {
api: MockApi,
prefix: String,
variant: Variant,
}
impl MockApiBech32 {
pub fn new(prefix: &str) -> Self {
Self::new_with_variant(prefix, Variant::Bech32)
}
pub(crate) fn new_with_variant(prefix: &str, variant: Variant) -> Self {
Self {
api: MockApi::default(),
prefix: prefix.to_string(),
variant,
}
}
}
impl Api for MockApiBech32 {
fn addr_validate(&self, input: &str) -> StdResult<Addr> {
self.addr_humanize(&self.addr_canonicalize(input)?)
}
fn addr_canonicalize(&self, input: &str) -> StdResult<CanonicalAddr> {
if let Ok((prefix, decoded, variant)) = decode(input) {
if prefix == self.prefix && variant == self.variant {
if let Ok(bytes) = Vec::<u8>::from_base32(&decoded) {
return Ok(bytes.into());
}
}
}
Err(StdError::generic_err("Invalid input"))
}
fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult<Addr> {
if let Ok(encoded) = encode(&self.prefix, canonical.as_slice().to_base32(), self.variant) {
Ok(Addr::unchecked(encoded))
} else {
Err(StdError::generic_err("Invalid canonical address"))
}
}
fn secp256k1_verify(
&self,
message_hash: &[u8],
signature: &[u8],
public_key: &[u8],
) -> Result<bool, VerificationError> {
self.api
.secp256k1_verify(message_hash, signature, public_key)
}
fn secp256k1_recover_pubkey(
&self,
message_hash: &[u8],
signature: &[u8],
recovery_param: u8,
) -> Result<Vec<u8>, RecoverPubkeyError> {
self.api
.secp256k1_recover_pubkey(message_hash, signature, recovery_param)
}
fn ed25519_verify(
&self,
message: &[u8],
signature: &[u8],
public_key: &[u8],
) -> Result<bool, VerificationError> {
self.api.ed25519_verify(message, signature, public_key)
}
fn ed25519_batch_verify(
&self,
messages: &[&[u8]],
signatures: &[&[u8]],
public_keys: &[&[u8]],
) -> Result<bool, VerificationError> {
self.api
.ed25519_batch_verify(messages, signatures, public_keys)
}
fn debug(&self, message: &str) {
self.api.debug(message)
}
}
impl MockApiBech32 {
pub fn addr_make(&self, input: &str) -> Addr {
let digest = Sha256::digest(input).to_vec();
match encode(&self.prefix, digest.to_base32(), self.variant) {
Ok(address) => Addr::unchecked(address),
Err(reason) => panic!("Generating address failed with reason: {}", reason),
}
}
}