diff --git a/src/descriptor/dsl.rs b/src/descriptor/dsl.rs index 4296b4d9..34081ab1 100644 --- a/src/descriptor/dsl.rs +++ b/src/descriptor/dsl.rs @@ -577,6 +577,23 @@ impl From<(A, (B, (C, ())))> for TupleThree { } } +#[doc(hidden)] +#[macro_export] +macro_rules! group_multi_keys { + ( $( $key:expr ),+ ) => {{ + use $crate::keys::IntoDescriptorKey; + + let keys = vec![ + $( + $key.into_descriptor_key(), + )* + ]; + + keys.into_iter().collect::, _>>() + .map_err($crate::descriptor::DescriptorError::Key) + }}; +} + #[doc(hidden)] #[macro_export] macro_rules! fragment_internal { @@ -737,21 +754,22 @@ macro_rules! fragment { .and_then(|items| $crate::fragment!(thresh_vec($thresh, items))) }); ( multi_vec ( $thresh:expr, $keys:expr ) ) => ({ - $crate::keys::make_multi($thresh, $keys) - }); - ( multi ( $thresh:expr $(, $key:expr )+ ) ) => ({ - use $crate::keys::IntoDescriptorKey; let secp = $crate::bitcoin::secp256k1::Secp256k1::new(); - let keys = vec![ - $( - $key.into_descriptor_key(), - )* - ]; + $crate::keys::make_multi($thresh, $crate::miniscript::Terminal::Multi, $keys, &secp) + }); + ( multi ( $thresh:expr $(, $key:expr )+ ) ) => ({ + $crate::group_multi_keys!( $( $key ),* ) + .and_then(|keys| $crate::fragment!( multi_vec ( $thresh, keys ) )) + }); + ( multi_a_vec ( $thresh:expr, $keys:expr ) ) => ({ + let secp = $crate::bitcoin::secp256k1::Secp256k1::new(); - keys.into_iter().collect::, _>>() - .map_err($crate::descriptor::DescriptorError::Key) - .and_then(|keys| $crate::keys::make_multi($thresh, keys, &secp)) + $crate::keys::make_multi($thresh, $crate::miniscript::Terminal::MultiA, $keys, &secp) + }); + ( multi_a ( $thresh:expr $(, $key:expr )+ ) ) => ({ + $crate::group_multi_keys!( $( $key ),* ) + .and_then(|keys| $crate::fragment!( multi_a_vec ( $thresh, keys ) )) }); // `sortedmulti()` is handled separately diff --git a/src/keys/mod.rs b/src/keys/mod.rs index 320cca1f..20ff5818 100644 --- a/src/keys/mod.rs +++ b/src/keys/mod.rs @@ -792,13 +792,18 @@ pub fn make_pkh, Ctx: ScriptContext>( // Used internally by `bdk::fragment!` to build `multi()` fragments #[doc(hidden)] -pub fn make_multi, Ctx: ScriptContext>( +pub fn make_multi< + Pk: IntoDescriptorKey, + Ctx: ScriptContext, + V: Fn(usize, Vec) -> Terminal, +>( thresh: usize, + variant: V, pks: Vec, secp: &SecpCtx, ) -> Result<(Miniscript, KeyMap, ValidNetworks), DescriptorError> { let (pks, key_map, valid_networks) = expand_multi_keys(pks, secp)?; - let minisc = Miniscript::from_ast(Terminal::Multi(thresh, pks))?; + let minisc = Miniscript::from_ast(variant(thresh, pks))?; minisc.check_miniscript()?;