Skip to content

Commit b6b6a29

Browse files
committed
feat: expose derived_address helper on Descriptor
1 parent fa23c99 commit b6b6a29

File tree

2 files changed

+53
-0
lines changed

2 files changed

+53
-0
lines changed

bdk-ffi/src/descriptor.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::bitcoin::Address;
12
use crate::bitcoin::DescriptorId;
23
use crate::bitcoin::DescriptorType;
34
use crate::error::DescriptorError;
@@ -12,6 +13,7 @@ use bdk_wallet::chain::DescriptorExt;
1213
use bdk_wallet::descriptor::{ExtendedDescriptor, IntoWalletDescriptor};
1314
use bdk_wallet::keys::DescriptorPublicKey as BdkDescriptorPublicKey;
1415
use bdk_wallet::keys::{DescriptorSecretKey as BdkDescriptorSecretKey, KeyMap};
16+
use bdk_wallet::miniscript::descriptor::ConversionError;
1517
use bdk_wallet::template::{
1618
Bip44, Bip44Public, Bip49, Bip49Public, Bip84, Bip84Public, Bip86, Bip86Public,
1719
DescriptorTemplate,
@@ -355,6 +357,30 @@ impl Descriptor {
355357
pub fn desc_type(&self) -> DescriptorType {
356358
self.extended_descriptor.desc_type()
357359
}
360+
361+
pub fn derived_address(
362+
&self,
363+
index: u32,
364+
network: Network,
365+
) -> Result<Arc<Address>, DescriptorError> {
366+
let secp = Secp256k1::verification_only();
367+
let derived_descriptor = self
368+
.extended_descriptor
369+
.at_derivation_index(index)
370+
.and_then(|desc| desc.derived_descriptor(&secp))
371+
.map_err(|error| match error {
372+
ConversionError::HardenedChild => DescriptorError::HardenedDerivationXpub,
373+
ConversionError::MultiKey => DescriptorError::MultiPath,
374+
})?;
375+
let script_pubkey = derived_descriptor.script_pubkey();
376+
let address = bdk_wallet::bitcoin::Address::from_script(&script_pubkey, network).map_err(
377+
|error| DescriptorError::Miniscript {
378+
error_message: error.to_string(),
379+
},
380+
)?;
381+
382+
Ok(Arc::new(address.into()))
383+
}
358384
}
359385

360386
impl Display for Descriptor {

bdk-ffi/src/tests/descriptor.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::descriptor::Descriptor;
33
use crate::error::DescriptorError;
44
use crate::keys::{DerivationPath, DescriptorSecretKey, Mnemonic};
55
use assert_matches::assert_matches;
6+
use bdk_wallet::bitcoin::secp256k1::Secp256k1;
67
use bdk_wallet::KeychainKind;
78

89
fn get_descriptor_secret_key() -> DescriptorSecretKey {
@@ -161,3 +162,29 @@ fn test_max_weight_to_satisfy() {
161162
// Verify the method works and returns a positive weight
162163
assert!(weight > 0, "Weight must be positive");
163164
}
165+
166+
#[test]
167+
fn test_descriptor_derived_address() {
168+
let descriptor = Descriptor::new_bip84(
169+
&get_descriptor_secret_key(),
170+
KeychainKind::External,
171+
Network::Testnet,
172+
);
173+
174+
let derived = descriptor
175+
.derived_address(0, Network::Testnet)
176+
.expect("derive address");
177+
178+
let secp = Secp256k1::verification_only();
179+
let expected_descriptor = descriptor
180+
.extended_descriptor
181+
.derived_descriptor(&secp, 0)
182+
.expect("derive descriptor");
183+
let expected_address = bdk_wallet::bitcoin::Address::from_script(
184+
&expected_descriptor.script_pubkey(),
185+
Network::Testnet,
186+
)
187+
.expect("address from script");
188+
189+
assert_eq!(derived.to_string(), expected_address.to_string());
190+
}

0 commit comments

Comments
 (0)