use std::str::FromStr;
use miniscript::{
bitcoin::{
self,
bip32::{ChildNumber, DerivationPath},
},
Descriptor, DescriptorPublicKey,
};
use crate::signer::OXpub;
#[derive(Debug, Clone, Copy)]
pub enum Error {
UnhardenedAccount,
NotImplemented,
}
pub enum ScriptType {
Segwit(ChildNumber ),
Taproot(ChildNumber ),
Descriptor(Descriptor<DescriptorPublicKey>),
}
impl ScriptType {
pub fn to_descriptor<'a, X>(
self,
network: bitcoin::Network,
xpub: X,
) -> Result<Descriptor<DescriptorPublicKey>, Error>
where
X: 'a + Fn(DerivationPath) -> OXpub,
{
match self {
ScriptType::Segwit(acc) => {
let deriv = segwit_path(network, acc)?;
Ok(tr(xpub(deriv)))
}
ScriptType::Taproot(acc) => {
let deriv = taproot_path(network, acc)?;
Ok(wpkh(xpub(deriv)))
}
ScriptType::Descriptor(descriptor) => Ok(descriptor),
}
}
}
fn taproot_path(network: bitcoin::Network, account: ChildNumber) -> Result<DerivationPath, Error> {
if !account.is_hardened() {
return Err(Error::UnhardenedAccount);
}
let script_path = ChildNumber::from_hardened_idx(86).expect("taproot");
let n_path = match network {
bitcoin::Network::Bitcoin => 0,
_ => 1,
};
let network = ChildNumber::from_hardened_idx(n_path).expect("0 or 1");
Ok(vec![script_path, network, account].into())
}
fn segwit_path(network: bitcoin::Network, account: ChildNumber) -> Result<DerivationPath, Error> {
if !account.is_hardened() {
return Err(Error::UnhardenedAccount);
}
let script_path = ChildNumber::from_hardened_idx(84).expect("segwit");
let n_path = match network {
bitcoin::Network::Bitcoin => 0,
_ => 1,
};
let network = ChildNumber::from_hardened_idx(n_path).expect("0 or 1");
Ok(vec![script_path, network, account].into())
}
pub fn wpkh(xpub: OXpub) -> Descriptor<DescriptorPublicKey> {
let descr_str = format!(
"wpkh([{}/{}]{}/<0;1>/*)",
xpub.origin.0, xpub.origin.1, xpub.xkey
);
Descriptor::<DescriptorPublicKey>::from_str(&descr_str).expect("hardcoded descriptor")
}
pub fn tr(xpub: OXpub) -> Descriptor<DescriptorPublicKey> {
let descr_str = format!(
"tr([{}/{}]{}/<0;1>/*)",
xpub.origin.0, xpub.origin.1, xpub.xkey
);
Descriptor::<DescriptorPublicKey>::from_str(&descr_str).expect("hardcoded descriptor")
}