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