Skip to content

Commit 9b792a7

Browse files
refactor: use static methods for miniscript and descriptor
Issue: BTC-1338
1 parent d7a0d08 commit 9b792a7

File tree

7 files changed

+93
-132
lines changed

7 files changed

+93
-132
lines changed

packages/wasm-miniscript-ui/src/index.ts

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,11 @@
1-
import {
2-
descriptorFromString,
3-
miniscriptFromBitcoinScript,
4-
miniscriptFromString,
5-
ScriptContext,
6-
} from "@bitgo/wasm-miniscript";
7-
81
import * as utxolib from "@bitgo/utxo-lib";
2+
import { Descriptor, Miniscript, ScriptContext } from "@bitgo/wasm-miniscript";
93

104
import "./style.css";
115

126
import { getElement } from "./html";
137
import { buildOptions, getOptions, Options } from "./options";
148
import { getHtmlForAst } from "./htmlAST";
15-
import { Descriptor, Miniscript } from "@bitgo/wasm-miniscript";
169
import { fromHex, toHex } from "./hex";
1710
import { getShare, setShare, Share } from "./sharing";
1811

@@ -22,7 +15,7 @@ function createMiniscriptFromBitcoinScriptDetectScriptContext(
2215
const formats = ["tap", "segwitv0", "legacy"] as const;
2316
for (const format of formats) {
2417
try {
25-
return [miniscriptFromBitcoinScript(script, format), format];
18+
return [Miniscript.fromBitcoinScript(script, format), format];
2619
} catch (e) {
2720
// ignore
2821
}
@@ -168,7 +161,7 @@ function applyUpdate(changedEl: HTMLElement, options: Options) {
168161
changedEl === elEditDescriptor ||
169162
changedEl === getElement("input-derivation-index", HTMLInputElement)
170163
) {
171-
const descriptor = descriptorFromString(elEditDescriptor.value, "derivable");
164+
const descriptor = Descriptor.fromString(elEditDescriptor.value, "derivable");
172165
setHtmlContent(elDescriptorAst, getHtmlForAst(descriptor.node()));
173166
const descriptorAtIndex = descriptor.atDerivationIndex(options.derivationIndex);
174167
return applyUpdateWith(
@@ -189,7 +182,7 @@ function applyUpdate(changedEl: HTMLElement, options: Options) {
189182
changedEl === getElement("input-script-context", HTMLSelectElement)
190183
) {
191184
try {
192-
const script = miniscriptFromString(elEditMiniscript.value, options.scriptContext);
185+
const script = Miniscript.fromString(elEditMiniscript.value, options.scriptContext);
193186
return applyUpdateWith(
194187
changedEl,
195188
{ descriptor: null, miniscript: script, scriptBytes: undefined, scriptAsm: undefined },

packages/wasm-miniscript-ui/src/sharing.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
import * as t from "io-ts";
2-
import {
3-
Descriptor,
4-
descriptorFromString,
5-
Miniscript,
6-
miniscriptFromString,
7-
} from "@bitgo/wasm-miniscript";
2+
import { Descriptor, Miniscript } from "@bitgo/wasm-miniscript";
83
import { fromHex, toHex } from "./hex";
94
import { ScriptContext } from "./codec";
105

@@ -67,11 +62,11 @@ export function getShare(
6762
}
6863

6964
if ("d" in v) {
70-
return { descriptor: descriptorFromString(v.d, "derivable") };
65+
return { descriptor: Descriptor.fromString(v.d, "derivable") };
7166
}
7267
if ("ms" in v && "sc" in v) {
7368
return {
74-
miniscript: miniscriptFromString(v.ms, v.sc),
69+
miniscript: Miniscript.fromString(v.ms, v.sc),
7570
scriptContext: v.sc,
7671
};
7772
}

packages/wasm-miniscript/js/index.ts

Lines changed: 17 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4,50 +4,28 @@ import * as wasm from "./wasm/wasm_miniscript";
44
// and forgets to include it in the bundle
55
void wasm;
66

7-
export type MiniscriptNode = unknown;
8-
9-
export type Miniscript = {
10-
node(): MiniscriptNode;
11-
toString(): string;
12-
encode(): Uint8Array;
13-
toAsmString(): string;
14-
};
15-
16-
export function isMiniscript(obj: unknown): obj is Miniscript {
17-
return obj instanceof wasm.WrapMiniscript;
18-
}
7+
export type DescriptorPkType = "derivable" | "definite" | "string";
198

209
export type ScriptContext = "tap" | "segwitv0" | "legacy";
2110

22-
export function miniscriptFromString(script: string, scriptContext: ScriptContext): Miniscript {
23-
return wasm.miniscript_from_string(script, scriptContext);
24-
}
25-
26-
export function miniscriptFromBitcoinScript(
27-
script: Uint8Array,
28-
scriptContext: ScriptContext,
29-
): Miniscript {
30-
return wasm.miniscript_from_bitcoin_script(script, scriptContext);
31-
}
11+
declare module "./wasm/wasm_miniscript" {
12+
interface WrapDescriptor {
13+
node(): unknown;
14+
}
3215

33-
export type DescriptorNode = unknown;
16+
namespace WrapDescriptor {
17+
function fromString(descriptor: string, pkType: DescriptorPkType): WrapDescriptor;
18+
}
3419

35-
export type Descriptor = {
36-
node(): DescriptorNode;
37-
toString(): string;
38-
hasWildcard(): boolean;
39-
atDerivationIndex(index: number): Descriptor;
40-
encode(): Uint8Array;
41-
toAsmString(): string;
42-
scriptPubkey(): Uint8Array;
43-
};
20+
interface WrapMiniscript {
21+
node(): unknown;
22+
}
4423

45-
export function isDescriptor(obj: unknown): obj is Descriptor {
46-
return obj instanceof wasm.WrapDescriptor;
24+
namespace WrapMiniscript {
25+
function fromString(miniscript: string, ctx: ScriptContext): WrapMiniscript;
26+
function fromBitcoinScript(script: Uint8Array, ctx: ScriptContext): WrapMiniscript;
27+
}
4728
}
4829

49-
type DescriptorPkType = "derivable" | "definite" | "string";
50-
51-
export function descriptorFromString(descriptor: string, pkType: DescriptorPkType): Descriptor {
52-
return wasm.descriptor_from_string(descriptor, pkType);
53-
}
30+
export { WrapDescriptor as Descriptor } from "./wasm/wasm_miniscript";
31+
export { WrapMiniscript as Miniscript } from "./wasm/wasm_miniscript";

packages/wasm-miniscript/src/descriptor.rs

Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
use std::str::FromStr;
2-
use miniscript::{DefiniteDescriptorKey, Descriptor, DescriptorPublicKey};
3-
use miniscript::bitcoin::ScriptBuf;
1+
use crate::try_into_js_value::TryIntoJsValue;
42
use miniscript::bitcoin::secp256k1::Secp256k1;
3+
use miniscript::bitcoin::ScriptBuf;
54
use miniscript::descriptor::KeyMap;
5+
use miniscript::{DefiniteDescriptorKey, Descriptor, DescriptorPublicKey};
6+
use std::str::FromStr;
67
use wasm_bindgen::prelude::wasm_bindgen;
78
use wasm_bindgen::{JsError, JsValue};
8-
use crate::try_into_js_value::TryIntoJsValue;
99

1010
enum WrapDescriptorEnum {
1111
Derivable(Descriptor<DescriptorPublicKey>, KeyMap),
@@ -58,18 +58,14 @@ impl WrapDescriptor {
5858
#[wasm_bindgen(js_name = scriptPubkey)]
5959
pub fn script_pubkey(&self) -> Result<Vec<u8>, JsError> {
6060
match &self.0 {
61-
WrapDescriptorEnum::Definite(desc) => {
62-
Ok(desc.script_pubkey().to_bytes())
63-
}
61+
WrapDescriptorEnum::Definite(desc) => Ok(desc.script_pubkey().to_bytes()),
6462
_ => Err(JsError::new("Cannot derive from a non-definite descriptor")),
6563
}
6664
}
6765

6866
fn explicit_script(&self) -> Result<ScriptBuf, JsError> {
6967
match &self.0 {
70-
WrapDescriptorEnum::Definite(desc) => {
71-
Ok(desc.explicit_script()?)
72-
}
68+
WrapDescriptorEnum::Definite(desc) => Ok(desc.explicit_script()?),
7369
WrapDescriptorEnum::Derivable(_, _) => {
7470
Err(JsError::new("Cannot encode a derivable descriptor"))
7571
}
@@ -85,24 +81,24 @@ impl WrapDescriptor {
8581
pub fn to_asm_string(&self) -> Result<String, JsError> {
8682
Ok(self.explicit_script()?.to_asm_string())
8783
}
88-
}
8984

90-
#[wasm_bindgen]
91-
pub fn descriptor_from_string(descriptor: &str, pk_type: &str) -> Result<WrapDescriptor, JsError> {
92-
match pk_type {
93-
"derivable" => {
94-
let secp = Secp256k1::new();
95-
let (desc, keys) = Descriptor::parse_descriptor(&secp, descriptor)?;
96-
Ok(WrapDescriptor(WrapDescriptorEnum::Derivable(desc, keys)))
97-
}
98-
"definite" => {
99-
let desc = Descriptor::<DefiniteDescriptorKey>::from_str(descriptor)?;
100-
Ok(WrapDescriptor(WrapDescriptorEnum::Definite(desc)))
101-
}
102-
"string" => {
103-
let desc = Descriptor::<String>::from_str(descriptor)?;
104-
Ok(WrapDescriptor(WrapDescriptorEnum::String(desc)))
85+
#[wasm_bindgen(js_name = fromString, skip_typescript)]
86+
pub fn from_string(descriptor: &str, pk_type: &str) -> Result<WrapDescriptor, JsError> {
87+
match pk_type {
88+
"derivable" => {
89+
let secp = Secp256k1::new();
90+
let (desc, keys) = Descriptor::parse_descriptor(&secp, descriptor)?;
91+
Ok(WrapDescriptor(WrapDescriptorEnum::Derivable(desc, keys)))
92+
}
93+
"definite" => {
94+
let desc = Descriptor::<DefiniteDescriptorKey>::from_str(descriptor)?;
95+
Ok(WrapDescriptor(WrapDescriptorEnum::Definite(desc)))
96+
}
97+
"string" => {
98+
let desc = Descriptor::<String>::from_str(descriptor)?;
99+
Ok(WrapDescriptor(WrapDescriptorEnum::String(desc)))
100+
}
101+
_ => Err(JsError::new("Invalid descriptor type")),
105102
}
106-
_ => Err(JsError::new("Invalid descriptor type")),
107103
}
108-
}
104+
}

packages/wasm-miniscript/src/lib.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,5 @@ mod miniscript;
55
mod error;
66
mod descriptor;
77

8-
pub use miniscript::miniscript_from_string;
9-
pub use miniscript::miniscript_from_bitcoin_script;
10-
pub use descriptor::descriptor_from_string;
8+
pub use miniscript::WrapMiniscript;
9+
pub use descriptor::WrapDescriptor;

packages/wasm-miniscript/src/miniscript.rs

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,42 @@ impl WrapMiniscript {
4848
pub fn to_asm_string(&self) -> Result<String, JsError> {
4949
unwrap_apply!(&self.0, |ms| Ok(ms.encode().to_asm_string()))
5050
}
51+
52+
#[wasm_bindgen(js_name = fromString, skip_typescript)]
53+
pub fn from_string(script: &str, context_type: &str) -> Result<WrapMiniscript, JsError> {
54+
match context_type {
55+
"tap" => Ok(WrapMiniscript::from(
56+
Miniscript::<XOnlyPublicKey, Tap>::from_str(script).map_err(JsError::from)?,
57+
)),
58+
"segwitv0" => Ok(WrapMiniscript::from(
59+
Miniscript::<PublicKey, Segwitv0>::from_str(script).map_err(JsError::from)?,
60+
)),
61+
"legacy" => Ok(WrapMiniscript::from(
62+
Miniscript::<PublicKey, Legacy>::from_str(script).map_err(JsError::from)?,
63+
)),
64+
_ => Err(JsError::new("Invalid context type")),
65+
}
66+
}
67+
68+
#[wasm_bindgen(js_name = fromBitcoinScript, skip_typescript)]
69+
pub fn from_bitcoin_script(
70+
script: &[u8],
71+
context_type: &str,
72+
) -> Result<WrapMiniscript, JsError> {
73+
let script = bitcoin::Script::from_bytes(script);
74+
match context_type {
75+
"tap" => Ok(WrapMiniscript::from(
76+
Miniscript::<XOnlyPublicKey, Tap>::parse(script).map_err(JsError::from)?,
77+
)),
78+
"segwitv0" => Ok(WrapMiniscript::from(
79+
Miniscript::<PublicKey, Segwitv0>::parse(script).map_err(JsError::from)?,
80+
)),
81+
"legacy" => Ok(WrapMiniscript::from(
82+
Miniscript::<PublicKey, Legacy>::parse(script).map_err(JsError::from)?,
83+
)),
84+
_ => Err(JsError::new("Invalid context type")),
85+
}
86+
}
5187
}
5288

5389
impl From<Miniscript<XOnlyPublicKey, Tap>> for WrapMiniscript {
@@ -68,42 +104,6 @@ impl From<Miniscript<PublicKey, Legacy>> for WrapMiniscript {
68104
}
69105
}
70106

71-
#[wasm_bindgen]
72-
pub fn miniscript_from_string(script: &str, context_type: &str) -> Result<WrapMiniscript, JsError> {
73-
match context_type {
74-
"tap" => Ok(WrapMiniscript::from(
75-
Miniscript::<XOnlyPublicKey, Tap>::from_str(script).map_err(JsError::from)?,
76-
)),
77-
"segwitv0" => Ok(WrapMiniscript::from(
78-
Miniscript::<PublicKey, Segwitv0>::from_str(script).map_err(JsError::from)?,
79-
)),
80-
"legacy" => Ok(WrapMiniscript::from(
81-
Miniscript::<PublicKey, Legacy>::from_str(script).map_err(JsError::from)?,
82-
)),
83-
_ => Err(JsError::new("Invalid context type")),
84-
}
85-
}
86-
87-
#[wasm_bindgen]
88-
pub fn miniscript_from_bitcoin_script(
89-
script: &[u8],
90-
context_type: &str,
91-
) -> Result<WrapMiniscript, JsError> {
92-
let script = bitcoin::Script::from_bytes(script);
93-
match context_type {
94-
"tap" => Ok(WrapMiniscript::from(
95-
Miniscript::<XOnlyPublicKey, Tap>::parse(script).map_err(JsError::from)?,
96-
)),
97-
"segwitv0" => Ok(WrapMiniscript::from(
98-
Miniscript::<PublicKey, Segwitv0>::parse(script).map_err(JsError::from)?,
99-
)),
100-
"legacy" => Ok(WrapMiniscript::from(
101-
Miniscript::<PublicKey, Legacy>::parse(script).map_err(JsError::from)?,
102-
)),
103-
_ => Err(JsError::new("Invalid context type")),
104-
}
105-
}
106-
107107
#[test]
108108
pub fn panic_xprv() {
109109
use miniscript::bitcoin::secp256k1::Secp256k1;

packages/wasm-miniscript/test/test.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import * as assert from "assert";
2-
import { descriptorFromString, miniscriptFromString, miniscriptFromBitcoinScript } from "../js";
2+
import { Miniscript, Descriptor } from "../js";
33
import { fixtures } from "./descriptorFixtures";
44

55
describe("AST", function () {
66
it("should get ast", function () {
77
const pubkey = Buffer.alloc(32, 1).toString("hex");
8-
const result = miniscriptFromString(`multi_a(1,${pubkey})`, "tap");
8+
const result = Miniscript.fromString(`multi_a(1,${pubkey})`, "tap");
99
console.dir(result.node(), { depth: null });
1010
console.dir(result.encode(), { depth: null });
11-
console.dir(miniscriptFromBitcoinScript(result.encode(), "tap").toString());
11+
console.dir(Miniscript.fromBitcoinScript(result.encode(), "tap").toString());
1212
});
1313
});
1414

@@ -20,7 +20,7 @@ function removeChecksum(descriptor: string): string {
2020
describe("Descriptor fixtures", function () {
2121
fixtures.valid.forEach((fixture, i) => {
2222
it("should parse fixture " + i, function () {
23-
const descriptor = descriptorFromString(fixture.descriptor, "string");
23+
const descriptor = Descriptor.fromString(fixture.descriptor, "string");
2424
assert.doesNotThrow(() => descriptor.node());
2525
let descriptorString = descriptor.toString();
2626
if (fixture.checksumRequired === false) {
@@ -34,7 +34,7 @@ describe("Descriptor fixtures", function () {
3434
assert.strictEqual(descriptorString, expected);
3535

3636
assert.doesNotThrow(() =>
37-
descriptorFromString(fixture.descriptor, "derivable").atDerivationIndex(0),
37+
Descriptor.fromString(fixture.descriptor, "derivable").atDerivationIndex(0),
3838
);
3939

4040
const nonDerivable = [33, 34, 35, 41, 42, 43];
@@ -43,14 +43,14 @@ describe("Descriptor fixtures", function () {
4343
console.log("Skipping encoding test for fixture", fixture.descriptor, i);
4444
} else {
4545
assert.doesNotThrow(() =>
46-
descriptorFromString(fixture.descriptor, "derivable").atDerivationIndex(0).encode(),
46+
Descriptor.fromString(fixture.descriptor, "derivable").atDerivationIndex(0).encode(),
4747
);
4848

4949
let descriptorString = fixture.descriptor;
5050
if (fixture.checksumRequired === false) {
5151
descriptorString = removeChecksum(descriptorString);
5252
}
53-
const descriptor = descriptorFromString(descriptorString, "derivable");
53+
const descriptor = Descriptor.fromString(descriptorString, "derivable");
5454
assert.strictEqual(
5555
Buffer.from(descriptor.atDerivationIndex(fixture.index ?? 0).scriptPubkey()).toString(
5656
"hex",

0 commit comments

Comments
 (0)