diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f768af9..05fa59f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Added - Expose miniscript `has_wildcard` and `sanity_check` methods on `Descriptor` type #945 +- Expose `new_wsh_sortedmulti` and `new_pk` methods on `Descriptor` type #949 ## [v2.3.0] diff --git a/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/DescriptorTest.kt b/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/DescriptorTest.kt index 7064f220..16f0f12e 100644 --- a/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/DescriptorTest.kt +++ b/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/DescriptorTest.kt @@ -40,6 +40,32 @@ class DescriptorTest { Descriptor("tr($MAINNET_EXTENDED_PRIVKEY/$BIP86_MAINNET_RECEIVE_PATH/0)", Network.BITCOIN) } + // Create a multisig descriptor. + @Test + fun createMultisigDescriptor() { + val pkList = listOf( + "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB", + "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB", + "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB" + ) + + Descriptor.newWshSortedmulti(2u, pkList); + + val invalidPkList = listOf( + "invalid_xpub", + "1111111111111", + "***" + ) + assertFails { + Descriptor.newWshSortedmulti(2u, invalidPkList); + } + } + + @Test + fun createSingleKeyDescriptor() { + Descriptor.newPk("xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB") + } + // Cannot create addr() descriptor. @Test fun cannotCreateAddrDescriptor() { diff --git a/bdk-ffi/src/descriptor.rs b/bdk-ffi/src/descriptor.rs index db705391..19a9c281 100644 --- a/bdk-ffi/src/descriptor.rs +++ b/bdk-ffi/src/descriptor.rs @@ -305,6 +305,52 @@ impl Descriptor { } } + /// Create a new wsh sorted multi descriptor + /// Errors when miniscript exceeds resource limits under p2sh context + #[uniffi::constructor] + pub fn new_wsh_sortedmulti(k: u32, pks: Vec) -> Result { + let bdk_pks: Vec = pks + .iter() + .map(|pk| { + BdkDescriptorPublicKey::from_str(pk).map_err(|e| DescriptorError::Miniscript { + error_message: e.to_string(), + }) + }) + .collect::, DescriptorError>>()?; + let miniscript_descriptor = + match bdk_wallet::miniscript::Descriptor::new_wsh_sortedmulti(k as usize, bdk_pks) { + Ok(descriptor) => descriptor, + Err(e) => { + return Err(DescriptorError::Miniscript { + error_message: e.to_string(), + }) + } + }; + let extended_descriptor = ExtendedDescriptor::from(miniscript_descriptor); + + Ok(Self { + extended_descriptor, + key_map: KeyMap::new(), + }) + } + + /// Create a new pay-to-pubkey descriptor from a public key string. + #[uniffi::constructor] + pub fn new_pk(pk: String) -> Result { + let key = + BdkDescriptorPublicKey::from_str(&pk).map_err(|e| DescriptorError::Miniscript { + error_message: e.to_string(), + })?; + + let miniscript_descriptor = bdk_wallet::miniscript::Descriptor::new_pk(key); + let extended_descriptor = ExtendedDescriptor::from(miniscript_descriptor); + + Ok(Self { + extended_descriptor, + key_map: KeyMap::new(), + }) + } + /// Dangerously convert the descriptor to a string. pub fn to_string_with_secret(&self) -> String { let descriptor = &self.extended_descriptor;