logo
macro_rules! descriptor {
    ( bare ( $( $minisc:tt )* ) ) => { ... };
    ( sh ( wsh ( $( $minisc:tt )* ) ) ) => { ... };
    ( shwsh ( $( $minisc:tt )* ) ) => { ... };
    ( pk ( $key:expr ) ) => { ... };
    ( pkh ( $key:expr ) ) => { ... };
    ( wpkh ( $key:expr ) ) => { ... };
    ( sh ( wpkh ( $key:expr ) ) ) => { ... };
    ( shwpkh ( $key:expr ) ) => { ... };
    ( sh ( $( $minisc:tt )* ) ) => { ... };
    ( wsh ( $( $minisc:tt )* ) ) => { ... };
}
Expand description

Macro to write full descriptors with code

This macro expands to a Result of DescriptorTemplateOut and DescriptorError

The syntax is very similar to the normal descriptor syntax, with the exception that modifiers cannot be grouped together. For instance, a descriptor fragment like sdv:older(144) has to be broken up to s:d:v:older(144).

The pk(), pk_k() and pk_h() operands can take as argument any type that implements IntoDescriptorKey. This means that keys can also be written inline as strings, but in that case they must be wrapped in quotes, which is another difference compared to the standard descriptor syntax.

Example

Signature plus timelock descriptor:

let (my_descriptor, my_keys_map, networks) = bdk::descriptor!(sh(wsh(and_v(v:pk("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy"),older(50)))))?;

2-of-3 that becomes a 1-of-3 after a timelock has expired. Both descriptor_a and descriptor_b are equivalent: the first syntax is more suitable for a fixed number of items known at compile time, while the other accepts a Vec of items, which makes it more suitable for writing dynamic descriptors.

They both produce the descriptor: wsh(thresh(2,pk(...),s:pk(...),sndv:older(...)))

let my_key_1 = bitcoin::PublicKey::from_str(
    "02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c",
)?;
let my_key_2 =
    bitcoin::PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy")?;
let my_timelock = 50;

let (descriptor_a, key_map_a, networks) = bdk::descriptor! {
    wsh (
        thresh(2, pk(my_key_1), s:pk(my_key_2), s:n:d:v:older(my_timelock))
    )
}?;

#[rustfmt::skip]
let b_items = vec![
    bdk::fragment!(pk(my_key_1))?,
    bdk::fragment!(s:pk(my_key_2))?,
    bdk::fragment!(s:n:d:v:older(my_timelock))?,
];
let (descriptor_b, mut key_map_b, networks) = bdk::descriptor!(wsh(thresh_vec(2, b_items)))?;

assert_eq!(descriptor_a, descriptor_b);
assert_eq!(key_map_a.len(), key_map_b.len());

Simple 2-of-2 multi-signature, equivalent to: wsh(multi(2, ...))

let my_key_1 = bitcoin::PublicKey::from_str(
    "02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c",
)?;
let my_key_2 =
    bitcoin::PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy")?;

let (descriptor, key_map, networks) = bdk::descriptor! {
    wsh (
        multi(2, my_key_1, my_key_2)
    )
}?;

Native-Segwit single-sig, equivalent to: wpkh(...)

let my_key =
    bitcoin::PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy")?;

let (descriptor, key_map, networks) = bdk::descriptor!(wpkh(my_key))?;