use bitcoin::util::address::WitnessVersion;
use bitcoin_scripts::{PubkeyScript, RedeemScript};
use crate::CompositeDescrType;
#[derive(
Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display, Error
)]
#[display(doc_comments)]
pub enum DeductionError {
NonTaprootV1,
UnsupportedWitnessVersion(WitnessVersion),
P2shWithoutRedeemScript,
InvalidRedeemScript,
}
impl CompositeDescrType {
pub fn deduce(
spk: &PubkeyScript,
redeem_script: Option<&RedeemScript>,
witness_script_known: bool,
) -> Result<Self, DeductionError> {
let witness_version = spk.witness_version();
match (spk, witness_version) {
(spk, _) if spk.is_p2pk() => Ok(CompositeDescrType::Pk),
(spk, _) if spk.is_p2pkh() => Ok(CompositeDescrType::Pkh),
(spk, _) if spk.is_v0_p2wpkh() => Ok(CompositeDescrType::Wpkh),
(spk, _) if spk.is_v0_p2wsh() => Ok(CompositeDescrType::Wsh),
(spk, _) if spk.is_v1_p2tr() => Ok(CompositeDescrType::Tr),
(spk, _) if spk.is_p2sh() => {
let redeem_script = if let Some(redeem_script) = redeem_script {
redeem_script
} else {
return Err(DeductionError::P2shWithoutRedeemScript);
};
if witness_script_known {
if redeem_script.is_v0_p2wpkh() {
Ok(CompositeDescrType::ShWpkh)
} else if redeem_script.is_v0_p2wsh() {
Ok(CompositeDescrType::ShWsh)
} else {
Err(DeductionError::InvalidRedeemScript)
}
} else {
Ok(CompositeDescrType::Sh)
}
}
(_, Some(WitnessVersion::V1)) => Err(DeductionError::NonTaprootV1),
(_, Some(version)) => Err(DeductionError::UnsupportedWitnessVersion(version)),
(_, None) => Ok(CompositeDescrType::Bare),
}
}
}