bdkffi/
descriptor.rs

1use crate::bitcoin::DescriptorId;
2use crate::bitcoin::DescriptorType;
3use crate::bitcoin::{Address, NetworkKind};
4use crate::error::DescriptorError;
5use crate::error::MiniscriptError;
6use crate::keys::DescriptorPublicKey;
7use crate::keys::DescriptorSecretKey;
8use crate::types::KeychainKind;
9
10use bdk_wallet::bitcoin::bip32::Fingerprint;
11use bdk_wallet::bitcoin::key::Secp256k1;
12use bdk_wallet::bitcoin::Network;
13use bdk_wallet::chain::DescriptorExt;
14use bdk_wallet::descriptor::{ExtendedDescriptor, IntoWalletDescriptor};
15use bdk_wallet::keys::DescriptorPublicKey as BdkDescriptorPublicKey;
16use bdk_wallet::keys::{DescriptorSecretKey as BdkDescriptorSecretKey, KeyMap};
17use bdk_wallet::miniscript::descriptor::{ConversionError, TapTree};
18use bdk_wallet::miniscript::Descriptor as BdkDescriptor;
19use bdk_wallet::miniscript::Miniscript as BdkMiniscript;
20use bdk_wallet::template::{
21    Bip44, Bip44Public, Bip49, Bip49Public, Bip84, Bip84Public, Bip86, Bip86Public,
22    DescriptorTemplate,
23};
24
25use std::fmt::Display;
26use std::str::FromStr;
27use std::sync::Arc;
28
29/// An expression of how to derive output scripts: https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md
30#[derive(Debug, uniffi::Object)]
31#[uniffi::export(Debug, Display)]
32pub struct Descriptor {
33    pub extended_descriptor: ExtendedDescriptor,
34    pub key_map: KeyMap,
35}
36
37#[uniffi::export]
38impl Descriptor {
39    /// Parse a string as a descriptor for the given network.
40    #[uniffi::constructor]
41    pub fn new(descriptor: String, network_kind: NetworkKind) -> Result<Self, DescriptorError> {
42        let secp = Secp256k1::new();
43        let (extended_descriptor, key_map) =
44            descriptor.into_wallet_descriptor(&secp, network_kind)?;
45        Ok(Self {
46            extended_descriptor,
47            key_map,
48        })
49    }
50
51    /// Multi-account hierarchy descriptor: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
52    #[uniffi::constructor]
53    pub fn new_bip44(
54        secret_key: &DescriptorSecretKey,
55        keychain_kind: KeychainKind,
56        network_kind: NetworkKind,
57    ) -> Self {
58        let derivable_key = &secret_key.0;
59
60        match derivable_key {
61            BdkDescriptorSecretKey::Single(_) => {
62                unreachable!()
63            }
64            BdkDescriptorSecretKey::XPrv(descriptor_x_key) => {
65                let derivable_key = descriptor_x_key.xkey;
66                let (extended_descriptor, key_map, _) = Bip44(derivable_key, keychain_kind)
67                    .build(network_kind)
68                    .unwrap();
69                Self {
70                    extended_descriptor,
71                    key_map,
72                }
73            }
74            BdkDescriptorSecretKey::MultiXPrv(_) => {
75                unreachable!()
76            }
77        }
78    }
79
80    /// Multi-account hierarchy descriptor: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
81    #[uniffi::constructor]
82    pub fn new_bip44_public(
83        public_key: &DescriptorPublicKey,
84        fingerprint: String,
85        keychain_kind: KeychainKind,
86        network_kind: NetworkKind,
87    ) -> Result<Self, DescriptorError> {
88        let fingerprint = Fingerprint::from_str(fingerprint.as_str()).map_err(|error| {
89            DescriptorError::Bip32 {
90                error_message: error.to_string(),
91            }
92        })?;
93        let derivable_key = &public_key.0;
94
95        match derivable_key {
96            BdkDescriptorPublicKey::Single(_) => {
97                unreachable!()
98            }
99            BdkDescriptorPublicKey::XPub(descriptor_x_key) => {
100                let derivable_key = descriptor_x_key.xkey;
101                let (extended_descriptor, key_map, _) =
102                    Bip44Public(derivable_key, fingerprint, keychain_kind)
103                        .build(network_kind)
104                        .map_err(DescriptorError::from)?;
105
106                Ok(Self {
107                    extended_descriptor,
108                    key_map,
109                })
110            }
111            BdkDescriptorPublicKey::MultiXPub(_) => {
112                unreachable!()
113            }
114        }
115    }
116
117    /// P2SH nested P2WSH descriptor: https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki
118    #[uniffi::constructor]
119    pub fn new_bip49(
120        secret_key: &DescriptorSecretKey,
121        keychain_kind: KeychainKind,
122        network_kind: NetworkKind,
123    ) -> Self {
124        let derivable_key = &secret_key.0;
125
126        match derivable_key {
127            BdkDescriptorSecretKey::Single(_) => {
128                unreachable!()
129            }
130            BdkDescriptorSecretKey::XPrv(descriptor_x_key) => {
131                let derivable_key = descriptor_x_key.xkey;
132                let (extended_descriptor, key_map, _) = Bip49(derivable_key, keychain_kind)
133                    .build(network_kind)
134                    .unwrap();
135                Self {
136                    extended_descriptor,
137                    key_map,
138                }
139            }
140            BdkDescriptorSecretKey::MultiXPrv(_) => {
141                unreachable!()
142            }
143        }
144    }
145
146    /// P2SH nested P2WSH descriptor: https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki
147    #[uniffi::constructor]
148    pub fn new_bip49_public(
149        public_key: &DescriptorPublicKey,
150        fingerprint: String,
151        keychain_kind: KeychainKind,
152        network_kind: NetworkKind,
153    ) -> Result<Self, DescriptorError> {
154        let fingerprint = Fingerprint::from_str(fingerprint.as_str()).map_err(|error| {
155            DescriptorError::Bip32 {
156                error_message: error.to_string(),
157            }
158        })?;
159        let derivable_key = &public_key.0;
160
161        match derivable_key {
162            BdkDescriptorPublicKey::Single(_) => {
163                unreachable!()
164            }
165            BdkDescriptorPublicKey::XPub(descriptor_x_key) => {
166                let derivable_key = descriptor_x_key.xkey;
167                let (extended_descriptor, key_map, _) =
168                    Bip49Public(derivable_key, fingerprint, keychain_kind)
169                        .build(network_kind)
170                        .map_err(DescriptorError::from)?;
171
172                Ok(Self {
173                    extended_descriptor,
174                    key_map,
175                })
176            }
177            BdkDescriptorPublicKey::MultiXPub(_) => {
178                unreachable!()
179            }
180        }
181    }
182
183    /// Pay to witness PKH descriptor: https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki
184    #[uniffi::constructor]
185    pub fn new_bip84(
186        secret_key: &DescriptorSecretKey,
187        keychain_kind: KeychainKind,
188        network_kind: NetworkKind,
189    ) -> Self {
190        let derivable_key = &secret_key.0;
191
192        match derivable_key {
193            BdkDescriptorSecretKey::Single(_) => {
194                unreachable!()
195            }
196            BdkDescriptorSecretKey::XPrv(descriptor_x_key) => {
197                let derivable_key = descriptor_x_key.xkey;
198                let (extended_descriptor, key_map, _) = Bip84(derivable_key, keychain_kind)
199                    .build(network_kind)
200                    .unwrap();
201                Self {
202                    extended_descriptor,
203                    key_map,
204                }
205            }
206            BdkDescriptorSecretKey::MultiXPrv(_) => {
207                unreachable!()
208            }
209        }
210    }
211
212    /// Pay to witness PKH descriptor: https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki
213    #[uniffi::constructor]
214    pub fn new_bip84_public(
215        public_key: &DescriptorPublicKey,
216        fingerprint: String,
217        keychain_kind: KeychainKind,
218        network_kind: NetworkKind,
219    ) -> Result<Self, DescriptorError> {
220        let fingerprint = Fingerprint::from_str(fingerprint.as_str()).map_err(|error| {
221            DescriptorError::Bip32 {
222                error_message: error.to_string(),
223            }
224        })?;
225        let derivable_key = &public_key.0;
226
227        match derivable_key {
228            BdkDescriptorPublicKey::Single(_) => {
229                unreachable!()
230            }
231            BdkDescriptorPublicKey::XPub(descriptor_x_key) => {
232                let derivable_key = descriptor_x_key.xkey;
233                let (extended_descriptor, key_map, _) =
234                    Bip84Public(derivable_key, fingerprint, keychain_kind)
235                        .build(network_kind)
236                        .map_err(DescriptorError::from)?;
237
238                Ok(Self {
239                    extended_descriptor,
240                    key_map,
241                })
242            }
243            BdkDescriptorPublicKey::MultiXPub(_) => {
244                unreachable!()
245            }
246        }
247    }
248
249    /// Single key P2TR descriptor: https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki
250    #[uniffi::constructor]
251    pub fn new_bip86(
252        secret_key: &DescriptorSecretKey,
253        keychain_kind: KeychainKind,
254        network_kind: NetworkKind,
255    ) -> Self {
256        let derivable_key = &secret_key.0;
257
258        match derivable_key {
259            BdkDescriptorSecretKey::Single(_) => {
260                unreachable!()
261            }
262            BdkDescriptorSecretKey::XPrv(descriptor_x_key) => {
263                let derivable_key = descriptor_x_key.xkey;
264                let (extended_descriptor, key_map, _) = Bip86(derivable_key, keychain_kind)
265                    .build(network_kind)
266                    .unwrap();
267                Self {
268                    extended_descriptor,
269                    key_map,
270                }
271            }
272            BdkDescriptorSecretKey::MultiXPrv(_) => {
273                unreachable!()
274            }
275        }
276    }
277
278    /// Single key P2TR descriptor: https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki
279    #[uniffi::constructor]
280    pub fn new_bip86_public(
281        public_key: &DescriptorPublicKey,
282        fingerprint: String,
283        keychain_kind: KeychainKind,
284        network_kind: NetworkKind,
285    ) -> Result<Self, DescriptorError> {
286        let fingerprint = Fingerprint::from_str(fingerprint.as_str()).map_err(|error| {
287            DescriptorError::Bip32 {
288                error_message: error.to_string(),
289            }
290        })?;
291        let derivable_key = &public_key.0;
292
293        match derivable_key {
294            BdkDescriptorPublicKey::Single(_) => {
295                unreachable!()
296            }
297            BdkDescriptorPublicKey::XPub(descriptor_x_key) => {
298                let derivable_key = descriptor_x_key.xkey;
299                let (extended_descriptor, key_map, _) =
300                    Bip86Public(derivable_key, fingerprint, keychain_kind)
301                        .build(network_kind)
302                        .map_err(DescriptorError::from)?;
303
304                Ok(Self {
305                    extended_descriptor,
306                    key_map,
307                })
308            }
309            BdkDescriptorPublicKey::MultiXPub(_) => {
310                unreachable!()
311            }
312        }
313    }
314
315    /// Create a new wsh sorted multi descriptor
316    /// Errors when miniscript exceeds resource limits under p2sh context
317    #[uniffi::constructor]
318    pub fn new_wsh_sortedmulti(k: u32, pks: Vec<String>) -> Result<Self, DescriptorError> {
319        let bdk_pks: Vec<BdkDescriptorPublicKey> = pks
320            .iter()
321            .map(|pk| {
322                BdkDescriptorPublicKey::from_str(pk).map_err(|e| DescriptorError::Key {
323                    error_message: e.to_string(),
324                })
325            })
326            .collect::<Result<Vec<BdkDescriptorPublicKey>, DescriptorError>>()?;
327        let miniscript_descriptor =
328            match bdk_wallet::miniscript::Descriptor::new_wsh_sortedmulti(k as usize, bdk_pks) {
329                Ok(descriptor) => descriptor,
330                Err(e) => {
331                    return Err(DescriptorError::Miniscript {
332                        error_message: e.to_string(),
333                    })
334                }
335            };
336        let extended_descriptor = ExtendedDescriptor::from(miniscript_descriptor);
337
338        Ok(Self {
339            extended_descriptor,
340            key_map: KeyMap::new(),
341        })
342    }
343
344    /// Create a new sh sortedmulti descriptor with threshold k and Vec of pks.
345    /// Errors when miniscript exceeds resource limits under p2sh context
346    #[uniffi::constructor]
347    pub fn new_sh_sortedmulti(k: u32, pks: Vec<String>) -> Result<Self, DescriptorError> {
348        let bdk_pks: Vec<BdkDescriptorPublicKey> = pks
349            .iter()
350            .map(|pk| {
351                BdkDescriptorPublicKey::from_str(pk).map_err(|e| DescriptorError::Key {
352                    error_message: e.to_string(),
353                })
354            })
355            .collect::<Result<Vec<BdkDescriptorPublicKey>, DescriptorError>>()?;
356        let miniscript_descriptor =
357            match bdk_wallet::miniscript::Descriptor::new_sh_sortedmulti(k as usize, bdk_pks) {
358                Ok(descriptor) => descriptor,
359                Err(e) => {
360                    return Err(DescriptorError::Miniscript {
361                        error_message: e.to_string(),
362                    })
363                }
364            };
365        let extended_descriptor = ExtendedDescriptor::from(miniscript_descriptor);
366
367        Ok(Self {
368            extended_descriptor,
369            key_map: KeyMap::new(),
370        })
371    }
372
373    /// Create a new sh wrapped wsh sortedmulti descriptor from threshold k and Vec of pks
374    /// Errors when miniscript exceeds resource limits under segwit context
375    #[uniffi::constructor]
376    pub fn new_sh_wsh_sortedmulti(k: u32, pks: Vec<String>) -> Result<Self, DescriptorError> {
377        let bdk_pks: Vec<BdkDescriptorPublicKey> = pks
378            .iter()
379            .map(|pk| {
380                BdkDescriptorPublicKey::from_str(pk).map_err(|e| DescriptorError::Key {
381                    error_message: e.to_string(),
382                })
383            })
384            .collect::<Result<Vec<BdkDescriptorPublicKey>, DescriptorError>>()?;
385        let miniscript_descriptor =
386            match bdk_wallet::miniscript::Descriptor::new_sh_wsh_sortedmulti(k as usize, bdk_pks) {
387                Ok(descriptor) => descriptor,
388                Err(e) => {
389                    return Err(DescriptorError::Miniscript {
390                        error_message: e.to_string(),
391                    })
392                }
393            };
394        let extended_descriptor = ExtendedDescriptor::from(miniscript_descriptor);
395
396        Ok(Self {
397            extended_descriptor,
398            key_map: KeyMap::new(),
399        })
400    }
401
402    /// Create a new pay-to-pubkey descriptor from a public key string.
403    #[uniffi::constructor]
404    pub fn new_pk(pk: String) -> Result<Self, DescriptorError> {
405        let key = BdkDescriptorPublicKey::from_str(&pk).map_err(|e| DescriptorError::Key {
406            error_message: e.to_string(),
407        })?;
408
409        let miniscript_descriptor = bdk_wallet::miniscript::Descriptor::new_pk(key);
410        let extended_descriptor = ExtendedDescriptor::from(miniscript_descriptor);
411
412        Ok(Self {
413            extended_descriptor,
414            key_map: KeyMap::new(),
415        })
416    }
417
418    /// Create a new PkH descriptor
419    #[uniffi::constructor]
420    pub fn new_pkh(pk: String) -> Result<Self, DescriptorError> {
421        let key = BdkDescriptorPublicKey::from_str(&pk).map_err(|e| DescriptorError::Key {
422            error_message: e.to_string(),
423        })?;
424
425        let miniscript_descriptor = match bdk_wallet::miniscript::Descriptor::new_pkh(key) {
426            Ok(descriptor) => descriptor,
427            Err(e) => {
428                return Err(DescriptorError::Miniscript {
429                    error_message: e.to_string(),
430                })
431            }
432        };
433        let extended_descriptor = ExtendedDescriptor::from(miniscript_descriptor);
434
435        Ok(Self {
436            extended_descriptor,
437            key_map: KeyMap::new(),
438        })
439    }
440
441    /// Create a new Wpkh descriptor Will return Err if uncompressed key is used
442    #[uniffi::constructor]
443    pub fn new_wpkh(pk: String) -> Result<Self, DescriptorError> {
444        let key = BdkDescriptorPublicKey::from_str(&pk).map_err(|e| DescriptorError::Key {
445            error_message: e.to_string(),
446        })?;
447
448        let miniscript_descriptor = match bdk_wallet::miniscript::Descriptor::new_wpkh(key) {
449            Ok(descriptor) => descriptor,
450            Err(e) => {
451                return Err(DescriptorError::Miniscript {
452                    error_message: e.to_string(),
453                })
454            }
455        };
456        let extended_descriptor = ExtendedDescriptor::from(miniscript_descriptor);
457
458        Ok(Self {
459            extended_descriptor,
460            key_map: KeyMap::new(),
461        })
462    }
463
464    /// Create a new sh wrapped wpkh from Pk. Errors when uncompressed keys are supplied
465    #[uniffi::constructor]
466    pub fn new_sh_wpkh(pk: String) -> Result<Self, DescriptorError> {
467        let key = BdkDescriptorPublicKey::from_str(&pk).map_err(|e| DescriptorError::Key {
468            error_message: e.to_string(),
469        })?;
470
471        let miniscript_descriptor = match bdk_wallet::miniscript::Descriptor::new_sh_wpkh(key) {
472            Ok(descriptor) => descriptor,
473            Err(e) => {
474                return Err(DescriptorError::Miniscript {
475                    error_message: e.to_string(),
476                })
477            }
478        };
479        let extended_descriptor = ExtendedDescriptor::from(miniscript_descriptor);
480
481        Ok(Self {
482            extended_descriptor,
483            key_map: KeyMap::new(),
484        })
485    }
486
487    /// Create a new wsh descriptor from witness script Errors when miniscript exceeds resource limits
488    /// under p2sh context or does not type check at the top level
489    #[uniffi::constructor]
490    pub fn new_wsh(mini_script: String) -> Result<Self, DescriptorError> {
491        let parsed_miniscript = match BdkMiniscript::from_str(&mini_script) {
492            Ok(miniscript) => miniscript,
493            Err(e) => {
494                return Err(DescriptorError::Miniscript {
495                    error_message: e.to_string(),
496                });
497            }
498        };
499
500        let miniscript_descriptor =
501            match bdk_wallet::miniscript::Descriptor::new_wsh(parsed_miniscript) {
502                Ok(descriptor) => descriptor,
503                Err(e) => {
504                    return Err(DescriptorError::Miniscript {
505                        error_message: e.to_string(),
506                    })
507                }
508            };
509        let extended_descriptor = ExtendedDescriptor::from(miniscript_descriptor);
510
511        Ok(Self {
512            extended_descriptor,
513            key_map: KeyMap::new(),
514        })
515    }
516
517    /// Create a new sh wrapped wsh descriptor with witness script Errors when miniscript exceeds resource limits
518    /// under wsh context or does not type check at the top level
519    #[uniffi::constructor]
520    pub fn new_sh_wsh(mini_script: String) -> Result<Self, DescriptorError> {
521        let parsed_miniscript = match BdkMiniscript::from_str(&mini_script) {
522            Ok(miniscript) => miniscript,
523            Err(e) => {
524                return Err(DescriptorError::Miniscript {
525                    error_message: e.to_string(),
526                });
527            }
528        };
529
530        let miniscript_descriptor =
531            match bdk_wallet::miniscript::Descriptor::new_sh_wsh(parsed_miniscript) {
532                Ok(descriptor) => descriptor,
533                Err(e) => {
534                    return Err(DescriptorError::Miniscript {
535                        error_message: e.to_string(),
536                    })
537                }
538            };
539        let extended_descriptor = ExtendedDescriptor::from(miniscript_descriptor);
540
541        Ok(Self {
542            extended_descriptor,
543            key_map: KeyMap::new(),
544        })
545    }
546
547    /// Create a new sh for a given redeem script Errors when miniscript exceeds resource limits under p2sh context or does not type check at the top level
548    #[uniffi::constructor]
549    pub fn new_sh(mini_script: String) -> Result<Self, DescriptorError> {
550        let parsed_miniscript = match BdkMiniscript::from_str(&mini_script) {
551            Ok(miniscript) => miniscript,
552            Err(e) => {
553                return Err(DescriptorError::Miniscript {
554                    error_message: e.to_string(),
555                });
556            }
557        };
558
559        let miniscript_descriptor =
560            match bdk_wallet::miniscript::Descriptor::new_sh(parsed_miniscript) {
561                Ok(descriptor) => descriptor,
562                Err(e) => {
563                    return Err(DescriptorError::Miniscript {
564                        error_message: e.to_string(),
565                    })
566                }
567            };
568        let extended_descriptor = ExtendedDescriptor::from(miniscript_descriptor);
569
570        Ok(Self {
571            extended_descriptor,
572            key_map: KeyMap::new(),
573        })
574    }
575
576    /// Create a new bare descriptor from witness script Errors when miniscript exceeds resource limits
577    /// under bare context or does not type check at the top level
578    #[uniffi::constructor]
579    pub fn new_bare(mini_script: String) -> Result<Self, DescriptorError> {
580        let parsed_miniscript = match BdkMiniscript::from_str(&mini_script) {
581            Ok(miniscript) => miniscript,
582            Err(e) => {
583                return Err(DescriptorError::Miniscript {
584                    error_message: e.to_string(),
585                });
586            }
587        };
588
589        let miniscript_descriptor =
590            match bdk_wallet::miniscript::Descriptor::new_bare(parsed_miniscript) {
591                Ok(descriptor) => descriptor,
592                Err(e) => {
593                    return Err(DescriptorError::Miniscript {
594                        error_message: e.to_string(),
595                    })
596                }
597            };
598        let extended_descriptor = ExtendedDescriptor::from(miniscript_descriptor);
599
600        Ok(Self {
601            extended_descriptor,
602            key_map: KeyMap::new(),
603        })
604    }
605
606    /// Create a new sh wrapper for the given wpkh descriptor
607    #[uniffi::constructor]
608    pub fn new_sh_with_wpkh(wpkh: String) -> Result<Self, DescriptorError> {
609        let descriptor = BdkDescriptor::<BdkDescriptorPublicKey>::from_str(&wpkh).map_err(|e| {
610            DescriptorError::Miniscript {
611                error_message: e.to_string(),
612            }
613        })?;
614
615        if let BdkDescriptor::Wpkh(wpkh_inner) = descriptor {
616            let sh_with_wpkh = bdk_wallet::miniscript::Descriptor::new_sh_with_wpkh(wpkh_inner);
617            Ok(Self {
618                extended_descriptor: ExtendedDescriptor::from(sh_with_wpkh),
619                key_map: KeyMap::new(),
620            })
621        } else {
622            Err(DescriptorError::Miniscript {
623                error_message: "Provided descriptor is not a valid wpkh descriptor".to_string(),
624            })
625        }
626    }
627
628    /// Create a new sh wrapper for the given wsh descriptor
629    #[uniffi::constructor]
630    pub fn new_sh_with_wsh(wsh: String) -> Result<Self, DescriptorError> {
631        let descriptor = BdkDescriptor::<BdkDescriptorPublicKey>::from_str(&wsh).map_err(|e| {
632            DescriptorError::Miniscript {
633                error_message: e.to_string(),
634            }
635        })?;
636
637        if let BdkDescriptor::Wsh(wsh_inner) = descriptor {
638            let sh_with_wsh = bdk_wallet::miniscript::Descriptor::new_sh_with_wsh(wsh_inner);
639            Ok(Self {
640                extended_descriptor: ExtendedDescriptor::from(sh_with_wsh),
641                key_map: KeyMap::new(),
642            })
643        } else {
644            Err(DescriptorError::Miniscript {
645                error_message: "Provided descriptor is not a valid wsh descriptor".to_string(),
646            })
647        }
648    }
649
650    /// Create new tr descriptor
651    /// Errors when miniscript exceeds resource limits under Tap context
652    #[uniffi::constructor]
653    pub fn new_tr(key: String, script: Option<String>) -> Result<Self, DescriptorError> {
654        let key = BdkDescriptorPublicKey::from_str(&key).map_err(|e| DescriptorError::Key {
655            error_message: e.to_string(),
656        })?;
657        let tap_tree = match script {
658            Some(s) => {
659                let ms_tap =
660                    BdkMiniscript::from_str(&s).map_err(|e| DescriptorError::Miniscript {
661                        error_message: e.to_string(),
662                    })?;
663
664                Some(TapTree::Leaf(Arc::new(ms_tap)))
665            }
666            None => None,
667        };
668
669        let descriptor =
670            bdk_wallet::miniscript::Descriptor::new_tr(key, tap_tree).map_err(|e| {
671                DescriptorError::Miniscript {
672                    error_message: e.to_string(),
673                }
674            })?;
675        Ok(Self {
676            extended_descriptor: ExtendedDescriptor::from(descriptor),
677            key_map: KeyMap::new(),
678        })
679    }
680
681    /// Return a public version of this descriptor without secret key material.
682    pub fn as_public(&self) -> Arc<Self> {
683        Arc::new(Self {
684            extended_descriptor: self.extended_descriptor.clone(),
685            key_map: KeyMap::new(),
686        })
687    }
688
689    /// Dangerously convert the descriptor to a string.
690    pub fn to_string_with_secret(&self) -> String {
691        let descriptor = &self.extended_descriptor;
692        let key_map = &self.key_map;
693        descriptor.to_string_with_secret(key_map)
694    }
695
696    /// Does this descriptor contain paths: https://github.com/bitcoin/bips/blob/master/bip-0389.mediawiki
697    pub fn is_multipath(&self) -> bool {
698        self.extended_descriptor.is_multipath()
699    }
700
701    /// A unique identifier for the descriptor.
702    pub fn descriptor_id(&self) -> Arc<DescriptorId> {
703        let d_id = self.extended_descriptor.descriptor_id();
704        Arc::new(DescriptorId(d_id.0))
705    }
706
707    /// Return descriptors for all valid paths.
708    pub fn to_single_descriptors(&self) -> Result<Vec<Arc<Descriptor>>, MiniscriptError> {
709        self.extended_descriptor
710            .clone()
711            .into_single_descriptors()
712            .map_err(MiniscriptError::from)
713            .map(|descriptors| {
714                descriptors
715                    .into_iter()
716                    .map(|desc| {
717                        Arc::new(Descriptor {
718                            extended_descriptor: desc,
719                            key_map: self.key_map.clone(),
720                        })
721                    })
722                    .collect()
723            })
724    }
725
726    /// Computes an upper bound on the difference between a non-satisfied `TxIn`'s
727    /// `segwit_weight` and a satisfied `TxIn`'s `segwit_weight`.
728    pub fn max_weight_to_satisfy(&self) -> Result<u64, DescriptorError> {
729        let weight = self
730            .extended_descriptor
731            .max_weight_to_satisfy()
732            .map_err(|e| DescriptorError::Miniscript {
733                error_message: e.to_string(),
734            })?;
735        Ok(weight.to_wu())
736    }
737
738    pub fn desc_type(&self) -> DescriptorType {
739        self.extended_descriptor.desc_type()
740    }
741
742    pub fn derive_address(
743        &self,
744        index: u32,
745        network: Network,
746    ) -> Result<Arc<Address>, DescriptorError> {
747        if self.extended_descriptor.is_multipath() {
748            return Err(DescriptorError::MultiPath);
749        }
750
751        let derived_descriptor = self
752            .extended_descriptor
753            .at_derivation_index(index)
754            .map_err(|error| match error {
755                ConversionError::HardenedChild => DescriptorError::HardenedDerivationXpub,
756                ConversionError::MultiKey => DescriptorError::MultiPath,
757            })?;
758
759        let address = derived_descriptor
760            .address(network)
761            .map_err(|error| DescriptorError::Miniscript {
762                error_message: error.to_string(),
763            })?
764            .into();
765
766        Ok(Arc::new(address))
767    }
768
769    /// Whether or not the descriptor has any wildcards.
770    pub fn has_wildcard(&self) -> bool {
771        self.extended_descriptor.has_wildcard()
772    }
773
774    /// Checks whether the descriptor is safe.
775    ///
776    /// Checks whether all the spend paths in the descriptor are possible on the
777    /// bitcoin network under the current standardness and consensus rules. Also
778    /// checks whether the descriptor requires signatures on all spend paths and
779    /// whether the script is malleable.
780    ///
781    /// In general, all the guarantees of miniscript hold only for safe scripts.
782    /// The signer may not be able to find satisfactions even if one exists.
783    pub fn sanity_check(&self) -> Result<(), DescriptorError> {
784        self.extended_descriptor
785            .sanity_check()
786            .map_err(|e| DescriptorError::Miniscript {
787                error_message: e.to_string(),
788            })
789    }
790}
791
792impl Display for Descriptor {
793    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
794        write!(f, "{}", self.extended_descriptor)
795    }
796}