@bitcoinerlab/miniscript-policies 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,26 +1,154 @@
1
1
  # Miniscript Policies
2
2
 
3
- This package exposes the reference C++ Miniscript policy compiler in JavaScript
4
- via Emscripten. It is a companion to https://github.com/bitcoinerlab/miniscript,
5
- which does the heavy lifting for compilation and satisfactions.
3
+ `@bitcoinerlab/miniscript-policies` exposes the reference C++ Miniscript policy
4
+ compiler from [`sipa/miniscript`](https://github.com/sipa/miniscript) in
5
+ JavaScript via Emscripten.
6
6
 
7
- Use this package when you need to compile policies into Miniscript expressions
8
- for P2WSH.
7
+ It is designed for projects that want to compile human-friendly policies (like
8
+ `or(and(pk(A),older(8640)),pk(B))`) into Miniscript expressions.
9
9
 
10
- ## Usage
10
+ Upstream Miniscript reference docs: https://bitcoin.sipa.be/miniscript/
11
+
12
+ ## What this package provides
13
+
14
+ - `compilePolicy(policy)`: reference policy compiler output (P2WSH-oriented)
15
+ - `compilePolicyTaproot(policy)`: Taproot-focused policy compiler shim
16
+ - `ready`: promise you must await before using compiler functions
17
+
18
+ For Miniscript parsing/analysis/satisfier features, use
19
+ [`@bitcoinerlab/miniscript`](https://github.com/bitcoinerlab/miniscript).
20
+
21
+ ## How Taproot support works
22
+
23
+ `compilePolicyTaproot` is a strict shim built on top of the same reference
24
+ compiler:
25
+
26
+ 1. Compile policy with the reference C++ compiler.
27
+ 2. Rewrite `multi(...)` to `multi_a(...)`.
28
+ 3. Validate the rewritten expression in tapscript context using
29
+ `@bitcoinerlab/miniscript`.
30
+ 4. If reference compilation fails, forward the same reference error string
31
+ (for example `"[compile error]"` or `"[exception: ...]"`) with
32
+ `issane=false`.
33
+ 5. If rewrite/validation fails, return a Taproot-specific error string with
34
+ prefix `"[taproot rewrite error]"` (or `"[taproot rewrite exception]"`)
35
+ and `issane=false`.
36
+
37
+ This gives a practical policy-to-miniscript path for Taproot while preserving
38
+ strict safety checks.
39
+
40
+ ## Installation
41
+
42
+ ```bash
43
+ npm install @bitcoinerlab/miniscript-policies
44
+ ```
45
+
46
+ ## Quick start
11
47
 
12
48
  ```javascript
13
- import { compilePolicy, ready } from '@bitcoinerlab/miniscript-policies';
49
+ import {
50
+ compilePolicy,
51
+ compilePolicyTaproot,
52
+ ready
53
+ } from '@bitcoinerlab/miniscript-policies';
14
54
 
15
55
  await ready;
56
+
16
57
  const policy = 'or(and(pk(A),older(8640)),pk(B))';
17
- const result = compilePolicy(policy);
18
- console.log(result.miniscript);
58
+
59
+ // Reference compiler (includes asm)
60
+ const p2wsh = compilePolicy(policy);
61
+ if (!p2wsh.issane) {
62
+ console.warn('Policy result is not sane for P2WSH:', p2wsh.miniscript);
63
+ } else {
64
+ console.log(p2wsh.miniscript);
65
+ }
66
+
67
+ // Taproot shim (no asm)
68
+ const taproot = compilePolicyTaproot('thresh(2,pk(A),pk(B),pk(C))');
69
+ if (!taproot.issane) {
70
+ console.warn('Policy result is not sane for tapscript:', taproot.miniscript);
71
+ } else {
72
+ console.log(taproot.miniscript); // multi_a(2,A,B,C)
73
+ }
74
+ ```
75
+
76
+ ## API
77
+
78
+ ### `compilePolicy(policy: string)`
79
+
80
+ Returns:
81
+
82
+ ```ts
83
+ {
84
+ miniscript: string;
85
+ asm: string;
86
+ issane: boolean;
87
+ issanesublevel: boolean;
88
+ }
89
+ ```
90
+
91
+ Notes:
92
+
93
+ - This follows the reference compiler behavior from
94
+ [`sipa/miniscript`](https://github.com/sipa/miniscript).
95
+ - `asm`, `issane`, and `issanesublevel` are computed by the bundled C++
96
+ reference implementation and are exposed for informational/compatibility
97
+ purposes.
98
+ - On failure, `miniscript` and `asm` are `"[compile error]"`.
99
+
100
+ ### `compilePolicyTaproot(policy: string)`
101
+
102
+ Returns:
103
+
104
+ ```ts
105
+ {
106
+ miniscript: string;
107
+ issane: boolean;
108
+ }
19
109
  ```
20
110
 
111
+ Notes:
112
+
113
+ - Same result shape style as `compilePolicy`, but without `asm`.
114
+ - Recommended success check is `issane`.
115
+ - On failure, `issane` is `false` and `miniscript` is an error string:
116
+
117
+ ```ts
118
+ {
119
+ miniscript:
120
+ | '[compile error]'
121
+ | `[exception: ...]`
122
+ | `[taproot rewrite error] ...`
123
+ | `[taproot rewrite exception] ...`;
124
+ issane: false;
125
+ }
126
+ ```
127
+
128
+ ### `ready: Promise<void>`
129
+
130
+ Await this once before calling any compiler function.
131
+
132
+ ## Related package
133
+
134
+ If you need Miniscript analysis, parsing, satisfier, or tapscript checks beyond
135
+ policy-to-miniscript compilation, use
136
+ [`@bitcoinerlab/miniscript`](https://github.com/bitcoinerlab/miniscript).
137
+
138
+ For application-level validation in both P2WSH and Taproot contexts, prefer
139
+ using `@bitcoinerlab/miniscript` directly. In this package, the reference
140
+ `asm`/sanity fields are returned as informational outputs.
141
+
142
+ ## Upstream credit
143
+
144
+ This package is built on top of Pieter Wuille's upstream Miniscript work:
145
+
146
+ - https://github.com/sipa/miniscript
147
+ - https://bitcoin.sipa.be/miniscript/
148
+
21
149
  ## Build
22
150
 
23
- This package uses Emscripten. Build with:
151
+ This package uses Emscripten.
24
152
 
25
153
  ```bash
26
154
  make clean && make
package/dist/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ var miniscript = require('@bitcoinerlab/miniscript');
4
+
3
5
  function getDefaultExportFromCjs (x) {
4
6
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
5
7
  }
@@ -52,7 +54,7 @@ var bindings = /*@__PURE__*/getDefaultExportFromCjs(bindingsExports);
52
54
 
53
55
  // Initial author: Pieter Wuille ( https://github.com/sipa/miniscript/blob/master/index.html)
54
56
  // Adapted by Jose-Luis Landabaso - https://bitcoinerlab.com:
55
- // compilePolicy, compileMiniscript with issane, issanesublevel and cleanAsm
57
+ // compilePolicy and compilePolicyTaproot with sanity flags
56
58
 
57
59
 
58
60
  const cleanAsm = asm =>
@@ -63,7 +65,6 @@ const cleanAsm = asm =>
63
65
 
64
66
  let Module;
65
67
  let em_miniscript_compile;
66
- let em_miniscript_analyze;
67
68
  let modulePromise;
68
69
 
69
70
  const initModule = () => {
@@ -79,13 +80,6 @@ const initModule = () => {
79
80
  'number',
80
81
  'number'
81
82
  ]);
82
- em_miniscript_analyze = Module.cwrap('miniscript_analyze', 'none', [
83
- 'string',
84
- 'number',
85
- 'number',
86
- 'number',
87
- 'number'
88
- ]);
89
83
  return Module;
90
84
  });
91
85
  }
@@ -96,7 +90,7 @@ const initModule = () => {
96
90
  const ready = initModule();
97
91
 
98
92
  const ensureReady = () => {
99
- if (!Module || !em_miniscript_compile || !em_miniscript_analyze) {
93
+ if (!Module || !em_miniscript_compile) {
100
94
  throw new Error('Miniscript bindings not ready. Await ready before calling compile functions.');
101
95
  }
102
96
  };
@@ -110,13 +104,11 @@ const ensureReady = () => {
110
104
  */
111
105
 
112
106
  /**
113
- * @typedef {Object} CompileMiniscriptResult
114
- * @property {string} asm - The Bitcoin asm code of the compiled miniscript expression.
107
+ * @typedef {Object} CompilePolicyTaprootResult
108
+ * @property {string} miniscript - Rewritten tapscript miniscript, or an error marker string.
115
109
  * @property {boolean} issane - Whether the miniscript is sane at the top level.
116
- * @property {boolean} issanesublevel - Whether the miniscript is sane at the sublevel.
117
110
  */
118
111
 
119
-
120
112
  /**
121
113
  * Compiles a miniscript policy into a miniscript expression (if possible).
122
114
  * @function
@@ -160,45 +152,69 @@ const compilePolicy = policy => {
160
152
  return result;
161
153
  };
162
154
 
155
+ const isCompileFailure = miniscript =>
156
+ typeof miniscript !== 'string' ||
157
+ miniscript === '[compile error]' ||
158
+ miniscript.startsWith('[exception:');
159
+
160
+ const rewriteForTapscript = miniscript => miniscript.replace(/\bmulti\(/g, 'multi_a(');
161
+ const taprootRewriteError = message => `[taproot rewrite error] ${message}`;
162
+ const taprootRewriteException = message => `[taproot rewrite exception] ${message}`;
163
+
163
164
  /**
164
- * Compiles a miniscript expression and returns its asm code.
165
- * @function
165
+ * Compiles a miniscript policy into a tapscript miniscript expression.
166
+ *
167
+ * Strict mode behavior:
168
+ * 1) compile with the C++ policy compiler
169
+ * 2) rewrite multi() to multi_a()
170
+ * 3) validate rewritten miniscript under tapscript rules
166
171
  *
167
- * @param {string} miniscript - A miniscript expression.
168
- * @returns {CompileMiniscriptResult}
172
+ * @param {string} policy - The miniscript policy to compile.
173
+ * @returns {CompilePolicyTaprootResult}
169
174
  */
170
- const compileMiniscript = miniscript => {
175
+ const compilePolicyTaproot = policy => {
171
176
  ensureReady();
172
- const analysis = Module._malloc(50000);
173
- const asm = Module._malloc(100000);
174
- const issane = Module._malloc(10);
175
- const issanesublevel = Module._malloc(10);
176
- em_miniscript_analyze(
177
- miniscript,
178
- analysis,
179
- 50000,
180
- asm,
181
- 100000,
182
- issane,
183
- 10,
184
- issanesublevel,
185
- 10
186
- );
187
- const result_asm = Module.UTF8ToString(asm);
188
- const result_issane = Module.UTF8ToString(issane);
189
- const result_issanesublebel = Module.UTF8ToString(issanesublevel);
190
- Module._free(analysis);
191
- Module._free(asm);
192
- Module._free(issane);
193
- Module._free(issanesublevel);
194
177
 
195
- return {
196
- asm: cleanAsm(result_asm),
197
- issane: result_issane === 'true' ? true : false,
198
- issanesublevel: result_issanesublebel === 'true' ? true : false
199
- };
178
+ const base = compilePolicy(policy);
179
+
180
+ if (isCompileFailure(base.miniscript)) {
181
+ return {
182
+ miniscript:
183
+ typeof base.miniscript === 'string' ? base.miniscript : '[compile error]',
184
+ issane: false
185
+ };
186
+ }
187
+
188
+ const miniscript$1 = rewriteForTapscript(base.miniscript);
189
+
190
+ try {
191
+ const analysis = miniscript.analyzeMiniscript(miniscript$1, { tapscript: true });
192
+ const isValidAndSane = analysis.valid && analysis.issane && analysis.issanesublevel;
193
+
194
+ if (!isValidAndSane) {
195
+ return {
196
+ miniscript: taprootRewriteError(
197
+ analysis.error ||
198
+ 'multi() to multi_a() rewrite produced miniscript that is not valid/sane in tapscript context.'
199
+ ),
200
+ issane: false
201
+ };
202
+ }
203
+
204
+ return {
205
+ miniscript: miniscript$1,
206
+ issane: analysis.issane
207
+ };
208
+ } catch (error) {
209
+ return {
210
+ miniscript: taprootRewriteException(
211
+ error instanceof Error ? error.message : String(error)
212
+ ),
213
+ issane: false
214
+ };
215
+ }
200
216
  };
201
217
 
202
- exports.compileMiniscript = compileMiniscript;
203
218
  exports.compilePolicy = compilePolicy;
219
+ exports.compilePolicyTaproot = compilePolicyTaproot;
204
220
  exports.ready = ready;
package/package.json CHANGED
@@ -11,10 +11,14 @@
11
11
  "descriptors"
12
12
  ],
13
13
  "homepage": "https://bitcoinerlab.com/modules/miniscript",
14
- "version": "1.0.0",
14
+ "version": "1.1.0",
15
15
  "description": "Bitcoin Miniscript policy compiler",
16
16
  "main": "dist/index.js",
17
17
  "types": "types/index.d.ts",
18
+ "files": [
19
+ "dist",
20
+ "types"
21
+ ],
18
22
  "scripts": {
19
23
  "build": "rollup -c --bundleConfigAsCjs",
20
24
  "build:prod": "NODE_ENV=production rollup -c --bundleConfigAsCjs",
@@ -44,6 +48,7 @@
44
48
  "rollup": "^3.29.5"
45
49
  },
46
50
  "dependencies": {
51
+ "@bitcoinerlab/miniscript": "^2.0.0",
47
52
  "bip68": "^1.0.4"
48
53
  },
49
54
  "bugs": {
package/types/index.d.ts CHANGED
@@ -1,14 +1,17 @@
1
- export declare const compilePolicy: (miniscript: string) => {
1
+ export declare const compilePolicy: (policy: string) => {
2
2
  miniscript: string;
3
3
  asm: string;
4
4
  issane: boolean;
5
5
  issanesublevel: boolean;
6
6
  };
7
7
 
8
- export declare const compileMiniscript: (miniscript: string) => {
9
- asm: string;
8
+ export type CompilePolicyTaprootResult = {
9
+ miniscript: string;
10
10
  issane: boolean;
11
- issanesublevel: boolean;
12
11
  };
13
12
 
13
+ export declare const compilePolicyTaproot: (
14
+ policy: string
15
+ ) => CompilePolicyTaprootResult;
16
+
14
17
  export declare const ready: Promise<void>;
package/Makefile DELETED
@@ -1,14 +0,0 @@
1
- MINISCRIPT_COMMIT ?= 6806dfb15a1fafabf7dd28aae3c9d2bc49db01f1
2
- # Pinned miniscript commit: "Merge sipa/miniscript#133: Hash clarifications"
3
- HEADERS := miniscript/bitcoin/util/vector.h miniscript/bitcoin/util/strencodings.h miniscript/bitcoin/span.h miniscript/bitcoin/util/spanparsing.h miniscript/bitcoin/script/script.h miniscript/bitcoin/script/miniscript.h miniscript/compiler.h miniscript/bitcoin/crypto/common.h miniscript/bitcoin/serialize.h miniscript/bitcoin/prevector.h miniscript/bitcoin/compat/endian.h miniscript/bitcoin/compat/byteswap.h miniscript/bitcoin/attributes.h miniscript/bitcoin/tinyformat.h miniscript/bitcoin/primitives/transaction.h
4
- SOURCES := miniscript/bitcoin/util/strencodings.cpp miniscript/bitcoin/util/spanparsing.cpp miniscript/bitcoin/script/script.cpp miniscript/bitcoin/script/miniscript.cpp miniscript/compiler.cpp
5
- src/bindings.js: miniscript $(HEADERS) $(SOURCES) miniscript/js_bindings.cpp
6
- em++ -O3 -g0 -Wall -std=c++17 -fno-rtti -flto -Iminiscript/bitcoin $(SOURCES) miniscript/js_bindings.cpp -s WASM=0 -s EXPORT_ES6=0 --memory-init-file 0 -s MODULARIZE=1 -s MALLOC=emmalloc -s WASM_ASYNC_COMPILATION=0 -s FILESYSTEM=0 -s ENVIRONMENT=web -s DISABLE_EXCEPTION_CATCHING=0 -s EXPORTED_FUNCTIONS='["_miniscript_compile","_miniscript_analyze","_malloc","_free"]' -s EXPORTED_RUNTIME_METHODS='["cwrap","UTF8ToString"]' -o src/bindings.js
7
- miniscript:
8
- git clone https://github.com/sipa/miniscript
9
- git -C miniscript reset --hard $(MINISCRIPT_COMMIT)
10
- #Patch: https://github.com/sipa/miniscript/pull/132
11
- patch -p0 miniscript/compiler.cpp < patches/uppercase-h.patch
12
- cp js_bindings.cpp miniscript/
13
- clean:
14
- rm -rf miniscript src/bindings.js
package/example.js DELETED
@@ -1,34 +0,0 @@
1
- // To run it: "node ./example.js"
2
-
3
- const { compilePolicy, compileMiniscript, ready } = require("./dist/index.js");
4
-
5
- (async () => {
6
- await ready;
7
-
8
- const policy = "or(and(pk(A),older(8640)),pk(B))";
9
-
10
- const {
11
- miniscript,
12
- asm: asmFromPolicy,
13
- issane: issaneFromPolicy,
14
- } = compilePolicy(policy);
15
-
16
- const { asm: asmFromMiniscript, issane: issaneFromMiniscript } =
17
- compileMiniscript(miniscript);
18
-
19
- console.assert(asmFromPolicy === asmFromMiniscript, "ERROR: Asm mismatch.");
20
- console.assert(
21
- issaneFromPolicy === issaneFromMiniscript,
22
- "ERROR: issane mismatch.",
23
- );
24
-
25
- console.log({
26
- miniscript,
27
- asm: asmFromMiniscript,
28
- issane: issaneFromMiniscript,
29
- });
30
-
31
- console.log(
32
- compileMiniscript("and_v(v:pk(key),or_b(l:after(100),al:after(200)))"),
33
- );
34
- })();
package/js_bindings.cpp DELETED
@@ -1,154 +0,0 @@
1
- // Initial author: Pieter Wuille
2
- // Adapted by Jose-Luis Landabaso so that miniscript_compile and miniscript_analyze
3
- // return issane & issanesublevel
4
- #include <string>
5
-
6
- #include <script/miniscript.h>
7
-
8
- #include "compiler.h"
9
-
10
- namespace {
11
-
12
- using miniscript::operator"" _mst;
13
-
14
- void Output(const std::string& str, char* out, int outlen) {
15
- int maxlen = std::min<int>(outlen - 1, str.size());
16
- memcpy(out, str.c_str(), maxlen);
17
- out[maxlen] = 0;
18
- }
19
-
20
- std::string Props(const miniscript::NodeRef<std::string>& node, std::string in) {
21
- std::string ret = "<span title=\"type: ";
22
- if (node->GetType() == ""_mst) {
23
- ret += "[invalid]";
24
- } else {
25
- if (node->GetType() << "B"_mst) ret += 'B';
26
- if (node->GetType() << "V"_mst) ret += 'V';
27
- if (node->GetType() << "W"_mst) ret += 'W';
28
- if (node->GetType() << "K"_mst) ret += 'K';
29
- if (node->GetType() << "z"_mst) ret += 'z';
30
- if (node->GetType() << "o"_mst) ret += 'o';
31
- if (node->GetType() << "n"_mst) ret += 'n';
32
- if (node->GetType() << "d"_mst) ret += 'd';
33
- if (node->GetType() << "f"_mst) ret += 'f';
34
- if (node->GetType() << "e"_mst) ret += 'e';
35
- if (node->GetType() << "m"_mst) ret += 'm';
36
- if (node->GetType() << "u"_mst) ret += 'u';
37
- if (node->GetType() << "s"_mst) ret += 's';
38
- if (node->GetType() << "k"_mst) ret += 'k';
39
- }
40
- ret += "&#13;scriptlen: " + std::to_string(node->ScriptSize());
41
- ret += "&#13;max ops: " + std::to_string(node->GetOps());
42
- ret += "&#13;max stack size: " + std::to_string(node->GetStackSize());
43
- return std::move(ret) + "\">" + std::move(in) + "</span>";
44
- }
45
-
46
- std::string Analyze(const miniscript::NodeRef<std::string>& node) {
47
- switch (node->fragment) {
48
- case miniscript::Fragment::PK_K: {
49
- return Props(node, "pk_k(" + (*COMPILER_CTX.ToString(node->keys[0])) + ")");
50
- }
51
- case miniscript::Fragment::PK_H: {
52
- return Props(node, "pk_h(" + (*COMPILER_CTX.ToString(node->keys[0])) + ")");
53
- }
54
- case miniscript::Fragment::MULTI: return Props(node, "multi(" + std::to_string(node->k) + " of " + std::to_string(node->keys.size()) + ")");
55
- case miniscript::Fragment::AFTER: return Props(node, "after(" + std::to_string(node->k) + ")");
56
- case miniscript::Fragment::OLDER: return Props(node, "older(" + std::to_string(node->k) + ")");
57
- case miniscript::Fragment::SHA256: return Props(node, "sha256()");
58
- case miniscript::Fragment::RIPEMD160: return Props(node, "ripemd160()");
59
- case miniscript::Fragment::HASH256: return Props(node, "hash256()");
60
- case miniscript::Fragment::HASH160: return Props(node, "hash160()");
61
- case miniscript::Fragment::JUST_0: return Props(node, "false");
62
- case miniscript::Fragment::JUST_1: return Props(node, "true");
63
- case miniscript::Fragment::WRAP_A: return Props(node, "a:") + " " + Analyze(node->subs[0]);
64
- case miniscript::Fragment::WRAP_S: return Props(node, "s:") + " " + Analyze(node->subs[0]);
65
- case miniscript::Fragment::WRAP_C: return Props(node, "c:") + " " + Analyze(node->subs[0]);
66
- case miniscript::Fragment::WRAP_D: return Props(node, "d:") + " " + Analyze(node->subs[0]);
67
- case miniscript::Fragment::WRAP_V: return Props(node, "v:") + " " + Analyze(node->subs[0]);
68
- case miniscript::Fragment::WRAP_N: return Props(node, "n:") + " " + Analyze(node->subs[0]);
69
- case miniscript::Fragment::WRAP_J: return Props(node, "j:") + " " + Analyze(node->subs[0]);
70
- case miniscript::Fragment::AND_V: return Props(node, "and_v") + "<ul style=\"list-style-type: disc;\"><li>" + Analyze(node->subs[0]) + "</li><li>" + Analyze(node->subs[1]) + "</li></ul>";
71
- case miniscript::Fragment::AND_B: return Props(node, "and_b") + "<ul style=\"list-style-type: disc;\"><li>" + Analyze(node->subs[0]) + "</li><li>" + Analyze(node->subs[1]) + "</li></ul>";
72
- case miniscript::Fragment::OR_B: return Props(node, "or_b") + "<ul style=\"list-style-type: disc;\"><li>" + Analyze(node->subs[0]) + "</li><li>" + Analyze(node->subs[1]) + "</li></ul>";
73
- case miniscript::Fragment::OR_C: return Props(node, "or_c") + "<ul style=\"list-style-type: disc;\"><li>" + Analyze(node->subs[0]) + "</li><li>" + Analyze(node->subs[1]) + "</li></ul>";
74
- case miniscript::Fragment::OR_D: return Props(node, "or_d") + "<ul style=\"list-style-type: disc;\"><li>" + Analyze(node->subs[0]) + "</li><li>" + Analyze(node->subs[1]) + "</li></ul>";
75
- case miniscript::Fragment::OR_I: return Props(node, "or_i") + "<ul style=\"list-style-type: disc;\"><li>" + Analyze(node->subs[0]) + "</li><li>" + Analyze(node->subs[1]) + "</li></ul>";
76
- case miniscript::Fragment::ANDOR: return Props(node, "andor [or]") + "<ul style=\"list-style-type: disc;\"><li>andor [and]<ul style=\"list-style-type: disc;\"><li>" + Analyze(node->subs[0]) + "</li><li>" + Analyze(node->subs[1]) + "</li></ul></li><li>" + Analyze(node->subs[2]) + "</li></ul>";
77
- case miniscript::Fragment::THRESH: {
78
- auto ret = Props(node, "thresh(" + std::to_string(node->k) + " of " + std::to_string(node->subs.size()) + ")") + "<ul style=\"list-style-type: disc;\">";
79
- for (const auto& sub : node->subs) {
80
- ret += "<li>" + Analyze(sub) + "</li>";
81
- }
82
- return std::move(ret) + "</ul>";
83
- }
84
- }
85
- }
86
-
87
- }
88
-
89
- extern "C" {
90
-
91
- void miniscript_compile(const char* desc, char* msout, int msoutlen, char* costout, int costoutlen, char* asmout, int asmoutlen, char* issane, int issanelen, char* issanesublevel, int issanesublevellen) {
92
- try {
93
- std::string str(desc);
94
- str.erase(str.find_last_not_of(" \n\r\t") + 1);
95
- miniscript::NodeRef<std::string> ret;
96
- double avgcost;
97
- if (!Compile(Expand(str), ret, avgcost)) {
98
- Output("[compile error]", msout, msoutlen);
99
- Output("[compile error]", costout, costoutlen);
100
- Output("[compile error]", asmout, asmoutlen);
101
- return;
102
- }
103
- Output(Abbreviate(*(ret->ToString(COMPILER_CTX))), msout, msoutlen);
104
- std::string coststr = "<ul><li>Script: " + std::to_string(ret->ScriptSize()) + " WU</li><li>Input: " + std::to_string(avgcost) + " WU</li><li>Total: " + std::to_string(ret->ScriptSize() + avgcost) + " WU</li></ul>";
105
- Output(coststr, costout, costoutlen);
106
- Output(Disassemble(ret->ToScript(COMPILER_CTX)), asmout, asmoutlen);
107
- if (ret->IsSane()) {
108
- Output("true", issanesublevel, issanesublevellen);
109
- } else {
110
- Output("false", issanesublevel, issanesublevellen);
111
- }
112
- if (ret->IsValidTopLevel()) {
113
- Output("true", issane, issanelen);
114
- } else {
115
- Output("false", issane, issanelen);
116
- }
117
- } catch (const std::exception& e) {
118
- Output("[exception: " + std::string(e.what()) + "]", msout, msoutlen);
119
- Output("", costout, costoutlen);
120
- Output("", asmout, asmoutlen);
121
- }
122
- }
123
-
124
- void miniscript_analyze(const char* ms, char* costout, int costoutlen, char* asmout, int asmoutlen, char* issane, int issanelen, char* issanesublevel, int issanesublevellen) {
125
- try {
126
- std::string str(ms);
127
- str.erase(str.find_last_not_of(" \n\r\t") + 1);
128
- miniscript::NodeRef<std::string> ret;
129
- ret = miniscript::FromString(Expand(str), COMPILER_CTX);
130
- if (!ret || !ret->IsValidTopLevel()) {
131
- Output("[analysis error]", costout, costoutlen);
132
- Output("[analysis error]", asmout, asmoutlen);
133
- return;
134
- }
135
- std::string coststr = "Size: " + std::to_string(ret->ScriptSize()) + " bytes script<ul><li>" + Analyze(ret) + "</li></ul>";
136
- Output(coststr, costout, costoutlen);
137
- Output(Disassemble(ret->ToScript(COMPILER_CTX)), asmout, asmoutlen);
138
- if (ret->IsSane()) {
139
- Output("true", issanesublevel, issanesublevellen);
140
- } else {
141
- Output("false", issanesublevel, issanesublevellen);
142
- }
143
- if (ret->IsValidTopLevel()) {
144
- Output("true", issane, issanelen);
145
- } else {
146
- Output("false", issane, issanelen);
147
- }
148
- } catch (const std::exception& e) {
149
- Output("[exception: " + std::string(e.what()) + "]", costout, costoutlen);
150
- Output("", asmout, asmoutlen);
151
- }
152
- }
153
-
154
- }
@@ -1,11 +0,0 @@
1
- --- compiler.cpp.bak 2026-01-30 13:12:43
2
- +++ compiler.cpp 2026-01-30 13:12:54
3
- @@ -848,7 +848,7 @@
4
- }
5
- if (data.size() == 20) {
6
- if (data == std::vector<unsigned char>(20, 0x99)) {
7
- - ret += "<h>";
8
- + ret += "<H>";
9
- } else if (data[0] == 'P' && data[1] == 'K' && data[2] == 'h') {
10
- while (data.size() && data.back() == 0) data.pop_back();
11
- ret += "<HASH160(" + std::string((const char*)data.data() + 3, data.size() - 3) + ")>";
package/rollup.config.js DELETED
@@ -1,13 +0,0 @@
1
-
2
- import commonjs from "@rollup/plugin-commonjs";
3
-
4
- export default {
5
- input: "./src/index.js",
6
- output: {
7
- file: "./dist/index.js",
8
- format: "cjs",
9
- },
10
- plugins: [commonjs()],
11
- // Tell Rollup not to bundle dependencies listed in package.json
12
- external: [...Object.keys(require("./package.json").dependencies || {})],
13
- };
package/src/index.js DELETED
@@ -1,5 +0,0 @@
1
- // Distributed under the MIT software license
2
-
3
- import { compilePolicy, compileMiniscript, ready } from './miniscript.js';
4
-
5
- export { compilePolicy, compileMiniscript, ready };