bdk_wallet/descriptor/
template.rs

1// Bitcoin Dev Kit
2// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
3//
4// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
5//
6// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
7// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
8// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
9// You may not use this file except in accordance with one or both of these
10// licenses.
11
12//! Descriptor templates
13//!
14//! This module contains the definition of various common script templates that are ready to be
15//! used. See the documentation of each template for an example.
16
17use bitcoin::bip32;
18use bitcoin::Network;
19
20use miniscript::{Legacy, Segwitv0, Tap};
21
22use super::{ExtendedDescriptor, IntoWalletDescriptor, KeyMap};
23use crate::descriptor::DescriptorError;
24use crate::keys::{DerivableKey, IntoDescriptorKey, ValidNetworks};
25use crate::wallet::utils::SecpCtx;
26use crate::{descriptor, KeychainKind};
27
28/// Type alias for the return type of [`DescriptorTemplate`], [`descriptor!`](crate::descriptor!)
29/// and others
30pub type DescriptorTemplateOut = (ExtendedDescriptor, KeyMap, ValidNetworks);
31
32/// Trait for descriptor templates that can be built into a full descriptor
33///
34/// Since [`IntoWalletDescriptor`] is implemented for any [`DescriptorTemplate`], they can also be
35/// passed directly to the [`Wallet`](crate::Wallet) constructor.
36///
37/// ## Example
38///
39/// ```
40/// use bdk_wallet::descriptor::error::Error as DescriptorError;
41/// use bdk_wallet::keys::{IntoDescriptorKey, KeyError};
42/// use bdk_wallet::miniscript::Legacy;
43/// use bdk_wallet::template::{DescriptorTemplate, DescriptorTemplateOut};
44/// use bitcoin::Network;
45///
46/// struct MyP2PKH<K: IntoDescriptorKey<Legacy>>(K);
47///
48/// impl<K: IntoDescriptorKey<Legacy>> DescriptorTemplate for MyP2PKH<K> {
49///     fn build(self, network: Network) -> Result<DescriptorTemplateOut, DescriptorError> {
50///         Ok(bdk_wallet::descriptor!(pkh(self.0))?)
51///     }
52/// }
53/// ```
54pub trait DescriptorTemplate {
55    /// Build the complete descriptor
56    fn build(self, network: Network) -> Result<DescriptorTemplateOut, DescriptorError>;
57}
58
59/// Turns a [`DescriptorTemplate`] into a valid wallet descriptor by calling its
60/// [`build`](DescriptorTemplate::build) method
61impl<T: DescriptorTemplate> IntoWalletDescriptor for T {
62    fn into_wallet_descriptor(
63        self,
64        secp: &SecpCtx,
65        network: Network,
66    ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
67        self.build(network)?.into_wallet_descriptor(secp, network)
68    }
69}
70
71/// P2PKH template. Expands to a descriptor `pkh(key)`
72///
73/// ## Example
74///
75/// ```
76/// # use bdk_wallet::bitcoin::{PrivateKey, Network};
77/// # use bdk_wallet::Wallet;
78/// # use bdk_wallet::KeychainKind;
79/// use bdk_wallet::template::P2Pkh;
80///
81/// let key_external =
82///     bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
83/// let key_internal =
84///     bitcoin::PrivateKey::from_wif("cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW")?;
85/// let mut wallet = Wallet::create(P2Pkh(key_external), P2Pkh(key_internal))
86///     .network(Network::Testnet)
87///     .create_wallet_no_persist()?;
88///
89/// assert_eq!(
90///     wallet
91///         .next_unused_address(KeychainKind::External)
92///         .to_string(),
93///     "mwJ8hxFYW19JLuc65RCTaP4v1rzVU8cVMT"
94/// );
95/// # Ok::<_, Box<dyn std::error::Error>>(())
96/// ```
97#[derive(Debug, Clone)]
98pub struct P2Pkh<K: IntoDescriptorKey<Legacy>>(pub K);
99
100impl<K: IntoDescriptorKey<Legacy>> DescriptorTemplate for P2Pkh<K> {
101    fn build(self, _network: Network) -> Result<DescriptorTemplateOut, DescriptorError> {
102        descriptor!(pkh(self.0))
103    }
104}
105
106/// P2WPKH-P2SH template. Expands to a descriptor `sh(wpkh(key))`
107///
108/// ## Example
109///
110/// ```
111/// # use bdk_wallet::bitcoin::{PrivateKey, Network};
112/// # use bdk_wallet::Wallet;
113/// # use bdk_wallet::KeychainKind;
114/// use bdk_wallet::template::P2Wpkh_P2Sh;
115///
116/// let key_external =
117///     bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
118/// let key_internal =
119///     bitcoin::PrivateKey::from_wif("cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW")?;
120/// let mut wallet = Wallet::create(P2Wpkh_P2Sh(key_external), P2Wpkh_P2Sh(key_internal))
121///     .network(Network::Testnet)
122///     .create_wallet_no_persist()?;
123///
124/// assert_eq!(
125///     wallet
126///         .next_unused_address(KeychainKind::External)
127///         .to_string(),
128///     "2NB4ox5VDRw1ecUv6SnT3VQHPXveYztRqk5"
129/// );
130/// # Ok::<_, Box<dyn std::error::Error>>(())
131/// ```
132#[allow(non_camel_case_types)]
133#[derive(Debug, Clone)]
134pub struct P2Wpkh_P2Sh<K: IntoDescriptorKey<Segwitv0>>(pub K);
135
136impl<K: IntoDescriptorKey<Segwitv0>> DescriptorTemplate for P2Wpkh_P2Sh<K> {
137    fn build(self, _network: Network) -> Result<DescriptorTemplateOut, DescriptorError> {
138        descriptor!(sh(wpkh(self.0)))
139    }
140}
141
142/// P2WPKH template. Expands to a descriptor `wpkh(key)`
143///
144/// ## Example
145///
146/// ```
147/// # use bdk_wallet::bitcoin::{PrivateKey, Network};
148/// # use bdk_wallet::Wallet;
149/// # use bdk_wallet::KeychainKind;
150/// use bdk_wallet::template::P2Wpkh;
151///
152/// let key_external =
153///     bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
154/// let key_internal =
155///     bitcoin::PrivateKey::from_wif("cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW")?;
156/// let mut wallet = Wallet::create(P2Wpkh(key_external), P2Wpkh(key_internal))
157///     .network(Network::Testnet)
158///     .create_wallet_no_persist()?;
159///
160/// assert_eq!(
161///     wallet
162///         .next_unused_address(KeychainKind::External)
163///         .to_string(),
164///     "tb1q4525hmgw265tl3drrl8jjta7ayffu6jf68ltjd"
165/// );
166/// # Ok::<_, Box<dyn std::error::Error>>(())
167/// ```
168#[derive(Debug, Clone)]
169pub struct P2Wpkh<K: IntoDescriptorKey<Segwitv0>>(pub K);
170
171impl<K: IntoDescriptorKey<Segwitv0>> DescriptorTemplate for P2Wpkh<K> {
172    fn build(self, _network: Network) -> Result<DescriptorTemplateOut, DescriptorError> {
173        descriptor!(wpkh(self.0))
174    }
175}
176
177/// P2TR template. Expands to a descriptor `tr(key)`
178///
179/// ## Example
180///
181/// ```
182/// # use bdk_wallet::bitcoin::{PrivateKey, Network};
183/// # use bdk_wallet::Wallet;
184/// # use bdk_wallet::KeychainKind;
185/// use bdk_wallet::template::P2TR;
186///
187/// let key_external =
188///     bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
189/// let key_internal =
190///     bitcoin::PrivateKey::from_wif("cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW")?;
191/// let mut wallet = Wallet::create(P2TR(key_external), P2TR(key_internal))
192///     .network(Network::Testnet)
193///     .create_wallet_no_persist()?;
194///
195/// assert_eq!(
196///     wallet
197///         .next_unused_address(KeychainKind::External)
198///         .to_string(),
199///     "tb1pvjf9t34fznr53u5tqhejz4nr69luzkhlvsdsdfq9pglutrpve2xq7hps46"
200/// );
201/// # Ok::<_, Box<dyn std::error::Error>>(())
202/// ```
203#[derive(Debug, Clone)]
204pub struct P2TR<K: IntoDescriptorKey<Tap>>(pub K);
205
206impl<K: IntoDescriptorKey<Tap>> DescriptorTemplate for P2TR<K> {
207    fn build(self, _network: Network) -> Result<DescriptorTemplateOut, DescriptorError> {
208        descriptor!(tr(self.0))
209    }
210}
211
212/// BIP44 template. Expands to `pkh(key/44'/{0,1}'/0'/{0,1}/*)`
213///
214/// Since there are hardened derivation steps, this template requires a private derivable key
215/// (generally a `xprv`/`tprv`).
216///
217/// See [`Bip44Public`] for a template that can work with a `xpub`/`tpub`.
218///
219/// ## Example
220///
221/// ```rust
222/// # use std::str::FromStr;
223/// # use bdk_wallet::bitcoin::{PrivateKey, Network};
224/// # use bdk_wallet::{Wallet, KeychainKind};
225/// use bdk_wallet::template::Bip44;
226///
227/// let key = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
228/// let mut wallet = Wallet::create(Bip44(key.clone(), KeychainKind::External), Bip44(key, KeychainKind::Internal))
229///     .network(Network::Testnet)
230///     .create_wallet_no_persist()?;
231///
232/// assert_eq!(wallet.next_unused_address(KeychainKind::External).to_string(), "mmogjc7HJEZkrLqyQYqJmxUqFaC7i4uf89");
233/// assert_eq!(wallet.public_descriptor(KeychainKind::External).to_string(), "pkh([c55b303f/44'/1'/0']tpubDCuorCpzvYS2LCD75BR46KHE8GdDeg1wsAgNZeNr6DaB5gQK1o14uErKwKLuFmeemkQ6N2m3rNgvctdJLyr7nwu2yia7413Hhg8WWE44cgT/0/*)#5wrnv0xt");
234/// # Ok::<_, Box<dyn std::error::Error>>(())
235/// ```
236#[derive(Debug, Clone)]
237pub struct Bip44<K: DerivableKey<Legacy>>(pub K, pub KeychainKind);
238
239impl<K: DerivableKey<Legacy>> DescriptorTemplate for Bip44<K> {
240    fn build(self, network: Network) -> Result<DescriptorTemplateOut, DescriptorError> {
241        P2Pkh(legacy::make_bipxx_private(44, self.0, self.1, network)?).build(network)
242    }
243}
244
245/// BIP44 public template. Expands to `pkh(key/{0,1}/*)`
246///
247/// This assumes that the key used has already been derived with `m/44'/0'/0'` for Mainnet or
248/// `m/44'/1'/0'` for Testnet.
249///
250/// This template requires the parent fingerprint to populate correctly the metadata of PSBTs.
251///
252/// See [`Bip44`] for a template that does the full derivation, but requires private data
253/// for the key.
254///
255/// ## Example
256///
257/// ```
258/// # use std::str::FromStr;
259/// # use bdk_wallet::bitcoin::{PrivateKey, Network};
260/// # use bdk_wallet::{KeychainKind, Wallet};
261/// use bdk_wallet::template::Bip44Public;
262///
263/// let key = bitcoin::bip32::Xpub::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU")?;
264/// let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f")?;
265/// let mut wallet = Wallet::create(
266///     Bip44Public(key.clone(), fingerprint, KeychainKind::External),
267///     Bip44Public(key, fingerprint, KeychainKind::Internal),
268///     )
269///     .network(Network::Testnet)
270/// .create_wallet_no_persist()?;
271///
272/// assert_eq!(wallet.next_unused_address(KeychainKind::External).to_string(), "miNG7dJTzJqNbFS19svRdTCisC65dsubtR");
273/// assert_eq!(wallet.public_descriptor(KeychainKind::External).to_string(), "pkh([c55b303f/44'/1'/0']tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU/0/*)#cfhumdqz");
274/// # Ok::<_, Box<dyn std::error::Error>>(())
275/// ```
276#[derive(Debug, Clone)]
277pub struct Bip44Public<K: DerivableKey<Legacy>>(pub K, pub bip32::Fingerprint, pub KeychainKind);
278
279impl<K: DerivableKey<Legacy>> DescriptorTemplate for Bip44Public<K> {
280    fn build(self, network: Network) -> Result<DescriptorTemplateOut, DescriptorError> {
281        P2Pkh(legacy::make_bipxx_public(
282            44, self.0, self.1, self.2, network,
283        )?)
284        .build(network)
285    }
286}
287
288/// BIP49 template. Expands to `sh(wpkh(key/49'/{0,1}'/0'/{0,1}/*))`
289///
290/// Since there are hardened derivation steps, this template requires a private derivable key
291/// (generally a `xprv`/`tprv`).
292///
293/// See [`Bip49Public`] for a template that can work with a `xpub`/`tpub`.
294///
295/// ## Example
296///
297/// ```
298/// # use std::str::FromStr;
299/// # use bdk_wallet::bitcoin::{PrivateKey, Network};
300/// # use bdk_wallet::{Wallet, KeychainKind};
301/// use bdk_wallet::template::Bip49;
302///
303/// let key = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
304/// let mut wallet = Wallet::create(
305///     Bip49(key.clone(), KeychainKind::External),
306///     Bip49(key, KeychainKind::Internal),
307/// )
308/// .network(Network::Testnet)
309/// .create_wallet_no_persist()?;
310///
311/// assert_eq!(wallet.next_unused_address(KeychainKind::External).to_string(), "2N4zkWAoGdUv4NXhSsU8DvS5MB36T8nKHEB");
312/// assert_eq!(wallet.public_descriptor(KeychainKind::External).to_string(), "sh(wpkh([c55b303f/49'/1'/0']tpubDDYr4kdnZgjjShzYNjZUZXUUtpXaofdkMaipyS8ThEh45qFmhT4hKYways7UXmg6V7het1QiFo9kf4kYUXyDvV4rHEyvSpys9pjCB3pukxi/0/*))#s9vxlc8e");
313/// # Ok::<_, Box<dyn std::error::Error>>(())
314/// ```
315#[derive(Debug, Clone)]
316pub struct Bip49<K: DerivableKey<Segwitv0>>(pub K, pub KeychainKind);
317
318impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for Bip49<K> {
319    fn build(self, network: Network) -> Result<DescriptorTemplateOut, DescriptorError> {
320        P2Wpkh_P2Sh(segwit_v0::make_bipxx_private(49, self.0, self.1, network)?).build(network)
321    }
322}
323
324/// BIP49 public template. Expands to `sh(wpkh(key/{0,1}/*))`
325///
326/// This assumes that the key used has already been derived with `m/49'/0'/0'` for Mainnet or
327/// `m/49'/1'/0'` for Testnet.
328///
329/// This template requires the parent fingerprint to populate correctly the metadata of PSBTs.
330///
331/// See [`Bip49`] for a template that does the full derivation, but requires private data
332/// for the key.
333///
334/// ## Example
335///
336/// ```
337/// # use std::str::FromStr;
338/// # use bdk_wallet::bitcoin::{PrivateKey, Network};
339/// # use bdk_wallet::{Wallet, KeychainKind};
340/// use bdk_wallet::template::Bip49Public;
341///
342/// let key = bitcoin::bip32::Xpub::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L")?;
343/// let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f")?;
344/// let mut wallet = Wallet::create(
345///     Bip49Public(key.clone(), fingerprint, KeychainKind::External),
346///     Bip49Public(key, fingerprint, KeychainKind::Internal),
347/// )
348/// .network(Network::Testnet)
349/// .create_wallet_no_persist()?;
350///
351/// assert_eq!(wallet.next_unused_address(KeychainKind::External).to_string(), "2N3K4xbVAHoiTQSwxkZjWDfKoNC27pLkYnt");
352/// assert_eq!(wallet.public_descriptor(KeychainKind::External).to_string(), "sh(wpkh([c55b303f/49'/1'/0']tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L/0/*))#3tka9g0q");
353/// # Ok::<_, Box<dyn std::error::Error>>(())
354/// ```
355#[derive(Debug, Clone)]
356pub struct Bip49Public<K: DerivableKey<Segwitv0>>(pub K, pub bip32::Fingerprint, pub KeychainKind);
357
358impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for Bip49Public<K> {
359    fn build(self, network: Network) -> Result<DescriptorTemplateOut, DescriptorError> {
360        P2Wpkh_P2Sh(segwit_v0::make_bipxx_public(
361            49, self.0, self.1, self.2, network,
362        )?)
363        .build(network)
364    }
365}
366
367/// BIP84 template. Expands to `wpkh(key/84'/{0,1}'/0'/{0,1}/*)`
368///
369/// Since there are hardened derivation steps, this template requires a private derivable key
370/// (generally a `xprv`/`tprv`).
371///
372/// See [`Bip84Public`] for a template that can work with a `xpub`/`tpub`.
373///
374/// ## Example
375///
376/// ```
377/// # use std::str::FromStr;
378/// # use bdk_wallet::bitcoin::{PrivateKey, Network};
379/// # use bdk_wallet::{Wallet, KeychainKind};
380/// use bdk_wallet::template::Bip84;
381///
382/// let key = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
383/// let mut wallet = Wallet::create(
384///     Bip84(key.clone(), KeychainKind::External),
385///     Bip84(key, KeychainKind::Internal),
386/// )
387/// .network(Network::Testnet)
388/// .create_wallet_no_persist()?;
389///
390/// assert_eq!(wallet.next_unused_address(KeychainKind::External).to_string(), "tb1qhl85z42h7r4su5u37rvvw0gk8j2t3n9y7zsg4n");
391/// assert_eq!(wallet.public_descriptor(KeychainKind::External).to_string(), "wpkh([c55b303f/84'/1'/0']tpubDDc5mum24DekpNw92t6fHGp8Gr2JjF9J7i4TZBtN6Vp8xpAULG5CFaKsfugWa5imhrQQUZKXe261asP5koDHo5bs3qNTmf3U3o4v9SaB8gg/0/*)#6kfecsmr");
392/// # Ok::<_, Box<dyn std::error::Error>>(())
393/// ```
394#[derive(Debug, Clone)]
395pub struct Bip84<K: DerivableKey<Segwitv0>>(pub K, pub KeychainKind);
396
397impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for Bip84<K> {
398    fn build(self, network: Network) -> Result<DescriptorTemplateOut, DescriptorError> {
399        P2Wpkh(segwit_v0::make_bipxx_private(84, self.0, self.1, network)?).build(network)
400    }
401}
402
403/// BIP84 public template. Expands to `wpkh(key/{0,1}/*)`
404///
405/// This assumes that the key used has already been derived with `m/84'/0'/0'` for Mainnet or
406/// `m/84'/1'/0'` for Testnet.
407///
408/// This template requires the parent fingerprint to populate correctly the metadata of PSBTs.
409///
410/// See [`Bip84`] for a template that does the full derivation, but requires private data
411/// for the key.
412///
413/// ## Example
414///
415/// ```
416/// # use std::str::FromStr;
417/// # use bdk_wallet::bitcoin::{PrivateKey, Network};
418/// # use bdk_wallet::{Wallet, KeychainKind};
419/// use bdk_wallet::template::Bip84Public;
420///
421/// let key = bitcoin::bip32::Xpub::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?;
422/// let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f")?;
423/// let mut wallet = Wallet::create(
424///     Bip84Public(key.clone(), fingerprint, KeychainKind::External),
425///     Bip84Public(key, fingerprint, KeychainKind::Internal),
426/// )
427/// .network(Network::Testnet)
428/// .create_wallet_no_persist()?;
429///
430/// assert_eq!(wallet.next_unused_address(KeychainKind::External).to_string(), "tb1qedg9fdlf8cnnqfd5mks6uz5w4kgpk2pr6y4qc7");
431/// assert_eq!(wallet.public_descriptor(KeychainKind::External).to_string(), "wpkh([c55b303f/84'/1'/0']tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q/0/*)#dhu402yv");
432/// # Ok::<_, Box<dyn std::error::Error>>(())
433/// ```
434#[derive(Debug, Clone)]
435pub struct Bip84Public<K: DerivableKey<Segwitv0>>(pub K, pub bip32::Fingerprint, pub KeychainKind);
436
437impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for Bip84Public<K> {
438    fn build(self, network: Network) -> Result<DescriptorTemplateOut, DescriptorError> {
439        P2Wpkh(segwit_v0::make_bipxx_public(
440            84, self.0, self.1, self.2, network,
441        )?)
442        .build(network)
443    }
444}
445
446/// BIP86 template. Expands to `tr(key/86'/{0,1}'/0'/{0,1}/*)`
447///
448/// Since there are hardened derivation steps, this template requires a private derivable key
449/// (generally a `xprv`/`tprv`).
450///
451/// See [`Bip86Public`] for a template that can work with a `xpub`/`tpub`.
452///
453/// ## Example
454///
455/// ```
456/// # use std::str::FromStr;
457/// # use bdk_wallet::bitcoin::{PrivateKey, Network};
458/// # use bdk_wallet::{Wallet, KeychainKind};
459/// use bdk_wallet::template::Bip86;
460///
461/// let key = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
462/// let mut wallet = Wallet::create(
463///     Bip86(key.clone(), KeychainKind::External),
464///     Bip86(key, KeychainKind::Internal),
465/// )
466/// .network(Network::Testnet)
467/// .create_wallet_no_persist()?;
468///
469/// assert_eq!(wallet.next_unused_address(KeychainKind::External).to_string(), "tb1p5unlj09djx8xsjwe97269kqtxqpwpu2epeskgqjfk4lnf69v4tnqpp35qu");
470/// assert_eq!(wallet.public_descriptor(KeychainKind::External).to_string(), "tr([c55b303f/86'/1'/0']tpubDCiHofpEs47kx358bPdJmTZHmCDqQ8qw32upCSxHrSEdeeBs2T5Mq6QMB2ukeMqhNBiyhosBvJErteVhfURPGXPv3qLJPw5MVpHUewsbP2m/0/*)#dkgvr5hm");
471/// # Ok::<_, Box<dyn std::error::Error>>(())
472/// ```
473#[derive(Debug, Clone)]
474pub struct Bip86<K: DerivableKey<Tap>>(pub K, pub KeychainKind);
475
476impl<K: DerivableKey<Tap>> DescriptorTemplate for Bip86<K> {
477    fn build(self, network: Network) -> Result<DescriptorTemplateOut, DescriptorError> {
478        P2TR(segwit_v1::make_bipxx_private(86, self.0, self.1, network)?).build(network)
479    }
480}
481
482/// BIP86 public template. Expands to `tr(key/{0,1}/*)`
483///
484/// This assumes that the key used has already been derived with `m/86'/0'/0'` for Mainnet or
485/// `m/86'/1'/0'` for Testnet.
486///
487/// This template requires the parent fingerprint to populate correctly the metadata of PSBTs.
488///
489/// See [`Bip86`] for a template that does the full derivation, but requires private data
490/// for the key.
491///
492/// ## Example
493///
494/// ```
495/// # use std::str::FromStr;
496/// # use bdk_wallet::bitcoin::{PrivateKey, Network};
497/// # use bdk_wallet::{Wallet, KeychainKind};
498/// use bdk_wallet::template::Bip86Public;
499///
500/// let key = bitcoin::bip32::Xpub::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?;
501/// let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f")?;
502/// let mut wallet = Wallet::create(
503///     Bip86Public(key.clone(), fingerprint, KeychainKind::External),
504///     Bip86Public(key, fingerprint, KeychainKind::Internal),
505/// )
506/// .network(Network::Testnet)
507/// .create_wallet_no_persist()?;
508///
509/// assert_eq!(wallet.next_unused_address(KeychainKind::External).to_string(), "tb1pwjp9f2k5n0xq73ecuu0c5njvgqr3vkh7yaylmpqvsuuaafymh0msvcmh37");
510/// assert_eq!(wallet.public_descriptor(KeychainKind::External).to_string(), "tr([c55b303f/86'/1'/0']tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q/0/*)#2p65srku");
511/// # Ok::<_, Box<dyn std::error::Error>>(())
512/// ```
513#[derive(Debug, Clone)]
514pub struct Bip86Public<K: DerivableKey<Tap>>(pub K, pub bip32::Fingerprint, pub KeychainKind);
515
516impl<K: DerivableKey<Tap>> DescriptorTemplate for Bip86Public<K> {
517    fn build(self, network: Network) -> Result<DescriptorTemplateOut, DescriptorError> {
518        P2TR(segwit_v1::make_bipxx_public(
519            86, self.0, self.1, self.2, network,
520        )?)
521        .build(network)
522    }
523}
524
525macro_rules! expand_make_bipxx {
526    ( $mod_name:ident, $ctx:ty ) => {
527        mod $mod_name {
528            use super::*;
529
530            pub(super) fn make_bipxx_private<K: DerivableKey<$ctx>>(
531                bip: u32,
532                key: K,
533                keychain: KeychainKind,
534                network: Network,
535            ) -> Result<impl IntoDescriptorKey<$ctx>, DescriptorError> {
536                let mut derivation_path = alloc::vec::Vec::with_capacity(4);
537                derivation_path.push(bip32::ChildNumber::from_hardened_idx(bip)?);
538
539                match network {
540                    Network::Bitcoin => {
541                        derivation_path.push(bip32::ChildNumber::from_hardened_idx(0)?);
542                    }
543                    _ => {
544                        derivation_path.push(bip32::ChildNumber::from_hardened_idx(1)?);
545                    }
546                }
547                derivation_path.push(bip32::ChildNumber::from_hardened_idx(0)?);
548
549                match keychain {
550                    KeychainKind::External => {
551                        derivation_path.push(bip32::ChildNumber::from_normal_idx(0)?)
552                    }
553                    KeychainKind::Internal => {
554                        derivation_path.push(bip32::ChildNumber::from_normal_idx(1)?)
555                    }
556                };
557
558                let derivation_path: bip32::DerivationPath = derivation_path.into();
559
560                Ok((key, derivation_path))
561            }
562            pub(super) fn make_bipxx_public<K: DerivableKey<$ctx>>(
563                bip: u32,
564                key: K,
565                parent_fingerprint: bip32::Fingerprint,
566                keychain: KeychainKind,
567                network: Network,
568            ) -> Result<impl IntoDescriptorKey<$ctx>, DescriptorError> {
569                let derivation_path: bip32::DerivationPath = match keychain {
570                    KeychainKind::External => vec![bip32::ChildNumber::from_normal_idx(0)?].into(),
571                    KeychainKind::Internal => vec![bip32::ChildNumber::from_normal_idx(1)?].into(),
572                };
573
574                let source_path = bip32::DerivationPath::from(vec![
575                    bip32::ChildNumber::from_hardened_idx(bip)?,
576                    match network {
577                        Network::Bitcoin => bip32::ChildNumber::from_hardened_idx(0)?,
578                        _ => bip32::ChildNumber::from_hardened_idx(1)?,
579                    },
580                    bip32::ChildNumber::from_hardened_idx(0)?,
581                ]);
582
583                Ok((key, (parent_fingerprint, source_path), derivation_path))
584            }
585        }
586    };
587}
588
589expand_make_bipxx!(legacy, Legacy);
590expand_make_bipxx!(segwit_v0, Segwitv0);
591expand_make_bipxx!(segwit_v1, Tap);
592
593#[cfg(test)]
594mod test {
595    // test existing descriptor templates, make sure they are expanded to the right descriptors
596
597    use alloc::{string::ToString, vec::Vec};
598    use core::str::FromStr;
599
600    use super::*;
601    use crate::descriptor::{DescriptorError, DescriptorMeta};
602    use crate::keys::ValidNetworks;
603    use assert_matches::assert_matches;
604    use miniscript::descriptor::{DescriptorPublicKey, KeyMap};
605    use miniscript::Descriptor;
606
607    // BIP44 `pkh(key/44'/{0,1}'/0'/{0,1}/*)`
608    #[test]
609    fn test_bip44_template_cointype() {
610        use bitcoin::bip32::ChildNumber::{self, Hardened};
611
612        let xprvkey = bitcoin::bip32::Xpriv::from_str("xprv9s21ZrQH143K2fpbqApQL69a4oKdGVnVN52R82Ft7d1pSqgKmajF62acJo3aMszZb6qQ22QsVECSFxvf9uyxFUvFYQMq3QbtwtRSMjLAhMf").unwrap();
613        assert!(xprvkey.network.is_mainnet());
614        let xdesc = Bip44(xprvkey, KeychainKind::Internal)
615            .build(Network::Bitcoin)
616            .unwrap();
617
618        if let ExtendedDescriptor::Pkh(pkh) = xdesc.0 {
619            let path: Vec<ChildNumber> = pkh.into_inner().full_derivation_path().unwrap().into();
620            let purpose = path.first().unwrap();
621            assert_matches!(purpose, Hardened { index: 44 });
622            let coin_type = path.get(1).unwrap();
623            assert_matches!(coin_type, Hardened { index: 0 });
624        }
625
626        let tprvkey = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
627        assert!(!tprvkey.network.is_mainnet());
628        let tdesc = Bip44(tprvkey, KeychainKind::Internal)
629            .build(Network::Testnet)
630            .unwrap();
631
632        if let ExtendedDescriptor::Pkh(pkh) = tdesc.0 {
633            let path: Vec<ChildNumber> = pkh.into_inner().full_derivation_path().unwrap().into();
634            let purpose = path.first().unwrap();
635            assert_matches!(purpose, Hardened { index: 44 });
636            let coin_type = path.get(1).unwrap();
637            assert_matches!(coin_type, Hardened { index: 1 });
638        }
639    }
640
641    // verify template descriptor generates expected address(es)
642    fn check(
643        desc: Result<(Descriptor<DescriptorPublicKey>, KeyMap, ValidNetworks), DescriptorError>,
644        is_witness: bool,
645        is_taproot: bool,
646        is_fixed: bool,
647        network: Network,
648        expected: &[&str],
649    ) {
650        let (desc, _key_map, _networks) = desc.unwrap();
651        assert_eq!(desc.is_witness(), is_witness);
652        assert_eq!(desc.is_taproot(), is_taproot);
653        assert_eq!(!desc.has_wildcard(), is_fixed);
654        for i in 0..expected.len() {
655            let index = i as u32;
656            let child_desc = if !desc.has_wildcard() {
657                desc.at_derivation_index(0).unwrap()
658            } else {
659                desc.at_derivation_index(index).unwrap()
660            };
661            let address = child_desc.address(network).unwrap();
662            assert_eq!(address.to_string(), *expected.get(i).unwrap());
663        }
664    }
665
666    // P2PKH
667    #[test]
668    fn test_p2ph_template() {
669        let prvkey =
670            bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")
671                .unwrap();
672        check(
673            P2Pkh(prvkey).build(Network::Bitcoin),
674            false,
675            false,
676            true,
677            Network::Regtest,
678            &["mwJ8hxFYW19JLuc65RCTaP4v1rzVU8cVMT"],
679        );
680
681        let pubkey = bitcoin::PublicKey::from_str(
682            "03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd",
683        )
684        .unwrap();
685        check(
686            P2Pkh(pubkey).build(Network::Bitcoin),
687            false,
688            false,
689            true,
690            Network::Regtest,
691            &["muZpTpBYhxmRFuCjLc7C6BBDF32C8XVJUi"],
692        );
693    }
694
695    // P2WPKH-P2SH `sh(wpkh(key))`
696    #[test]
697    fn test_p2wphp2sh_template() {
698        let prvkey =
699            bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")
700                .unwrap();
701        check(
702            P2Wpkh_P2Sh(prvkey).build(Network::Bitcoin),
703            true,
704            false,
705            true,
706            Network::Regtest,
707            &["2NB4ox5VDRw1ecUv6SnT3VQHPXveYztRqk5"],
708        );
709
710        let pubkey = bitcoin::PublicKey::from_str(
711            "03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd",
712        )
713        .unwrap();
714        check(
715            P2Wpkh_P2Sh(pubkey).build(Network::Bitcoin),
716            true,
717            false,
718            true,
719            Network::Regtest,
720            &["2N5LiC3CqzxDamRTPG1kiNv1FpNJQ7x28sb"],
721        );
722    }
723
724    // P2WPKH `wpkh(key)`
725    #[test]
726    fn test_p2wph_template() {
727        let prvkey =
728            bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")
729                .unwrap();
730        check(
731            P2Wpkh(prvkey).build(Network::Bitcoin),
732            true,
733            false,
734            true,
735            Network::Regtest,
736            &["bcrt1q4525hmgw265tl3drrl8jjta7ayffu6jfcwxx9y"],
737        );
738
739        let pubkey = bitcoin::PublicKey::from_str(
740            "03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd",
741        )
742        .unwrap();
743        check(
744            P2Wpkh(pubkey).build(Network::Bitcoin),
745            true,
746            false,
747            true,
748            Network::Regtest,
749            &["bcrt1qngw83fg8dz0k749cg7k3emc7v98wy0c7azaa6h"],
750        );
751    }
752
753    // P2TR `tr(key)`
754    #[test]
755    fn test_p2tr_template() {
756        let prvkey =
757            bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")
758                .unwrap();
759        check(
760            P2TR(prvkey).build(Network::Bitcoin),
761            false,
762            true,
763            true,
764            Network::Regtest,
765            &["bcrt1pvjf9t34fznr53u5tqhejz4nr69luzkhlvsdsdfq9pglutrpve2xqnwtkqq"],
766        );
767
768        let pubkey = bitcoin::PublicKey::from_str(
769            "03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd",
770        )
771        .unwrap();
772        check(
773            P2TR(pubkey).build(Network::Bitcoin),
774            false,
775            true,
776            true,
777            Network::Regtest,
778            &["bcrt1pw74tdcrxlzn5r8z6ku2vztr86fgq0m245s72mjktf4afwzsf8ugs4evwdf"],
779        );
780    }
781
782    // BIP44 `pkh(key/44'/0'/0'/{0,1}/*)`
783    #[test]
784    fn test_bip44_template() {
785        let prvkey = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
786        check(
787            Bip44(prvkey, KeychainKind::External).build(Network::Bitcoin),
788            false,
789            false,
790            false,
791            Network::Regtest,
792            &[
793                "n453VtnjDHPyDt2fDstKSu7A3YCJoHZ5g5",
794                "mvfrrumXgTtwFPWDNUecBBgzuMXhYM7KRP",
795                "mzYvhRAuQqbdSKMVVzXNYyqihgNdRadAUQ",
796            ],
797        );
798        check(
799            Bip44(prvkey, KeychainKind::Internal).build(Network::Bitcoin),
800            false,
801            false,
802            false,
803            Network::Regtest,
804            &[
805                "muHF98X9KxEzdKrnFAX85KeHv96eXopaip",
806                "n4hpyLJE5ub6B5Bymv4eqFxS5KjrewSmYR",
807                "mgvkdv1ffmsXd2B1sRKQ5dByK3SzpG42rA",
808            ],
809        );
810    }
811
812    // BIP44 public `pkh(key/{0,1}/*)`
813    #[test]
814    fn test_bip44_public_template() {
815        let pubkey = bitcoin::bip32::Xpub::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU").unwrap();
816        let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f").unwrap();
817        check(
818            Bip44Public(pubkey, fingerprint, KeychainKind::External).build(Network::Bitcoin),
819            false,
820            false,
821            false,
822            Network::Regtest,
823            &[
824                "miNG7dJTzJqNbFS19svRdTCisC65dsubtR",
825                "n2UqaDbCjWSFJvpC84m3FjUk5UaeibCzYg",
826                "muCPpS6Ue7nkzeJMWDViw7Lkwr92Yc4K8g",
827            ],
828        );
829        check(
830            Bip44Public(pubkey, fingerprint, KeychainKind::Internal).build(Network::Bitcoin),
831            false,
832            false,
833            false,
834            Network::Regtest,
835            &[
836                "moDr3vJ8wpt5nNxSK55MPq797nXJb2Ru9H",
837                "ms7A1Yt4uTezT2XkefW12AvLoko8WfNJMG",
838                "mhYiyat2rtEnV77cFfQsW32y1m2ceCGHPo",
839            ],
840        );
841    }
842
843    // BIP49 `sh(wpkh(key/49'/0'/0'/{0,1}/*))`
844    #[test]
845    fn test_bip49_template() {
846        let prvkey = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
847        check(
848            Bip49(prvkey, KeychainKind::External).build(Network::Bitcoin),
849            true,
850            false,
851            false,
852            Network::Regtest,
853            &[
854                "2N9bCAJXGm168MjVwpkBdNt6ucka3PKVoUV",
855                "2NDckYkqrYyDMtttEav5hB3Bfw9EGAW5HtS",
856                "2NAFTVtksF9T4a97M7nyCjwUBD24QevZ5Z4",
857            ],
858        );
859        check(
860            Bip49(prvkey, KeychainKind::Internal).build(Network::Bitcoin),
861            true,
862            false,
863            false,
864            Network::Regtest,
865            &[
866                "2NB3pA8PnzJLGV8YEKNDFpbViZv3Bm1K6CG",
867                "2NBiX2Wzxngb5rPiWpUiJQ2uLVB4HBjFD4p",
868                "2NA8ek4CdQ6aMkveYF6AYuEYNrftB47QGTn",
869            ],
870        );
871    }
872
873    // BIP49 public `sh(wpkh(key/{0,1}/*))`
874    #[test]
875    fn test_bip49_public_template() {
876        let pubkey = bitcoin::bip32::Xpub::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L").unwrap();
877        let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f").unwrap();
878        check(
879            Bip49Public(pubkey, fingerprint, KeychainKind::External).build(Network::Bitcoin),
880            true,
881            false,
882            false,
883            Network::Regtest,
884            &[
885                "2N3K4xbVAHoiTQSwxkZjWDfKoNC27pLkYnt",
886                "2NCTQfJ1sZa3wQ3pPseYRHbaNEpC3AquEfX",
887                "2MveFxAuC8BYPzTybx7FxSzW8HSd8ATT4z7",
888            ],
889        );
890        check(
891            Bip49Public(pubkey, fingerprint, KeychainKind::Internal).build(Network::Bitcoin),
892            true,
893            false,
894            false,
895            Network::Regtest,
896            &[
897                "2NF2vttKibwyxigxtx95Zw8K7JhDbo5zPVJ",
898                "2Mtmyd8taksxNVWCJ4wVvaiss7QPZGcAJuH",
899                "2NBs3CTVYPr1HCzjB4YFsnWCPCtNg8uMEfp",
900            ],
901        );
902    }
903
904    // BIP84 `wpkh(key/84'/0'/0'/{0,1}/*)`
905    #[test]
906    fn test_bip84_template() {
907        let prvkey = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
908        check(
909            Bip84(prvkey, KeychainKind::External).build(Network::Bitcoin),
910            true,
911            false,
912            false,
913            Network::Regtest,
914            &[
915                "bcrt1qkmvk2nadgplmd57ztld8nf8v2yxkzmdvwtjf8s",
916                "bcrt1qx0v6zgfwe50m4kqc58cqzcyem7ay2sfl3gvqhp",
917                "bcrt1q4h7fq9zhxst6e69p3n882nfj649l7w9g3zccfp",
918            ],
919        );
920        check(
921            Bip84(prvkey, KeychainKind::Internal).build(Network::Bitcoin),
922            true,
923            false,
924            false,
925            Network::Regtest,
926            &[
927                "bcrt1qtrwtz00wxl69e5xex7amy4xzlxkaefg3gfdkxa",
928                "bcrt1qqqasfhxpkkf7zrxqnkr2sfhn74dgsrc3e3ky45",
929                "bcrt1qpks7n0gq74hsgsz3phn5vuazjjq0f5eqhsgyce",
930            ],
931        );
932    }
933
934    // BIP84 public `wpkh(key/{0,1}/*)`
935    #[test]
936    fn test_bip84_public_template() {
937        let pubkey = bitcoin::bip32::Xpub::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q").unwrap();
938        let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f").unwrap();
939        check(
940            Bip84Public(pubkey, fingerprint, KeychainKind::External).build(Network::Bitcoin),
941            true,
942            false,
943            false,
944            Network::Regtest,
945            &[
946                "bcrt1qedg9fdlf8cnnqfd5mks6uz5w4kgpk2prcdvd0h",
947                "bcrt1q3lncdlwq3lgcaaeyruynjnlccr0ve0kakh6ana",
948                "bcrt1qt9800y6xl3922jy3uyl0z33jh5wfpycyhcylr9",
949            ],
950        );
951        check(
952            Bip84Public(pubkey, fingerprint, KeychainKind::Internal).build(Network::Bitcoin),
953            true,
954            false,
955            false,
956            Network::Regtest,
957            &[
958                "bcrt1qm6wqukenh7guu792lj2njgw9n78cmwsy8xy3z2",
959                "bcrt1q694twxtjn4nnrvnyvra769j0a23rllj5c6cgwp",
960                "bcrt1qhlac3c5ranv5w5emlnqs7wxhkxt8maelylcarp",
961            ],
962        );
963    }
964
965    // BIP86 `tr(key/86'/0'/0'/{0,1}/*)`
966    // Used addresses in test vector in https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki
967    #[test]
968    fn test_bip86_template() {
969        let prvkey = bitcoin::bip32::Xpriv::from_str("xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu").unwrap();
970        check(
971            Bip86(prvkey, KeychainKind::External).build(Network::Bitcoin),
972            false,
973            true,
974            false,
975            Network::Bitcoin,
976            &[
977                "bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr",
978                "bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh",
979                "bc1p0d0rhyynq0awa9m8cqrcr8f5nxqx3aw29w4ru5u9my3h0sfygnzs9khxz8",
980            ],
981        );
982        check(
983            Bip86(prvkey, KeychainKind::Internal).build(Network::Bitcoin),
984            false,
985            true,
986            false,
987            Network::Bitcoin,
988            &[
989                "bc1p3qkhfews2uk44qtvauqyr2ttdsw7svhkl9nkm9s9c3x4ax5h60wqwruhk7",
990                "bc1ptdg60grjk9t3qqcqczp4tlyy3z47yrx9nhlrjsmw36q5a72lhdrs9f00nj",
991                "bc1pgcwgsu8naxp7xlp5p7ufzs7emtfza2las7r2e7krzjhe5qj5xz2q88kmk5",
992            ],
993        );
994    }
995
996    // BIP86 public `tr(key/{0,1}/*)`
997    // Used addresses in test vector in https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki
998    #[test]
999    fn test_bip86_public_template() {
1000        let pubkey = bitcoin::bip32::Xpub::from_str("xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ").unwrap();
1001        let fingerprint = bitcoin::bip32::Fingerprint::from_str("73c5da0a").unwrap();
1002        check(
1003            Bip86Public(pubkey, fingerprint, KeychainKind::External).build(Network::Bitcoin),
1004            false,
1005            true,
1006            false,
1007            Network::Bitcoin,
1008            &[
1009                "bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr",
1010                "bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh",
1011                "bc1p0d0rhyynq0awa9m8cqrcr8f5nxqx3aw29w4ru5u9my3h0sfygnzs9khxz8",
1012            ],
1013        );
1014        check(
1015            Bip86Public(pubkey, fingerprint, KeychainKind::Internal).build(Network::Bitcoin),
1016            false,
1017            true,
1018            false,
1019            Network::Bitcoin,
1020            &[
1021                "bc1p3qkhfews2uk44qtvauqyr2ttdsw7svhkl9nkm9s9c3x4ax5h60wqwruhk7",
1022                "bc1ptdg60grjk9t3qqcqczp4tlyy3z47yrx9nhlrjsmw36q5a72lhdrs9f00nj",
1023                "bc1pgcwgsu8naxp7xlp5p7ufzs7emtfza2las7r2e7krzjhe5qj5xz2q88kmk5",
1024            ],
1025        );
1026    }
1027}