// Bitcoin Dev Kit // Written in 2020 by Alekos Filini // // Copyright (c) 2020-2021 Bitcoin Dev Kit Developers // // This file is licensed under the Apache License, Version 2.0 or the MIT license // , at your option. // You may not use this file except in accordance with one or both of these // licenses. //! Descriptor templates //! //! This module contains the definition of various common script templates that are ready to be //! used. See the documentation of each template for an example. use bitcoin::util::bip32; use bitcoin::Network; use miniscript::{Legacy, Segwitv0}; use super::{ExtendedDescriptor, IntoWalletDescriptor, KeyMap}; use crate::descriptor::DescriptorError; use crate::keys::{DerivableKey, IntoDescriptorKey, ValidNetworks}; use crate::wallet::utils::SecpCtx; use crate::{descriptor, KeychainKind}; /// Type alias for the return type of [`DescriptorTemplate`], [`descriptor!`](crate::descriptor!) and others pub type DescriptorTemplateOut = (ExtendedDescriptor, KeyMap, ValidNetworks); /// Trait for descriptor templates that can be built into a full descriptor /// /// Since [`IntoWalletDescriptor`] is implemented for any [`DescriptorTemplate`], they can also be /// passed directly to the [`Wallet`](crate::Wallet) constructor. /// /// ## Example /// /// ``` /// use bdk::descriptor::error::Error as DescriptorError; /// use bdk::keys::{KeyError, IntoDescriptorKey}; /// use bdk::miniscript::Legacy; /// use bdk::template::{DescriptorTemplate, DescriptorTemplateOut}; /// /// struct MyP2PKH>(K); /// /// impl> DescriptorTemplate for MyP2PKH { /// fn build(self) -> Result { /// Ok(bdk::descriptor!(pkh(self.0))?) /// } /// } /// ``` pub trait DescriptorTemplate { /// Build the complete descriptor fn build(self) -> Result; } /// Turns a [`DescriptorTemplate`] into a valid wallet descriptor by calling its /// [`build`](DescriptorTemplate::build) method impl IntoWalletDescriptor for T { fn into_wallet_descriptor( self, secp: &SecpCtx, network: Network, ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> { self.build()?.into_wallet_descriptor(secp, network) } } /// P2PKH template. Expands to a descriptor `pkh(key)` /// /// ## Example /// /// ``` /// # use bdk::bitcoin::{PrivateKey, Network}; /// # use bdk::{Wallet}; /// # use bdk::database::MemoryDatabase; /// use bdk::template::P2PKH; /// /// let key = /// bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?; /// let wallet = Wallet::new_offline( /// P2PKH(key), /// None, /// Network::Testnet, /// MemoryDatabase::default(), /// )?; /// /// assert_eq!( /// wallet.get_new_address()?.to_string(), /// "mwJ8hxFYW19JLuc65RCTaP4v1rzVU8cVMT" /// ); /// # Ok::<_, Box>(()) /// ``` pub struct P2PKH>(pub K); impl> DescriptorTemplate for P2PKH { fn build(self) -> Result { descriptor!(pkh(self.0)) } } /// P2WPKH-P2SH template. Expands to a descriptor `sh(wpkh(key))` /// /// ## Example /// /// ``` /// # use bdk::bitcoin::{PrivateKey, Network}; /// # use bdk::{Wallet}; /// # use bdk::database::MemoryDatabase; /// use bdk::template::P2WPKH_P2SH; /// /// let key = /// bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?; /// let wallet = Wallet::new_offline( /// P2WPKH_P2SH(key), /// None, /// Network::Testnet, /// MemoryDatabase::default(), /// )?; /// /// assert_eq!( /// wallet.get_new_address()?.to_string(), /// "2NB4ox5VDRw1ecUv6SnT3VQHPXveYztRqk5" /// ); /// # Ok::<_, Box>(()) /// ``` #[allow(non_camel_case_types)] pub struct P2WPKH_P2SH>(pub K); impl> DescriptorTemplate for P2WPKH_P2SH { fn build(self) -> Result { descriptor!(sh(wpkh(self.0))) } } /// P2WPKH template. Expands to a descriptor `wpkh(key)` /// /// ## Example /// /// ``` /// # use bdk::bitcoin::{PrivateKey, Network}; /// # use bdk::{Wallet}; /// # use bdk::database::MemoryDatabase; /// use bdk::template::P2WPKH; /// /// let key = /// bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?; /// let wallet = Wallet::new_offline( /// P2WPKH(key), /// None, /// Network::Testnet, /// MemoryDatabase::default(), /// )?; /// /// assert_eq!( /// wallet.get_new_address()?.to_string(), /// "tb1q4525hmgw265tl3drrl8jjta7ayffu6jf68ltjd" /// ); /// # Ok::<_, Box>(()) /// ``` pub struct P2WPKH>(pub K); impl> DescriptorTemplate for P2WPKH { fn build(self) -> Result { descriptor!(wpkh(self.0)) } } /// BIP44 template. Expands to `pkh(key/44'/0'/0'/{0,1}/*)` /// /// Since there are hardened derivation steps, this template requires a private derivable key (generally a `xprv`/`tprv`). /// /// See [`BIP44Public`] for a template that can work with a `xpub`/`tpub`. /// /// ## Example /// /// ``` /// # use std::str::FromStr; /// # use bdk::bitcoin::{PrivateKey, Network}; /// # use bdk::{Wallet, KeychainKind}; /// # use bdk::database::MemoryDatabase; /// use bdk::template::BIP44; /// /// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?; /// let wallet = Wallet::new_offline( /// BIP44(key.clone(), KeychainKind::External), /// Some(BIP44(key, KeychainKind::Internal)), /// Network::Testnet, /// MemoryDatabase::default() /// )?; /// /// assert_eq!(wallet.get_new_address()?.to_string(), "miNG7dJTzJqNbFS19svRdTCisC65dsubtR"); /// assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "pkh([c55b303f/44'/0'/0']tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU/0/*)#xgaaevjx"); /// # Ok::<_, Box>(()) /// ``` pub struct BIP44>(pub K, pub KeychainKind); impl> DescriptorTemplate for BIP44 { fn build(self) -> Result { P2PKH(legacy::make_bipxx_private(44, self.0, self.1)?).build() } } /// BIP44 public template. Expands to `pkh(key/{0,1}/*)` /// /// This assumes that the key used has already been derived with `m/44'/0'/0'`. /// /// This template requires the parent fingerprint to populate correctly the metadata of PSBTs. /// /// See [`BIP44`] for a template that does the full derivation, but requires private data /// for the key. /// /// ## Example /// /// ``` /// # use std::str::FromStr; /// # use bdk::bitcoin::{PrivateKey, Network}; /// # use bdk::{Wallet, KeychainKind}; /// # use bdk::database::MemoryDatabase; /// use bdk::template::BIP44Public; /// /// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU")?; /// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?; /// let wallet = Wallet::new_offline( /// BIP44Public(key.clone(), fingerprint, KeychainKind::External), /// Some(BIP44Public(key, fingerprint, KeychainKind::Internal)), /// Network::Testnet, /// MemoryDatabase::default() /// )?; /// /// assert_eq!(wallet.get_new_address()?.to_string(), "miNG7dJTzJqNbFS19svRdTCisC65dsubtR"); /// assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "pkh([c55b303f/44'/0'/0']tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU/0/*)#xgaaevjx"); /// # Ok::<_, Box>(()) /// ``` pub struct BIP44Public>(pub K, pub bip32::Fingerprint, pub KeychainKind); impl> DescriptorTemplate for BIP44Public { fn build(self) -> Result { P2PKH(legacy::make_bipxx_public(44, self.0, self.1, self.2)?).build() } } /// BIP49 template. Expands to `sh(wpkh(key/49'/0'/0'/{0,1}/*))` /// /// Since there are hardened derivation steps, this template requires a private derivable key (generally a `xprv`/`tprv`). /// /// See [`BIP49Public`] for a template that can work with a `xpub`/`tpub`. /// /// ## Example /// /// ``` /// # use std::str::FromStr; /// # use bdk::bitcoin::{PrivateKey, Network}; /// # use bdk::{Wallet, KeychainKind}; /// # use bdk::database::MemoryDatabase; /// use bdk::template::BIP49; /// /// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?; /// let wallet = Wallet::new_offline( /// BIP49(key.clone(), KeychainKind::External), /// Some(BIP49(key, KeychainKind::Internal)), /// Network::Testnet, /// MemoryDatabase::default() /// )?; /// /// assert_eq!(wallet.get_new_address()?.to_string(), "2N3K4xbVAHoiTQSwxkZjWDfKoNC27pLkYnt"); /// assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "sh(wpkh([c55b303f/49\'/0\'/0\']tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L/0/*))#gsmdv4xr"); /// # Ok::<_, Box>(()) /// ``` pub struct BIP49>(pub K, pub KeychainKind); impl> DescriptorTemplate for BIP49 { fn build(self) -> Result { P2WPKH_P2SH(segwit_v0::make_bipxx_private(49, self.0, self.1)?).build() } } /// BIP49 public template. Expands to `sh(wpkh(key/{0,1}/*))` /// /// This assumes that the key used has already been derived with `m/49'/0'/0'`. /// /// This template requires the parent fingerprint to populate correctly the metadata of PSBTs. /// /// See [`BIP49`] for a template that does the full derivation, but requires private data /// for the key. /// /// ## Example /// /// ``` /// # use std::str::FromStr; /// # use bdk::bitcoin::{PrivateKey, Network}; /// # use bdk::{Wallet, KeychainKind}; /// # use bdk::database::MemoryDatabase; /// use bdk::template::BIP49Public; /// /// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L")?; /// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?; /// let wallet = Wallet::new_offline( /// BIP49Public(key.clone(), fingerprint, KeychainKind::External), /// Some(BIP49Public(key, fingerprint, KeychainKind::Internal)), /// Network::Testnet, /// MemoryDatabase::default() /// )?; /// /// assert_eq!(wallet.get_new_address()?.to_string(), "2N3K4xbVAHoiTQSwxkZjWDfKoNC27pLkYnt"); /// assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "sh(wpkh([c55b303f/49\'/0\'/0\']tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L/0/*))#gsmdv4xr"); /// # Ok::<_, Box>(()) /// ``` pub struct BIP49Public>(pub K, pub bip32::Fingerprint, pub KeychainKind); impl> DescriptorTemplate for BIP49Public { fn build(self) -> Result { P2WPKH_P2SH(segwit_v0::make_bipxx_public(49, self.0, self.1, self.2)?).build() } } /// BIP84 template. Expands to `wpkh(key/84'/0'/0'/{0,1}/*)` /// /// Since there are hardened derivation steps, this template requires a private derivable key (generally a `xprv`/`tprv`). /// /// See [`BIP84Public`] for a template that can work with a `xpub`/`tpub`. /// /// ## Example /// /// ``` /// # use std::str::FromStr; /// # use bdk::bitcoin::{PrivateKey, Network}; /// # use bdk::{Wallet, KeychainKind}; /// # use bdk::database::MemoryDatabase; /// use bdk::template::BIP84; /// /// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?; /// let wallet = Wallet::new_offline( /// BIP84(key.clone(), KeychainKind::External), /// Some(BIP84(key, KeychainKind::Internal)), /// Network::Testnet, /// MemoryDatabase::default() /// )?; /// /// assert_eq!(wallet.get_new_address()?.to_string(), "tb1qedg9fdlf8cnnqfd5mks6uz5w4kgpk2pr6y4qc7"); /// assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "wpkh([c55b303f/84\'/0\'/0\']tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q/0/*)#nkk5dtkg"); /// # Ok::<_, Box>(()) /// ``` pub struct BIP84>(pub K, pub KeychainKind); impl> DescriptorTemplate for BIP84 { fn build(self) -> Result { P2WPKH(segwit_v0::make_bipxx_private(84, self.0, self.1)?).build() } } /// BIP84 public template. Expands to `wpkh(key/{0,1}/*)` /// /// This assumes that the key used has already been derived with `m/84'/0'/0'`. /// /// This template requires the parent fingerprint to populate correctly the metadata of PSBTs. /// /// See [`BIP84`] for a template that does the full derivation, but requires private data /// for the key. /// /// ## Example /// /// ``` /// # use std::str::FromStr; /// # use bdk::bitcoin::{PrivateKey, Network}; /// # use bdk::{Wallet, KeychainKind}; /// # use bdk::database::MemoryDatabase; /// use bdk::template::BIP84Public; /// /// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?; /// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?; /// let wallet = Wallet::new_offline( /// BIP84Public(key.clone(), fingerprint, KeychainKind::External), /// Some(BIP84Public(key, fingerprint, KeychainKind::Internal)), /// Network::Testnet, /// MemoryDatabase::default() /// )?; /// /// assert_eq!(wallet.get_new_address()?.to_string(), "tb1qedg9fdlf8cnnqfd5mks6uz5w4kgpk2pr6y4qc7"); /// assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "wpkh([c55b303f/84\'/0\'/0\']tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q/0/*)#nkk5dtkg"); /// # Ok::<_, Box>(()) /// ``` pub struct BIP84Public>(pub K, pub bip32::Fingerprint, pub KeychainKind); impl> DescriptorTemplate for BIP84Public { fn build(self) -> Result { P2WPKH(segwit_v0::make_bipxx_public(84, self.0, self.1, self.2)?).build() } } macro_rules! expand_make_bipxx { ( $mod_name:ident, $ctx:ty ) => { mod $mod_name { use super::*; pub(super) fn make_bipxx_private>( bip: u32, key: K, keychain: KeychainKind, ) -> Result, DescriptorError> { let mut derivation_path = Vec::with_capacity(4); derivation_path.push(bip32::ChildNumber::from_hardened_idx(bip)?); derivation_path.push(bip32::ChildNumber::from_hardened_idx(0)?); derivation_path.push(bip32::ChildNumber::from_hardened_idx(0)?); match keychain { KeychainKind::External => { derivation_path.push(bip32::ChildNumber::from_normal_idx(0)?) } KeychainKind::Internal => { derivation_path.push(bip32::ChildNumber::from_normal_idx(1)?) } }; let derivation_path: bip32::DerivationPath = derivation_path.into(); Ok((key, derivation_path)) } pub(super) fn make_bipxx_public>( bip: u32, key: K, parent_fingerprint: bip32::Fingerprint, keychain: KeychainKind, ) -> Result, DescriptorError> { let derivation_path: bip32::DerivationPath = match keychain { KeychainKind::External => vec![bip32::ChildNumber::from_normal_idx(0)?].into(), KeychainKind::Internal => vec![bip32::ChildNumber::from_normal_idx(1)?].into(), }; let source_path = bip32::DerivationPath::from(vec![ bip32::ChildNumber::from_hardened_idx(bip)?, bip32::ChildNumber::from_hardened_idx(0)?, bip32::ChildNumber::from_hardened_idx(0)?, ]); Ok((key, (parent_fingerprint, source_path), derivation_path)) } } }; } expand_make_bipxx!(legacy, Legacy); expand_make_bipxx!(segwit_v0, Segwitv0); #[cfg(test)] mod test { // test existing descriptor templates, make sure they are expanded to the right descriptors use super::*; use crate::descriptor::derived::AsDerived; use crate::descriptor::{DescriptorError, DescriptorMeta}; use crate::keys::ValidNetworks; use bitcoin::hashes::core::str::FromStr; use bitcoin::network::constants::Network::Regtest; use bitcoin::secp256k1::Secp256k1; use miniscript::descriptor::{DescriptorPublicKey, DescriptorTrait, KeyMap}; use miniscript::Descriptor; // verify template descriptor generates expected address(es) fn check( desc: Result<(Descriptor, KeyMap, ValidNetworks), DescriptorError>, is_witness: bool, is_fixed: bool, expected: &[&str], ) { let secp = Secp256k1::new(); let (desc, _key_map, _networks) = desc.unwrap(); assert_eq!(desc.is_witness(), is_witness); assert_eq!(!desc.is_deriveable(), is_fixed); for i in 0..expected.len() { let index = i as u32; let child_desc = if !desc.is_deriveable() { desc.as_derived_fixed(&secp) } else { desc.as_derived(index, &secp) }; let address = child_desc.address(Regtest).unwrap(); assert_eq!(address.to_string(), *expected.get(i).unwrap()); } } // P2PKH #[test] fn test_p2ph_template() { let prvkey = bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um") .unwrap(); check( P2PKH(prvkey).build(), false, true, &["mwJ8hxFYW19JLuc65RCTaP4v1rzVU8cVMT"], ); let pubkey = bitcoin::PublicKey::from_str( "03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd", ) .unwrap(); check( P2PKH(pubkey).build(), false, true, &["muZpTpBYhxmRFuCjLc7C6BBDF32C8XVJUi"], ); } // P2WPKH-P2SH `sh(wpkh(key))` #[test] fn test_p2wphp2sh_template() { let prvkey = bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um") .unwrap(); check( P2WPKH_P2SH(prvkey).build(), true, true, &["2NB4ox5VDRw1ecUv6SnT3VQHPXveYztRqk5"], ); let pubkey = bitcoin::PublicKey::from_str( "03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd", ) .unwrap(); check( P2WPKH_P2SH(pubkey).build(), true, true, &["2N5LiC3CqzxDamRTPG1kiNv1FpNJQ7x28sb"], ); } // P2WPKH `wpkh(key)` #[test] fn test_p2wph_template() { let prvkey = bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um") .unwrap(); check( P2WPKH(prvkey).build(), true, true, &["bcrt1q4525hmgw265tl3drrl8jjta7ayffu6jfcwxx9y"], ); let pubkey = bitcoin::PublicKey::from_str( "03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd", ) .unwrap(); check( P2WPKH(pubkey).build(), true, true, &["bcrt1qngw83fg8dz0k749cg7k3emc7v98wy0c7azaa6h"], ); } // BIP44 `pkh(key/44'/0'/0'/{0,1}/*)` #[test] fn test_bip44_template() { let prvkey = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); check( BIP44(prvkey, KeychainKind::External).build(), false, false, &[ "n453VtnjDHPyDt2fDstKSu7A3YCJoHZ5g5", "mvfrrumXgTtwFPWDNUecBBgzuMXhYM7KRP", "mzYvhRAuQqbdSKMVVzXNYyqihgNdRadAUQ", ], ); check( BIP44(prvkey, KeychainKind::Internal).build(), false, false, &[ "muHF98X9KxEzdKrnFAX85KeHv96eXopaip", "n4hpyLJE5ub6B5Bymv4eqFxS5KjrewSmYR", "mgvkdv1ffmsXd2B1sRKQ5dByK3SzpG42rA", ], ); } // BIP44 public `pkh(key/{0,1}/*)` #[test] fn test_bip44_public_template() { let pubkey = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU").unwrap(); let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f").unwrap(); check( BIP44Public(pubkey, fingerprint, KeychainKind::External).build(), false, false, &[ "miNG7dJTzJqNbFS19svRdTCisC65dsubtR", "n2UqaDbCjWSFJvpC84m3FjUk5UaeibCzYg", "muCPpS6Ue7nkzeJMWDViw7Lkwr92Yc4K8g", ], ); check( BIP44Public(pubkey, fingerprint, KeychainKind::Internal).build(), false, false, &[ "moDr3vJ8wpt5nNxSK55MPq797nXJb2Ru9H", "ms7A1Yt4uTezT2XkefW12AvLoko8WfNJMG", "mhYiyat2rtEnV77cFfQsW32y1m2ceCGHPo", ], ); } // BIP49 `sh(wpkh(key/49'/0'/0'/{0,1}/*))` #[test] fn test_bip49_template() { let prvkey = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); check( BIP49(prvkey, KeychainKind::External).build(), true, false, &[ "2N9bCAJXGm168MjVwpkBdNt6ucka3PKVoUV", "2NDckYkqrYyDMtttEav5hB3Bfw9EGAW5HtS", "2NAFTVtksF9T4a97M7nyCjwUBD24QevZ5Z4", ], ); check( BIP49(prvkey, KeychainKind::Internal).build(), true, false, &[ "2NB3pA8PnzJLGV8YEKNDFpbViZv3Bm1K6CG", "2NBiX2Wzxngb5rPiWpUiJQ2uLVB4HBjFD4p", "2NA8ek4CdQ6aMkveYF6AYuEYNrftB47QGTn", ], ); } // BIP49 public `sh(wpkh(key/{0,1}/*))` #[test] fn test_bip49_public_template() { let pubkey = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L").unwrap(); let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f").unwrap(); check( BIP49Public(pubkey, fingerprint, KeychainKind::External).build(), true, false, &[ "2N3K4xbVAHoiTQSwxkZjWDfKoNC27pLkYnt", "2NCTQfJ1sZa3wQ3pPseYRHbaNEpC3AquEfX", "2MveFxAuC8BYPzTybx7FxSzW8HSd8ATT4z7", ], ); check( BIP49Public(pubkey, fingerprint, KeychainKind::Internal).build(), true, false, &[ "2NF2vttKibwyxigxtx95Zw8K7JhDbo5zPVJ", "2Mtmyd8taksxNVWCJ4wVvaiss7QPZGcAJuH", "2NBs3CTVYPr1HCzjB4YFsnWCPCtNg8uMEfp", ], ); } // BIP84 `wpkh(key/84'/0'/0'/{0,1}/*)` #[test] fn test_bip84_template() { let prvkey = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); check( BIP84(prvkey, KeychainKind::External).build(), true, false, &[ "bcrt1qkmvk2nadgplmd57ztld8nf8v2yxkzmdvwtjf8s", "bcrt1qx0v6zgfwe50m4kqc58cqzcyem7ay2sfl3gvqhp", "bcrt1q4h7fq9zhxst6e69p3n882nfj649l7w9g3zccfp", ], ); check( BIP84(prvkey, KeychainKind::Internal).build(), true, false, &[ "bcrt1qtrwtz00wxl69e5xex7amy4xzlxkaefg3gfdkxa", "bcrt1qqqasfhxpkkf7zrxqnkr2sfhn74dgsrc3e3ky45", "bcrt1qpks7n0gq74hsgsz3phn5vuazjjq0f5eqhsgyce", ], ); } // BIP84 public `wpkh(key/{0,1}/*)` #[test] fn test_bip84_public_template() { let pubkey = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q").unwrap(); let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f").unwrap(); check( BIP84Public(pubkey, fingerprint, KeychainKind::External).build(), true, false, &[ "bcrt1qedg9fdlf8cnnqfd5mks6uz5w4kgpk2prcdvd0h", "bcrt1q3lncdlwq3lgcaaeyruynjnlccr0ve0kakh6ana", "bcrt1qt9800y6xl3922jy3uyl0z33jh5wfpycyhcylr9", ], ); check( BIP84Public(pubkey, fingerprint, KeychainKind::Internal).build(), true, false, &[ "bcrt1qm6wqukenh7guu792lj2njgw9n78cmwsy8xy3z2", "bcrt1q694twxtjn4nnrvnyvra769j0a23rllj5c6cgwp", "bcrt1qhlac3c5ranv5w5emlnqs7wxhkxt8maelylcarp", ], ); } }