Skip to content

Commit 0778ad4

Browse files
authored
feat: add miniscript key descriptor methods
1 parent a5918b0 commit 0778ad4

3 files changed

Lines changed: 142 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
99
### Added
1010
- Expose miniscript `has_wildcard` and `sanity_check` methods on `Descriptor` type #945
1111
- Expose `new_wsh_sortedmulti` and `new_pk` methods on `Descriptor` type #949
12+
- Expose `new_sh_sortedmulti`, `new_sh_wsh_sortedmulti`, `new_pkh`, `new_wpkh`, `new_sh_wpkh` methods on `Descriptor` type #973
1213

1314
## [v2.3.0]
1415

bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/DescriptorTest.kt

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,17 @@ class DescriptorTest {
4949
"xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB",
5050
"xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB"
5151
)
52-
val wshDescriptor = Descriptor.newWshSortedmulti(2u, pkList);
52+
val wshSortedMultiDescriptor = Descriptor.newWshSortedmulti(2u, pkList);
53+
val shWshSortedMultiDescriptor = Descriptor.newShWshSortedmulti(2u, pkList);
54+
val shSortedMultiDescriptor = Descriptor.newShSortedmulti(2u, pkList);
5355

54-
assertEquals(wshDescriptor.descType(), DescriptorType.WSH_SORTED_MULTI)
56+
assertEquals(wshSortedMultiDescriptor.descType(), DescriptorType.WSH_SORTED_MULTI)
57+
assertEquals(shWshSortedMultiDescriptor.descType(), DescriptorType.SH_WSH_SORTED_MULTI)
58+
assertEquals(shSortedMultiDescriptor.descType(), DescriptorType.SH_SORTED_MULTI)
5559
}
5660

5761
@Test
58-
fun createInvalidMutlisigDescriptor() {
62+
fun createInvalidMultisigDescriptor() {
5963
val invalidPkList = listOf(
6064
"invalid_xpub",
6165
"1111111111111",
@@ -69,7 +73,14 @@ class DescriptorTest {
6973
@Test
7074
fun createSingleKeyDescriptor() {
7175
val newPkDescriptor = Descriptor.newPk("xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB")
76+
val newPkhDescriptor = Descriptor.newPkh("xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB")
77+
val newWpkhDescriptor = Descriptor.newWpkh("xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB")
78+
val newShWpkhDescriptor = Descriptor.newShWpkh("xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB")
79+
7280
assertEquals(newPkDescriptor.descType(), DescriptorType.BARE)
81+
assertEquals(newPkhDescriptor.descType(), DescriptorType.PKH)
82+
assertEquals(newWpkhDescriptor.descType(), DescriptorType.WPKH)
83+
assertEquals(newShWpkhDescriptor.descType(), DescriptorType.SH_WPKH)
7384
}
7485

7586
// Cannot create addr() descriptor.

bdk-ffi/src/descriptor.rs

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,64 @@ impl Descriptor {
334334
})
335335
}
336336

337+
/// Create a new sh sortedmulti descriptor with threshold k and Vec of pks.
338+
/// Errors when miniscript exceeds resource limits under p2sh context
339+
#[uniffi::constructor]
340+
pub fn new_sh_sortedmulti(k: u32, pks: Vec<String>) -> Result<Self, DescriptorError> {
341+
let bdk_pks: Vec<BdkDescriptorPublicKey> = pks
342+
.iter()
343+
.map(|pk| {
344+
BdkDescriptorPublicKey::from_str(pk).map_err(|e| DescriptorError::Key {
345+
error_message: e.to_string(),
346+
})
347+
})
348+
.collect::<Result<Vec<BdkDescriptorPublicKey>, DescriptorError>>()?;
349+
let miniscript_descriptor =
350+
match bdk_wallet::miniscript::Descriptor::new_sh_sortedmulti(k as usize, bdk_pks) {
351+
Ok(descriptor) => descriptor,
352+
Err(e) => {
353+
return Err(DescriptorError::Miniscript {
354+
error_message: e.to_string(),
355+
})
356+
}
357+
};
358+
let extended_descriptor = ExtendedDescriptor::from(miniscript_descriptor);
359+
360+
Ok(Self {
361+
extended_descriptor,
362+
key_map: KeyMap::new(),
363+
})
364+
}
365+
366+
/// Create a new sh wrapped wsh sortedmulti descriptor from threshold k and Vec of pks
367+
/// Errors when miniscript exceeds resource limits under segwit context
368+
#[uniffi::constructor]
369+
pub fn new_sh_wsh_sortedmulti(k: u32, pks: Vec<String>) -> Result<Self, DescriptorError> {
370+
let bdk_pks: Vec<BdkDescriptorPublicKey> = pks
371+
.iter()
372+
.map(|pk| {
373+
BdkDescriptorPublicKey::from_str(pk).map_err(|e| DescriptorError::Key {
374+
error_message: e.to_string(),
375+
})
376+
})
377+
.collect::<Result<Vec<BdkDescriptorPublicKey>, DescriptorError>>()?;
378+
let miniscript_descriptor =
379+
match bdk_wallet::miniscript::Descriptor::new_sh_wsh_sortedmulti(k as usize, bdk_pks) {
380+
Ok(descriptor) => descriptor,
381+
Err(e) => {
382+
return Err(DescriptorError::Miniscript {
383+
error_message: e.to_string(),
384+
})
385+
}
386+
};
387+
let extended_descriptor = ExtendedDescriptor::from(miniscript_descriptor);
388+
389+
Ok(Self {
390+
extended_descriptor,
391+
key_map: KeyMap::new(),
392+
})
393+
}
394+
337395
/// Create a new pay-to-pubkey descriptor from a public key string.
338396
#[uniffi::constructor]
339397
pub fn new_pk(pk: String) -> Result<Self, DescriptorError> {
@@ -350,6 +408,75 @@ impl Descriptor {
350408
})
351409
}
352410

411+
/// Create a new PkH descriptor
412+
#[uniffi::constructor]
413+
pub fn new_pkh(pk: String) -> Result<Self, DescriptorError> {
414+
let key = BdkDescriptorPublicKey::from_str(&pk).map_err(|e| DescriptorError::Key {
415+
error_message: e.to_string(),
416+
})?;
417+
418+
let miniscript_descriptor = match bdk_wallet::miniscript::Descriptor::new_pkh(key) {
419+
Ok(descriptor) => descriptor,
420+
Err(e) => {
421+
return Err(DescriptorError::Miniscript {
422+
error_message: e.to_string(),
423+
})
424+
}
425+
};
426+
let extended_descriptor = ExtendedDescriptor::from(miniscript_descriptor);
427+
428+
Ok(Self {
429+
extended_descriptor,
430+
key_map: KeyMap::new(),
431+
})
432+
}
433+
434+
/// Create a new Wpkh descriptor Will return Err if uncompressed key is used
435+
#[uniffi::constructor]
436+
pub fn new_wpkh(pk: String) -> Result<Self, DescriptorError> {
437+
let key = BdkDescriptorPublicKey::from_str(&pk).map_err(|e| DescriptorError::Key {
438+
error_message: e.to_string(),
439+
})?;
440+
441+
let miniscript_descriptor = match bdk_wallet::miniscript::Descriptor::new_wpkh(key) {
442+
Ok(descriptor) => descriptor,
443+
Err(e) => {
444+
return Err(DescriptorError::Miniscript {
445+
error_message: e.to_string(),
446+
})
447+
}
448+
};
449+
let extended_descriptor = ExtendedDescriptor::from(miniscript_descriptor);
450+
451+
Ok(Self {
452+
extended_descriptor,
453+
key_map: KeyMap::new(),
454+
})
455+
}
456+
457+
/// Create a new sh wrapped wpkh from Pk. Errors when uncompressed keys are supplied
458+
#[uniffi::constructor]
459+
pub fn new_sh_wpkh(pk: String) -> Result<Self, DescriptorError> {
460+
let key = BdkDescriptorPublicKey::from_str(&pk).map_err(|e| DescriptorError::Key {
461+
error_message: e.to_string(),
462+
})?;
463+
464+
let miniscript_descriptor = match bdk_wallet::miniscript::Descriptor::new_sh_wpkh(key) {
465+
Ok(descriptor) => descriptor,
466+
Err(e) => {
467+
return Err(DescriptorError::Miniscript {
468+
error_message: e.to_string(),
469+
})
470+
}
471+
};
472+
let extended_descriptor = ExtendedDescriptor::from(miniscript_descriptor);
473+
474+
Ok(Self {
475+
extended_descriptor,
476+
key_map: KeyMap::new(),
477+
})
478+
}
479+
353480
/// Dangerously convert the descriptor to a string.
354481
pub fn to_string_with_secret(&self) -> String {
355482
let descriptor = &self.extended_descriptor;

0 commit comments

Comments
 (0)