diff --git a/src/handlers/descriptor.rs b/src/handlers/descriptor.rs index e35fcea3..ba5005c5 100644 --- a/src/handlers/descriptor.rs +++ b/src/handlers/descriptor.rs @@ -13,6 +13,8 @@ use crate::{ }; use clap::Parser; #[cfg(feature = "compiler")] +use clap::ValueEnum; +#[cfg(feature = "compiler")] use { bdk_wallet::{ bitcoin::{ @@ -70,9 +72,24 @@ pub struct CompileCommand { #[arg(env = "POLICY", required = true, index = 1)] policy: String, /// Sets the script type used to embed the compiled policy. - #[arg(env = "TYPE", short = 't', long = "type", default_value = "wsh", value_parser = ["sh","wsh", "sh-wsh", "tr"] - )] - script_type: String, + #[arg( + env = "TYPE", + short = 't', + long = "type", + value_enum, + default_value_t = ScriptType::Wsh + )] + script_type: ScriptType, +} + +/// Script types the compiled policy can be embedded in. +#[cfg(feature = "compiler")] +#[derive(Clone, Copy, ValueEnum, Debug, Eq, PartialEq)] +pub enum ScriptType { + Sh, + Wsh, + ShWsh, + Tr, } #[cfg(feature = "compiler")] @@ -87,11 +104,11 @@ impl AppCommand> for CompileCommand { // Compile per branch, not once up front: the contexts have different script // limits, and the narrowest one would reject policies valid for the requested type. - let descriptor = match self.script_type.as_str() { - "sh" => Descriptor::new_sh(policy.compile()?), - "wsh" => Descriptor::new_wsh(policy.compile()?), - "sh-wsh" => Descriptor::new_sh_wsh(policy.compile()?), - "tr" => { + let descriptor = match self.script_type { + ScriptType::Sh => Descriptor::new_sh(policy.compile()?), + ScriptType::Wsh => Descriptor::new_wsh(policy.compile()?), + ScriptType::ShWsh => Descriptor::new_sh_wsh(policy.compile()?), + ScriptType::Tr => { // Use a randomized unspendable internal key (H + rG) instead of a fixed NUMS // point. This improves privacy by preventing observers from determining whether // key-path spending is disabled. `r` is returned so the user can verify the key @@ -113,11 +130,6 @@ impl AppCommand> for CompileCommand { let tree = TapTree::Leaf(Arc::new(policy.compile()?)); Descriptor::new_tr(xonly_internal_key.to_string(), Some(tree)) } - _ => { - return Err(Error::Generic( - "Invalid script type. Supported: sh, wsh, sh-wsh, tr".into(), - )); - } }?; Ok(DescriptorResult { diff --git a/tests/integration/init.rs b/tests/integration/init.rs index 5244d996..120341ab 100644 --- a/tests/integration/init.rs +++ b/tests/integration/init.rs @@ -223,6 +223,26 @@ mod test_compile { .stdout(predicate::str::contains("wsh(")); } + #[test] + fn test_compile_sh_and_sh_wsh() { + let temp_dir = TempDir::new().unwrap(); + let cli = BdkCli::new("testnet", Some(temp_dir.path().to_path_buf())); + + let policy = "pk(02e5b88fdb71c696e1a473f309a47535b7190e21a22bd25e7fc8bd055db3bba12f)"; + + // compile sh + cli.cmd("compile", &[policy, "--type", "sh"]) + .assert() + .success() + .stdout(predicate::str::contains("\"descriptor\": \"sh(pk(")); + + // compile sh-wsh + cli.cmd("compile", &[policy, "--type", "sh-wsh"]) + .assert() + .success() + .stdout(predicate::str::contains("\"descriptor\": \"sh(wsh(pk(")); + } + #[test] fn test_compile_invalid_policy() { let temp_dir = TempDir::new().unwrap();