From 0c15036ec09fd41002387626fdbd291e3b91ffe9 Mon Sep 17 00:00:00 2001 From: Otto Allmendinger Date: Wed, 29 Apr 2026 15:32:07 +0200 Subject: [PATCH 1/4] build(wasm-utxo): bump rust-miniscript to bitgo.3 Update miniscript dependency from 13.0.0-bitgo.2 to 13.0.0-bitgo.3 to include latest fixes. Issue: BTC-3357 Co-authored-by: llm-git --- packages/wasm-utxo/Cargo.lock | 2 +- packages/wasm-utxo/Cargo.toml | 2 +- packages/wasm-utxo/src/wasm/try_into_js_value.rs | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/wasm-utxo/Cargo.lock b/packages/wasm-utxo/Cargo.lock index 890a6b32a50..e16e3ab3407 100644 --- a/packages/wasm-utxo/Cargo.lock +++ b/packages/wasm-utxo/Cargo.lock @@ -1675,7 +1675,7 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniscript" version = "13.0.0" -source = "git+https://github.com/BitGo/rust-miniscript?tag=miniscript-13.0.0-bitgo.2#25595dc04a51240cf8dfb6df21d3c6bef84089b9" +source = "git+https://github.com/BitGo/rust-miniscript?tag=miniscript-13.0.0-bitgo.3#5d30fff5f4af6d76657ca5fd27b2fa14da8e51e2" dependencies = [ "bech32", "bitcoin", diff --git a/packages/wasm-utxo/Cargo.toml b/packages/wasm-utxo/Cargo.toml index 20e1bd727f5..7c876ede69e 100644 --- a/packages/wasm-utxo/Cargo.toml +++ b/packages/wasm-utxo/Cargo.toml @@ -27,7 +27,7 @@ inspect = ["dep:num-bigint", "dep:serde", "dep:serde_json", "dep:hex"] [dependencies] wasm-bindgen = "0.2" js-sys = "0.3" -miniscript = { git = "https://github.com/BitGo/rust-miniscript", tag = "miniscript-13.0.0-bitgo.2" } +miniscript = { git = "https://github.com/BitGo/rust-miniscript", tag = "miniscript-13.0.0-bitgo.3" } bech32 = "0.11" musig2 = { version = "0.3.1", default-features = false, features = ["k256"] } getrandom = { version = "0.2", features = ["js"] } diff --git a/packages/wasm-utxo/src/wasm/try_into_js_value.rs b/packages/wasm-utxo/src/wasm/try_into_js_value.rs index 5592b45e506..9ba6bba355f 100644 --- a/packages/wasm-utxo/src/wasm/try_into_js_value.rs +++ b/packages/wasm-utxo/src/wasm/try_into_js_value.rs @@ -203,6 +203,9 @@ impl TryIntoJsValue for Terminal::Thresh(t) => js_obj!("Thresh" => t), Terminal::Multi(pks) => js_obj!("Multi" => pks), Terminal::MultiA(pks) => js_obj!("MultiA" => pks), + Terminal::PayloadDrop(payload) => { + js_obj!("PayloadDrop" => payload.iter().map(|b| format!("{:02x}", b)).collect::()) + } } } } From dbbe2b9b81b5a2df978152ecc90a493df8d068cc Mon Sep 17 00:00:00 2001 From: Otto Allmendinger Date: Tue, 28 Apr 2026 17:21:15 +0200 Subject: [PATCH 2/4] feat(wasm-utxo): implement ExtParamsConfig for descriptor parsing Add ExtParamsConfig struct to enable fine-grained control over miniscript analysis checks when parsing descriptors. This allows callers to selectively enable non-standard behaviors like drop operations, timelock mixing, or malleability. The configuration uses camelCase field names for JavaScript compatibility and defaults all flags to false for sane behavior. Issue: BTC-3357 Co-authored-by: llm-git --- packages/wasm-utxo/js/index.ts | 15 ++++ packages/wasm-utxo/src/wasm/descriptor.rs | 78 +++++++++++++++++++ .../wasm-utxo/src/wasm/try_from_js_value.rs | 8 ++ 3 files changed, 101 insertions(+) diff --git a/packages/wasm-utxo/js/index.ts b/packages/wasm-utxo/js/index.ts index c9c1ea1ad22..2db503805b1 100644 --- a/packages/wasm-utxo/js/index.ts +++ b/packages/wasm-utxo/js/index.ts @@ -38,6 +38,16 @@ export type DescriptorPkType = "derivable" | "definite" | "string"; export type ScriptContext = "tap" | "segwitv0" | "legacy"; +export interface ExtParamsConfig { + drop?: boolean; + topUnsafe?: boolean; + resourceLimitations?: boolean; + timelockMixing?: boolean; + malleability?: boolean; + repeatedPk?: boolean; + rawPkh?: boolean; +} + declare module "./wasm/wasm_utxo.js" { interface WrapDescriptor { /** These are not the same types of nodes as in the ast module */ @@ -48,6 +58,11 @@ declare module "./wasm/wasm_utxo.js" { namespace WrapDescriptor { function fromString(descriptor: string, pkType: DescriptorPkType): WrapDescriptor; function fromStringDetectType(descriptor: string): WrapDescriptor; + function fromStringExt( + descriptor: string, + pkType: "definite", + extParams: ExtParamsConfig, + ): WrapDescriptor; } interface WrapMiniscript { diff --git a/packages/wasm-utxo/src/wasm/descriptor.rs b/packages/wasm-utxo/src/wasm/descriptor.rs index ae876e25e18..bdec943287c 100644 --- a/packages/wasm-utxo/src/wasm/descriptor.rs +++ b/packages/wasm-utxo/src/wasm/descriptor.rs @@ -1,4 +1,5 @@ use crate::error::WasmUtxoError; +use crate::wasm::try_from_js_value::get_field; use crate::wasm::try_into_js_value::TryIntoJsValue; use miniscript::bitcoin::secp256k1::{Secp256k1, Signing}; use miniscript::bitcoin::ScriptBuf; @@ -156,6 +157,83 @@ impl WrapDescriptor { } } + fn from_string_definite_ext( + descriptor: &str, + ext_params: &miniscript::miniscript::analyzable::ExtParams, + ) -> Result { + let desc = Descriptor::::from_str_ext(descriptor, ext_params)?; + Ok(WrapDescriptor(WrapDescriptorEnum::Definite(desc))) + } + + /// Parse a descriptor string with custom ExtParams for taproot leaf validation. + /// + /// This allows control over which miniscript analysis checks are applied to + /// taproot leaves. All options default to false (sane behavior). + /// + /// # Arguments + /// * `descriptor` - A string containing the descriptor to parse + /// * `pk_type` - The type of public key ("definite" only for now) + /// * `ext_params_config` - JavaScript object with optional boolean flags: + /// - `drop`: Allow drop operations (r: wrapper) + /// - `topUnsafe`: Allow scripts without signatures on all paths + /// - `resourceLimitations`: Allow scripts exceeding resource limits + /// - `timelockMixing`: Allow CSV + CLTV mixing + /// - `malleability`: Allow malleable scripts + /// - `repeatedPk`: Allow repeated public keys + /// - `rawPkh`: Allow raw pubkey hash fragments + /// + /// # Example + /// ```javascript + /// // Allow r:older() only (for sBTC) + /// Descriptor.fromStringExt(desc, "definite", { drop: true }) + /// + /// // Allow multiple extensions + /// Descriptor.fromStringExt(desc, "definite", { drop: true, malleability: true }) + /// + /// // All sane (default) + /// Descriptor.fromStringExt(desc, "definite", {}) + /// ``` + #[wasm_bindgen(js_name = fromStringExt, skip_typescript)] + pub fn from_string_ext( + descriptor: &str, + pk_type: &str, + ext_params_config: JsValue, + ) -> Result { + let flag = |key| -> Result { + Ok(get_field::>(&ext_params_config, key)?.unwrap_or(false)) + }; + + let mut params = miniscript::miniscript::analyzable::ExtParams::sane(); + if flag("drop")? { + params = params.drop(); + } + if flag("topUnsafe")? { + params = params.top_unsafe(); + } + if flag("resourceLimitations")? { + params = params.exceed_resource_limitations(); + } + if flag("timelockMixing")? { + params = params.timelock_mixing(); + } + if flag("malleability")? { + params = params.malleability(); + } + if flag("repeatedPk")? { + params = params.repeated_pk(); + } + if flag("rawPkh")? { + params = params.raw_pkh(); + } + + match pk_type { + "definite" => WrapDescriptor::from_string_definite_ext(descriptor, ¶ms), + _ => Err(WasmUtxoError::new( + "fromStringExt only supports 'definite' pk_type", + )), + } + } + /// Parse a descriptor string, automatically detecting the appropriate public key type. /// This will check if the descriptor contains wildcards to determine if it should be /// parsed as derivable or definite. diff --git a/packages/wasm-utxo/src/wasm/try_from_js_value.rs b/packages/wasm-utxo/src/wasm/try_from_js_value.rs index 0e26894e503..cb6bb426125 100644 --- a/packages/wasm-utxo/src/wasm/try_from_js_value.rs +++ b/packages/wasm-utxo/src/wasm/try_from_js_value.rs @@ -78,6 +78,14 @@ impl TryFromJsValue for u8 { } } +impl TryFromJsValue for bool { + fn try_from_js_value(value: &JsValue) -> Result { + value + .as_bool() + .ok_or_else(|| WasmUtxoError::new("Expected a boolean")) + } +} + impl TryFromJsValue for u32 { fn try_from_js_value(value: &JsValue) -> Result { value From 01f214da5aae9c0c35992dbf7dc1382c2c1ce361 Mon Sep 17 00:00:00 2001 From: Otto Allmendinger Date: Tue, 28 Apr 2026 17:21:15 +0200 Subject: [PATCH 3/4] feat: add comprehensive sBTC taproot descriptor tests Add complete test suite for sBTC protocol's two-leaf taproot tree with deposit (payload_drop) and reclaim (r:older with multi_a) leaves. Verify structure parsing, P2TR output generation, and address derivation. Tests demonstrate proper use of fromStringExt with `drop: true` to enable r:older() in taproot context. Issue: BTC-3357 Co-authored-by: llm-git --- packages/wasm-utxo/test/sbtc.ts | 158 ++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 packages/wasm-utxo/test/sbtc.ts diff --git a/packages/wasm-utxo/test/sbtc.ts b/packages/wasm-utxo/test/sbtc.ts new file mode 100644 index 00000000000..73339f44130 --- /dev/null +++ b/packages/wasm-utxo/test/sbtc.ts @@ -0,0 +1,158 @@ +import * as assert from "assert"; +import * as crypto from "crypto"; +import { Descriptor, ExtParamsConfig } from "../js/index.js"; +import { getUnspendableKey } from "../js/testutils/descriptor/descriptors.js"; + +// sBTC protocol uses two taproot script leaves: +// 1. Deposit leaf: allows the signers to spend with a protocol payload +// 2. Reclaim leaf: allows the depositors to reclaim after a timelock + +const SIGNERS_KEY = "c9c2312ca406dcb8eed50b829b5292f5fb3e846db0a556af61cc53834ce75421"; + +// BIP341 "nothing up my sleeve" unspendable internal key — used so the taproot address +// can only be spent via script path (no key-path spend). +const UNSPENDABLE_KEY = getUnspendableKey(); + +const DEPOSIT_LEAF = + "c:and_v(payload_drop(" + + "0000000000013880051ad206838b7981a116c334e8cb1b950afb73eb54a5" + + "),pk_k(" + + SIGNERS_KEY + + "))"; + +const RECLAIM_LEAF = + "and_v(r:older(1),multi_a(2," + + "4d838759b2a74616a2298e0580ca815874f5e5a9d2dd1b2f0203b68c66fc6c1e," + + "639779c4b700dc51ece012a0e20325fcafada22a4a122ffaa04d0c0ccae83943," + + "d1d6084eac98303e9d28e082bfd9eadf0b8be033e223a17ad01df81bdaa8c7b2))"; + +// Reference vectors from rust-miniscript test_payload_drop_stacks_vectors. +// Deposit leaf: OP_PUSHBYTES_30 OP_DROP OP_PUSHBYTES_32 OP_CHECKSIG +const DEPOSIT_SCRIPT_HEX = + "1e0000000000013880051ad206838b7981a116c334e8cb1b950afb73eb54a5" + + "7520c9c2312ca406dcb8eed50b829b5292f5fb3e846db0a556af61cc53834ce75421ac"; +const DEPOSIT_LEAF_HASH = "b14bbf1c6699b64429be4f11e1d4df7b75f16f68e7a86cb91c58daf024d0b379"; +// Reclaim leaf: OP_1 OP_CSV OP_DROP + 2-of-3 multi_a +const RECLAIM_SCRIPT_HEX = + "51b275" + + "204d838759b2a74616a2298e0580ca815874f5e5a9d2dd1b2f0203b68c66fc6c1eac" + + "20639779c4b700dc51ece012a0e20325fcafada22a4a122ffaa04d0c0ccae83943ba" + + "20d1d6084eac98303e9d28e082bfd9eadf0b8be033e223a17ad01df81bdaa8c7b2ba529c"; +const RECLAIM_LEAF_HASH = "1e379caf8335dc3bd0af785d32d8135647ffa2ee76dd2c1bcc663ff424602ac0"; +// P2TR output: OP_1 OP_PUSHBYTES_32 +const SCRIPT_PUBKEY_HEX = "5120f3b3930e1e7103753b62e5cfee821b5bfa942eacb868e1d625243df606882dff"; + +// BIP341 tagged hash: SHA256(SHA256(tag) || SHA256(tag) || data) +function taggedHash(tag: string, data: Buffer): Buffer { + const tagHash = crypto.createHash("sha256").update(tag).digest(); + return crypto + .createHash("sha256") + .update(Buffer.concat([tagHash, tagHash, data])) + .digest(); +} + +// BIP341 tap leaf hash: tagged_hash("TapLeaf", version || compact_size(len) || script) +// version 0xc0 = TapScript; compact_size is a single byte for scripts shorter than 253 bytes. +function tapLeafHash(scriptHex: string): string { + const script = Buffer.from(scriptHex, "hex"); + const data = Buffer.concat([Buffer.from([0xc0, script.length]), script]); + return taggedHash("TapLeaf", data).toString("hex"); +} + +function getSbtcDescriptor(depositLeaf: string, reclaimLeaf: string) { + return `tr(${UNSPENDABLE_KEY},{${depositLeaf},${reclaimLeaf}})`; +} + +// Types matching the node() structure for the sBTC taproot descriptor +type DefiniteKey = { Single: string }; + +type SbtcDepositLeaf = { + Check: { + AndV: [{ PayloadDrop: string }, { PkK: DefiniteKey }]; + }; +}; + +type SbtcReclaimLeaf = { + AndV: [{ Drop: { Older: { relLockTime: number } } }, { MultiA: DefiniteKey[] }]; +}; + +type SbtcDescriptorNode = { + Tr: [DefiniteKey, { Tree: [SbtcDepositLeaf, SbtcReclaimLeaf] }]; +}; + +describe("sBTC taproot descriptor", function () { + // Use fromStringExt with { drop: true } to enable r:older() in taproot + const descriptor = Descriptor.fromStringExt( + getSbtcDescriptor(DEPOSIT_LEAF, RECLAIM_LEAF), + "definite", + { drop: true } satisfies ExtParamsConfig, + ); + + it("parses successfully with fromStringExt", () => { + // Key test: Descriptor.fromStringExt({ drop: true }) handles r:older() with targeted drop permission + assert.ok(descriptor, "Descriptor should parse successfully"); + }); + + it("has expected taproot structure", () => { + const node = descriptor.node() as SbtcDescriptorNode; + // Definite descriptors wrap keys in { Single: "..." } + assert.deepStrictEqual( + node.Tr[0], + { Single: UNSPENDABLE_KEY }, + "Should have correct internal key", + ); + assert.ok(node.Tr[1].Tree, "Should have taproot tree structure"); + assert.strictEqual(node.Tr[1].Tree.length, 2, "Should have two leaves"); + }); + + describe("deposit leaf", function () { + it("has correct structure with payload_drop", () => { + const node = descriptor.node() as SbtcDescriptorNode; + const depositLeaf = node.Tr[1].Tree[0]; + + assert.deepStrictEqual(depositLeaf, { + Check: { + AndV: [ + { PayloadDrop: "0000000000013880051ad206838b7981a116c334e8cb1b950afb73eb54a5" }, + { PkK: { Single: "c9c2312ca406dcb8eed50b829b5292f5fb3e846db0a556af61cc53834ce75421" } }, + ], + }, + }); + }); + + it("has correct script hex and tap leaf hash", () => { + assert.strictEqual(tapLeafHash(DEPOSIT_SCRIPT_HEX), DEPOSIT_LEAF_HASH); + }); + }); + + describe("reclaim leaf", function () { + it("has correct structure with r:older (Drop wrapper)", () => { + const node = descriptor.node() as SbtcDescriptorNode; + const reclaimLeaf = node.Tr[1].Tree[1]; + + // Verify the r:older pattern creates a Drop wrapper + assert.ok(reclaimLeaf.AndV, "Should have AndV structure"); + assert.ok(reclaimLeaf.AndV[0].Drop, "Should have Drop wrapper for r:older"); + assert.ok(reclaimLeaf.AndV[0].Drop.Older, "Should contain Older inside Drop"); + assert.strictEqual( + reclaimLeaf.AndV[0].Drop.Older.relLockTime, + 1, + "Should have locktime of 1", + ); + + // Verify the multi_a is the second part + assert.ok(reclaimLeaf.AndV[1].MultiA, "Should have MultiA as second element"); + }); + + it("has correct script hex and tap leaf hash", () => { + assert.strictEqual(tapLeafHash(RECLAIM_SCRIPT_HEX), RECLAIM_LEAF_HASH); + }); + }); + + describe("P2TR output", function () { + it("produces correct script pubkey", () => { + const scriptPubkeyBytes = descriptor.scriptPubkey(); + assert.strictEqual(Buffer.from(scriptPubkeyBytes).toString("hex"), SCRIPT_PUBKEY_HEX); + }); + }); +}); From 5457b17ec45fd25c87ea5a499d9bfcfe8284a2d3 Mon Sep 17 00:00:00 2001 From: Otto Allmendinger Date: Wed, 29 Apr 2026 15:44:33 +0200 Subject: [PATCH 4/4] build(wasm-utxo): update miniscript to bitgo.5 and enforce sane+drop mode Update rust-miniscript dependency from bitgo.3 to bitgo.5. Change all descriptor parsing to use `ExtParams::sane().drop()` by default, allowing r: wrappers while maintaining other safety checks. The `fromStringExt` method now always enables drop mode, with other flags remaining opt-in for taproot leaf validation. Issue: BTC-3357 Co-authored-by: llm-git --- packages/wasm-utxo/Cargo.lock | 2 +- packages/wasm-utxo/Cargo.toml | 2 +- packages/wasm-utxo/src/wasm/descriptor.rs | 44 ++++++++++------------- packages/wasm-utxo/test/sbtc.ts | 5 ++- 4 files changed, 22 insertions(+), 31 deletions(-) diff --git a/packages/wasm-utxo/Cargo.lock b/packages/wasm-utxo/Cargo.lock index e16e3ab3407..e69b5548502 100644 --- a/packages/wasm-utxo/Cargo.lock +++ b/packages/wasm-utxo/Cargo.lock @@ -1675,7 +1675,7 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniscript" version = "13.0.0" -source = "git+https://github.com/BitGo/rust-miniscript?tag=miniscript-13.0.0-bitgo.3#5d30fff5f4af6d76657ca5fd27b2fa14da8e51e2" +source = "git+https://github.com/BitGo/rust-miniscript?tag=miniscript-13.0.0-bitgo.5#d4f80008dc31f6a8512ccce260709808cc34d483" dependencies = [ "bech32", "bitcoin", diff --git a/packages/wasm-utxo/Cargo.toml b/packages/wasm-utxo/Cargo.toml index 7c876ede69e..f5a0b21d4c7 100644 --- a/packages/wasm-utxo/Cargo.toml +++ b/packages/wasm-utxo/Cargo.toml @@ -27,7 +27,7 @@ inspect = ["dep:num-bigint", "dep:serde", "dep:serde_json", "dep:hex"] [dependencies] wasm-bindgen = "0.2" js-sys = "0.3" -miniscript = { git = "https://github.com/BitGo/rust-miniscript", tag = "miniscript-13.0.0-bitgo.3" } +miniscript = { git = "https://github.com/BitGo/rust-miniscript", tag = "miniscript-13.0.0-bitgo.5" } bech32 = "0.11" musig2 = { version = "0.3.1", default-features = false, features = ["k256"] } getrandom = { version = "0.2", features = ["js"] } diff --git a/packages/wasm-utxo/src/wasm/descriptor.rs b/packages/wasm-utxo/src/wasm/descriptor.rs index bdec943287c..7c0eb19bbc8 100644 --- a/packages/wasm-utxo/src/wasm/descriptor.rs +++ b/packages/wasm-utxo/src/wasm/descriptor.rs @@ -4,6 +4,7 @@ use crate::wasm::try_into_js_value::TryIntoJsValue; use miniscript::bitcoin::secp256k1::{Secp256k1, Signing}; use miniscript::bitcoin::ScriptBuf; use miniscript::descriptor::KeyMap; +use miniscript::miniscript::analyzable::ExtParams; use miniscript::{DefiniteDescriptorKey, Descriptor, DescriptorPublicKey}; use std::fmt; use std::str::FromStr; @@ -112,12 +113,16 @@ impl WrapDescriptor { secp: &Secp256k1, descriptor: &str, ) -> Result { - let (desc, keys) = Descriptor::parse_descriptor(secp, descriptor)?; + let (desc, keys) = + Descriptor::parse_descriptor_ext(secp, descriptor, &ExtParams::sane().drop())?; Ok(WrapDescriptor(WrapDescriptorEnum::Derivable(desc, keys))) } fn from_string_definite(descriptor: &str) -> Result { - let desc = Descriptor::::from_str(descriptor)?; + let desc = Descriptor::::from_str_ext( + descriptor, + &ExtParams::sane().drop(), + )?; Ok(WrapDescriptor(WrapDescriptorEnum::Definite(desc))) } @@ -150,31 +155,24 @@ impl WrapDescriptor { "derivable" => WrapDescriptor::from_string_derivable(&Secp256k1::new(), descriptor), "definite" => WrapDescriptor::from_string_definite(descriptor), "string" => { - let desc = Descriptor::::from_str(descriptor)?; + let desc = + Descriptor::::from_str_ext(descriptor, &ExtParams::sane().drop())?; Ok(WrapDescriptor(WrapDescriptorEnum::String(desc))) } _ => Err(WasmUtxoError::new("Invalid descriptor type")), } } - fn from_string_definite_ext( - descriptor: &str, - ext_params: &miniscript::miniscript::analyzable::ExtParams, - ) -> Result { - let desc = Descriptor::::from_str_ext(descriptor, ext_params)?; - Ok(WrapDescriptor(WrapDescriptorEnum::Definite(desc))) - } - /// Parse a descriptor string with custom ExtParams for taproot leaf validation. /// /// This allows control over which miniscript analysis checks are applied to - /// taproot leaves. All options default to false (sane behavior). + /// taproot leaves. The `drop` flag is always enabled; other flags default to false. /// /// # Arguments /// * `descriptor` - A string containing the descriptor to parse /// * `pk_type` - The type of public key ("definite" only for now) /// * `ext_params_config` - JavaScript object with optional boolean flags: - /// - `drop`: Allow drop operations (r: wrapper) + /// - `drop`: Allow drop operations (r: wrapper) — always enabled /// - `topUnsafe`: Allow scripts without signatures on all paths /// - `resourceLimitations`: Allow scripts exceeding resource limits /// - `timelockMixing`: Allow CSV + CLTV mixing @@ -184,14 +182,8 @@ impl WrapDescriptor { /// /// # Example /// ```javascript - /// // Allow r:older() only (for sBTC) - /// Descriptor.fromStringExt(desc, "definite", { drop: true }) - /// - /// // Allow multiple extensions - /// Descriptor.fromStringExt(desc, "definite", { drop: true, malleability: true }) - /// - /// // All sane (default) - /// Descriptor.fromStringExt(desc, "definite", {}) + /// // r:older() is always allowed; add extra flags as needed + /// Descriptor.fromStringExt(desc, "definite", { malleability: true }) /// ``` #[wasm_bindgen(js_name = fromStringExt, skip_typescript)] pub fn from_string_ext( @@ -203,10 +195,7 @@ impl WrapDescriptor { Ok(get_field::>(&ext_params_config, key)?.unwrap_or(false)) }; - let mut params = miniscript::miniscript::analyzable::ExtParams::sane(); - if flag("drop")? { - params = params.drop(); - } + let mut params = ExtParams::sane().drop(); if flag("topUnsafe")? { params = params.top_unsafe(); } @@ -227,7 +216,10 @@ impl WrapDescriptor { } match pk_type { - "definite" => WrapDescriptor::from_string_definite_ext(descriptor, ¶ms), + "definite" => { + let desc = Descriptor::::from_str_ext(descriptor, ¶ms)?; + Ok(WrapDescriptor(WrapDescriptorEnum::Definite(desc))) + } _ => Err(WasmUtxoError::new( "fromStringExt only supports 'definite' pk_type", )), diff --git a/packages/wasm-utxo/test/sbtc.ts b/packages/wasm-utxo/test/sbtc.ts index 73339f44130..c08bf7918c5 100644 --- a/packages/wasm-utxo/test/sbtc.ts +++ b/packages/wasm-utxo/test/sbtc.ts @@ -1,6 +1,6 @@ import * as assert from "assert"; import * as crypto from "crypto"; -import { Descriptor, ExtParamsConfig } from "../js/index.js"; +import { Descriptor } from "../js/index.js"; import { getUnspendableKey } from "../js/testutils/descriptor/descriptors.js"; // sBTC protocol uses two taproot script leaves: @@ -82,10 +82,9 @@ type SbtcDescriptorNode = { describe("sBTC taproot descriptor", function () { // Use fromStringExt with { drop: true } to enable r:older() in taproot - const descriptor = Descriptor.fromStringExt( + const descriptor = Descriptor.fromString( getSbtcDescriptor(DEPOSIT_LEAF, RECLAIM_LEAF), "definite", - { drop: true } satisfies ExtParamsConfig, ); it("parses successfully with fromStringExt", () => {