@arkade-os/sdk 0.0.16

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.
Files changed (103) hide show
  1. package/README.md +312 -0
  2. package/dist/cjs/arknote/index.js +86 -0
  3. package/dist/cjs/forfeit.js +38 -0
  4. package/dist/cjs/identity/inMemoryKey.js +40 -0
  5. package/dist/cjs/identity/index.js +2 -0
  6. package/dist/cjs/index.js +48 -0
  7. package/dist/cjs/musig2/index.js +10 -0
  8. package/dist/cjs/musig2/keys.js +57 -0
  9. package/dist/cjs/musig2/nonces.js +44 -0
  10. package/dist/cjs/musig2/sign.js +102 -0
  11. package/dist/cjs/networks.js +26 -0
  12. package/dist/cjs/package.json +3 -0
  13. package/dist/cjs/providers/ark.js +530 -0
  14. package/dist/cjs/providers/onchain.js +61 -0
  15. package/dist/cjs/script/address.js +45 -0
  16. package/dist/cjs/script/base.js +51 -0
  17. package/dist/cjs/script/default.js +40 -0
  18. package/dist/cjs/script/tapscript.js +528 -0
  19. package/dist/cjs/script/vhtlc.js +84 -0
  20. package/dist/cjs/tree/signingSession.js +238 -0
  21. package/dist/cjs/tree/validation.js +184 -0
  22. package/dist/cjs/tree/vtxoTree.js +197 -0
  23. package/dist/cjs/utils/bip21.js +114 -0
  24. package/dist/cjs/utils/coinselect.js +73 -0
  25. package/dist/cjs/utils/psbt.js +124 -0
  26. package/dist/cjs/utils/transactionHistory.js +148 -0
  27. package/dist/cjs/utils/txSizeEstimator.js +95 -0
  28. package/dist/cjs/wallet/index.js +8 -0
  29. package/dist/cjs/wallet/serviceWorker/db/vtxo/idb.js +153 -0
  30. package/dist/cjs/wallet/serviceWorker/db/vtxo/index.js +2 -0
  31. package/dist/cjs/wallet/serviceWorker/request.js +75 -0
  32. package/dist/cjs/wallet/serviceWorker/response.js +187 -0
  33. package/dist/cjs/wallet/serviceWorker/wallet.js +332 -0
  34. package/dist/cjs/wallet/serviceWorker/worker.js +452 -0
  35. package/dist/cjs/wallet/wallet.js +720 -0
  36. package/dist/esm/arknote/index.js +81 -0
  37. package/dist/esm/forfeit.js +35 -0
  38. package/dist/esm/identity/inMemoryKey.js +36 -0
  39. package/dist/esm/identity/index.js +1 -0
  40. package/dist/esm/index.js +39 -0
  41. package/dist/esm/musig2/index.js +3 -0
  42. package/dist/esm/musig2/keys.js +21 -0
  43. package/dist/esm/musig2/nonces.js +8 -0
  44. package/dist/esm/musig2/sign.js +63 -0
  45. package/dist/esm/networks.js +22 -0
  46. package/dist/esm/package.json +3 -0
  47. package/dist/esm/providers/ark.js +526 -0
  48. package/dist/esm/providers/onchain.js +57 -0
  49. package/dist/esm/script/address.js +41 -0
  50. package/dist/esm/script/base.js +46 -0
  51. package/dist/esm/script/default.js +37 -0
  52. package/dist/esm/script/tapscript.js +491 -0
  53. package/dist/esm/script/vhtlc.js +81 -0
  54. package/dist/esm/tree/signingSession.js +200 -0
  55. package/dist/esm/tree/validation.js +179 -0
  56. package/dist/esm/tree/vtxoTree.js +157 -0
  57. package/dist/esm/utils/bip21.js +110 -0
  58. package/dist/esm/utils/coinselect.js +69 -0
  59. package/dist/esm/utils/psbt.js +118 -0
  60. package/dist/esm/utils/transactionHistory.js +145 -0
  61. package/dist/esm/utils/txSizeEstimator.js +91 -0
  62. package/dist/esm/wallet/index.js +5 -0
  63. package/dist/esm/wallet/serviceWorker/db/vtxo/idb.js +149 -0
  64. package/dist/esm/wallet/serviceWorker/db/vtxo/index.js +1 -0
  65. package/dist/esm/wallet/serviceWorker/request.js +72 -0
  66. package/dist/esm/wallet/serviceWorker/response.js +184 -0
  67. package/dist/esm/wallet/serviceWorker/wallet.js +328 -0
  68. package/dist/esm/wallet/serviceWorker/worker.js +448 -0
  69. package/dist/esm/wallet/wallet.js +716 -0
  70. package/dist/types/arknote/index.d.ts +17 -0
  71. package/dist/types/forfeit.d.ts +15 -0
  72. package/dist/types/identity/inMemoryKey.d.ts +12 -0
  73. package/dist/types/identity/index.d.ts +7 -0
  74. package/dist/types/index.d.ts +22 -0
  75. package/dist/types/musig2/index.d.ts +4 -0
  76. package/dist/types/musig2/keys.d.ts +9 -0
  77. package/dist/types/musig2/nonces.d.ts +13 -0
  78. package/dist/types/musig2/sign.d.ts +27 -0
  79. package/dist/types/networks.d.ts +16 -0
  80. package/dist/types/providers/ark.d.ts +126 -0
  81. package/dist/types/providers/onchain.d.ts +36 -0
  82. package/dist/types/script/address.d.ts +10 -0
  83. package/dist/types/script/base.d.ts +26 -0
  84. package/dist/types/script/default.d.ts +19 -0
  85. package/dist/types/script/tapscript.d.ts +94 -0
  86. package/dist/types/script/vhtlc.d.ts +31 -0
  87. package/dist/types/tree/signingSession.d.ts +32 -0
  88. package/dist/types/tree/validation.d.ts +22 -0
  89. package/dist/types/tree/vtxoTree.d.ts +32 -0
  90. package/dist/types/utils/bip21.d.ts +21 -0
  91. package/dist/types/utils/coinselect.d.ts +21 -0
  92. package/dist/types/utils/psbt.d.ts +11 -0
  93. package/dist/types/utils/transactionHistory.d.ts +2 -0
  94. package/dist/types/utils/txSizeEstimator.d.ts +27 -0
  95. package/dist/types/wallet/index.d.ts +122 -0
  96. package/dist/types/wallet/serviceWorker/db/vtxo/idb.d.ts +18 -0
  97. package/dist/types/wallet/serviceWorker/db/vtxo/index.d.ts +12 -0
  98. package/dist/types/wallet/serviceWorker/request.d.ts +68 -0
  99. package/dist/types/wallet/serviceWorker/response.d.ts +107 -0
  100. package/dist/types/wallet/serviceWorker/wallet.d.ts +23 -0
  101. package/dist/types/wallet/serviceWorker/worker.d.ts +26 -0
  102. package/dist/types/wallet/wallet.d.ts +42 -0
  103. package/package.json +88 -0
@@ -0,0 +1,528 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.CLTVMultisigTapscript = exports.ConditionMultisigTapscript = exports.ConditionCSVMultisigTapscript = exports.CSVMultisigTapscript = exports.MultisigTapscript = exports.TapscriptType = void 0;
37
+ exports.decodeTapscript = decodeTapscript;
38
+ const bip68 = __importStar(require("bip68"));
39
+ const script_1 = require("@scure/btc-signer/script");
40
+ const payment_1 = require("@scure/btc-signer/payment");
41
+ const base_1 = require("@scure/base");
42
+ var TapscriptType;
43
+ (function (TapscriptType) {
44
+ TapscriptType["Multisig"] = "multisig";
45
+ TapscriptType["CSVMultisig"] = "csv-multisig";
46
+ TapscriptType["ConditionCSVMultisig"] = "condition-csv-multisig";
47
+ TapscriptType["ConditionMultisig"] = "condition-multisig";
48
+ TapscriptType["CLTVMultisig"] = "cltv-multisig";
49
+ })(TapscriptType || (exports.TapscriptType = TapscriptType = {}));
50
+ function decodeTapscript(script) {
51
+ const types = [
52
+ MultisigTapscript,
53
+ CSVMultisigTapscript,
54
+ ConditionCSVMultisigTapscript,
55
+ ConditionMultisigTapscript,
56
+ CLTVMultisigTapscript,
57
+ ];
58
+ for (const type of types) {
59
+ try {
60
+ return type.decode(script);
61
+ }
62
+ catch (error) {
63
+ continue;
64
+ }
65
+ }
66
+ throw new Error(`Failed to decode: script ${base_1.hex.encode(script)} is not a valid tapscript`);
67
+ }
68
+ /**
69
+ * Implements a multi-signature script that requires a threshold of signatures
70
+ * from the specified pubkeys.
71
+ */
72
+ var MultisigTapscript;
73
+ (function (MultisigTapscript) {
74
+ let MultisigType;
75
+ (function (MultisigType) {
76
+ MultisigType[MultisigType["CHECKSIG"] = 0] = "CHECKSIG";
77
+ MultisigType[MultisigType["CHECKSIGADD"] = 1] = "CHECKSIGADD";
78
+ })(MultisigType = MultisigTapscript.MultisigType || (MultisigTapscript.MultisigType = {}));
79
+ function encode(params) {
80
+ if (params.pubkeys.length === 0) {
81
+ throw new Error("At least 1 pubkey is required");
82
+ }
83
+ for (const pubkey of params.pubkeys) {
84
+ if (pubkey.length !== 32) {
85
+ throw new Error(`Invalid pubkey length: expected 32, got ${pubkey.length}`);
86
+ }
87
+ }
88
+ if (!params.type) {
89
+ params.type = MultisigType.CHECKSIG;
90
+ }
91
+ if (params.type === MultisigType.CHECKSIGADD) {
92
+ return {
93
+ type: TapscriptType.Multisig,
94
+ params,
95
+ script: (0, payment_1.p2tr_ms)(params.pubkeys.length, params.pubkeys).script,
96
+ witnessSize: () => params.pubkeys.length * 64,
97
+ };
98
+ }
99
+ const asm = [];
100
+ for (let i = 0; i < params.pubkeys.length; i++) {
101
+ asm.push(params.pubkeys[i]);
102
+ // CHECKSIGVERIFY except the last pubkey
103
+ if (i < params.pubkeys.length - 1) {
104
+ asm.push("CHECKSIGVERIFY");
105
+ }
106
+ else {
107
+ asm.push("CHECKSIG");
108
+ }
109
+ }
110
+ return {
111
+ type: TapscriptType.Multisig,
112
+ params,
113
+ script: script_1.Script.encode(asm),
114
+ witnessSize: () => params.pubkeys.length * 64,
115
+ };
116
+ }
117
+ MultisigTapscript.encode = encode;
118
+ function decode(script) {
119
+ if (script.length === 0) {
120
+ throw new Error("Failed to decode: script is empty");
121
+ }
122
+ try {
123
+ // Try decoding as checksigAdd first
124
+ return decodeChecksigAdd(script);
125
+ }
126
+ catch (error) {
127
+ // If checksigAdd fails, try regular checksig
128
+ try {
129
+ return decodeChecksig(script);
130
+ }
131
+ catch (error2) {
132
+ throw new Error(`Failed to decode script: ${error2 instanceof Error ? error2.message : String(error2)}`);
133
+ }
134
+ }
135
+ }
136
+ MultisigTapscript.decode = decode;
137
+ // <pubkey> CHECKSIG <pubkey> CHECKSIGADD <len_keys> NUMEQUAL
138
+ function decodeChecksigAdd(script) {
139
+ const asm = script_1.Script.decode(script);
140
+ const pubkeys = [];
141
+ let foundNumEqual = false;
142
+ // Parse through ASM operations
143
+ for (let i = 0; i < asm.length; i++) {
144
+ const op = asm[i];
145
+ // If it's a data push, it should be a 32-byte pubkey
146
+ if (typeof op !== "string" && typeof op !== "number") {
147
+ if (op.length !== 32) {
148
+ throw new Error(`Invalid pubkey length: expected 32, got ${op.length}`);
149
+ }
150
+ pubkeys.push(op);
151
+ // Check next operation is CHECKSIGADD or CHECKSIG
152
+ if (i + 1 >= asm.length ||
153
+ (asm[i + 1] !== "CHECKSIGADD" && asm[i + 1] !== "CHECKSIG")) {
154
+ throw new Error("Expected CHECKSIGADD or CHECKSIG after pubkey");
155
+ }
156
+ i++; // Skip the CHECKSIGADD op
157
+ continue;
158
+ }
159
+ // Last operation should be NUMEQUAL
160
+ if (i === asm.length - 1) {
161
+ if (op !== "NUMEQUAL") {
162
+ throw new Error("Expected NUMEQUAL at end of script");
163
+ }
164
+ foundNumEqual = true;
165
+ }
166
+ }
167
+ if (!foundNumEqual) {
168
+ throw new Error("Missing NUMEQUAL operation");
169
+ }
170
+ if (pubkeys.length === 0) {
171
+ throw new Error("Invalid script: must have at least 1 pubkey");
172
+ }
173
+ // Verify the script by re-encoding and comparing
174
+ const reconstructed = encode({
175
+ pubkeys,
176
+ type: MultisigType.CHECKSIGADD,
177
+ });
178
+ if (base_1.hex.encode(reconstructed.script) !== base_1.hex.encode(script)) {
179
+ throw new Error("Invalid script format: script reconstruction mismatch");
180
+ }
181
+ return {
182
+ type: TapscriptType.Multisig,
183
+ params: { pubkeys, type: MultisigType.CHECKSIGADD },
184
+ script,
185
+ witnessSize: () => pubkeys.length * 64,
186
+ };
187
+ }
188
+ // <pubkey> CHECKSIGVERIFY <pubkey> CHECKSIG
189
+ function decodeChecksig(script) {
190
+ const asm = script_1.Script.decode(script);
191
+ const pubkeys = [];
192
+ // Parse through ASM operations
193
+ for (let i = 0; i < asm.length; i++) {
194
+ const op = asm[i];
195
+ // If it's a data push, it should be a 32-byte pubkey
196
+ if (typeof op !== "string" && typeof op !== "number") {
197
+ if (op.length !== 32) {
198
+ throw new Error(`Invalid pubkey length: expected 32, got ${op.length}`);
199
+ }
200
+ pubkeys.push(op);
201
+ // Check next operation
202
+ if (i + 1 >= asm.length) {
203
+ throw new Error("Unexpected end of script");
204
+ }
205
+ const nextOp = asm[i + 1];
206
+ if (nextOp !== "CHECKSIGVERIFY" && nextOp !== "CHECKSIG") {
207
+ throw new Error("Expected CHECKSIGVERIFY or CHECKSIG after pubkey");
208
+ }
209
+ // Last operation must be CHECKSIG, not CHECKSIGVERIFY
210
+ if (i === asm.length - 2 && nextOp !== "CHECKSIG") {
211
+ throw new Error("Last operation must be CHECKSIG");
212
+ }
213
+ i++; // Skip the CHECKSIG/CHECKSIGVERIFY op
214
+ continue;
215
+ }
216
+ }
217
+ if (pubkeys.length === 0) {
218
+ throw new Error("Invalid script: must have at least 1 pubkey");
219
+ }
220
+ // Verify the script by re-encoding and comparing
221
+ const reconstructed = encode({ pubkeys, type: MultisigType.CHECKSIG });
222
+ if (base_1.hex.encode(reconstructed.script) !== base_1.hex.encode(script)) {
223
+ throw new Error("Invalid script format: script reconstruction mismatch");
224
+ }
225
+ return {
226
+ type: TapscriptType.Multisig,
227
+ params: { pubkeys, type: MultisigType.CHECKSIG },
228
+ script,
229
+ witnessSize: () => pubkeys.length * 64,
230
+ };
231
+ }
232
+ function is(tapscript) {
233
+ return tapscript.type === TapscriptType.Multisig;
234
+ }
235
+ MultisigTapscript.is = is;
236
+ })(MultisigTapscript || (exports.MultisigTapscript = MultisigTapscript = {}));
237
+ /**
238
+ * Implements a relative timelock script that requires all specified pubkeys to sign
239
+ * after the relative timelock has expired. The timelock can be specified in blocks or seconds.
240
+ *
241
+ * This is the standard exit closure and it is also used for the sweep closure in vtxo trees.
242
+ */
243
+ var CSVMultisigTapscript;
244
+ (function (CSVMultisigTapscript) {
245
+ function encode(params) {
246
+ for (const pubkey of params.pubkeys) {
247
+ if (pubkey.length !== 32) {
248
+ throw new Error(`Invalid pubkey length: expected 32, got ${pubkey.length}`);
249
+ }
250
+ }
251
+ const sequence = (0, script_1.ScriptNum)().encode(BigInt(bip68.encode(params.timelock.type === "blocks"
252
+ ? { blocks: Number(params.timelock.value) }
253
+ : { seconds: Number(params.timelock.value) })));
254
+ const asm = [sequence, "CHECKSEQUENCEVERIFY", "DROP"];
255
+ const multisigScript = MultisigTapscript.encode(params);
256
+ const script = new Uint8Array([
257
+ ...script_1.Script.encode(asm),
258
+ ...multisigScript.script,
259
+ ]);
260
+ return {
261
+ type: TapscriptType.CSVMultisig,
262
+ params,
263
+ script,
264
+ witnessSize: () => params.pubkeys.length * 64,
265
+ };
266
+ }
267
+ CSVMultisigTapscript.encode = encode;
268
+ function decode(script) {
269
+ if (script.length === 0) {
270
+ throw new Error("Failed to decode: script is empty");
271
+ }
272
+ const asm = script_1.Script.decode(script);
273
+ if (asm.length < 3) {
274
+ throw new Error(`Invalid script: too short (expected at least 3)`);
275
+ }
276
+ const sequence = asm[0];
277
+ if (typeof sequence === "string" || typeof sequence === "number") {
278
+ throw new Error("Invalid script: expected sequence number");
279
+ }
280
+ if (asm[1] !== "CHECKSEQUENCEVERIFY" || asm[2] !== "DROP") {
281
+ throw new Error("Invalid script: expected CHECKSEQUENCEVERIFY DROP");
282
+ }
283
+ const multisigScript = new Uint8Array(script_1.Script.encode(asm.slice(3)));
284
+ let multisig;
285
+ try {
286
+ multisig = MultisigTapscript.decode(multisigScript);
287
+ }
288
+ catch (error) {
289
+ throw new Error(`Invalid multisig script: ${error instanceof Error ? error.message : String(error)}`);
290
+ }
291
+ const sequenceNum = Number((0, script_1.ScriptNum)().decode(sequence));
292
+ const decodedTimelock = bip68.decode(sequenceNum);
293
+ const timelock = decodedTimelock.blocks !== undefined
294
+ ? { type: "blocks", value: BigInt(decodedTimelock.blocks) }
295
+ : { type: "seconds", value: BigInt(decodedTimelock.seconds) };
296
+ const reconstructed = encode({
297
+ timelock,
298
+ ...multisig.params,
299
+ });
300
+ if (base_1.hex.encode(reconstructed.script) !== base_1.hex.encode(script)) {
301
+ throw new Error("Invalid script format: script reconstruction mismatch");
302
+ }
303
+ return {
304
+ type: TapscriptType.CSVMultisig,
305
+ params: {
306
+ timelock,
307
+ ...multisig.params,
308
+ },
309
+ script,
310
+ witnessSize: () => multisig.params.pubkeys.length * 64,
311
+ };
312
+ }
313
+ CSVMultisigTapscript.decode = decode;
314
+ function is(tapscript) {
315
+ return tapscript.type === TapscriptType.CSVMultisig;
316
+ }
317
+ CSVMultisigTapscript.is = is;
318
+ })(CSVMultisigTapscript || (exports.CSVMultisigTapscript = CSVMultisigTapscript = {}));
319
+ /**
320
+ * Combines a condition script with an exit closure. The resulting script requires
321
+ * the condition to be met, followed by the standard exit closure requirements
322
+ * (timelock and signatures).
323
+ */
324
+ var ConditionCSVMultisigTapscript;
325
+ (function (ConditionCSVMultisigTapscript) {
326
+ function encode(params) {
327
+ const script = new Uint8Array([
328
+ ...params.conditionScript,
329
+ ...script_1.Script.encode(["VERIFY"]),
330
+ ...CSVMultisigTapscript.encode(params).script,
331
+ ]);
332
+ return {
333
+ type: TapscriptType.ConditionCSVMultisig,
334
+ params,
335
+ script,
336
+ witnessSize: (conditionSize) => conditionSize + params.pubkeys.length * 64,
337
+ };
338
+ }
339
+ ConditionCSVMultisigTapscript.encode = encode;
340
+ function decode(script) {
341
+ if (script.length === 0) {
342
+ throw new Error("Failed to decode: script is empty");
343
+ }
344
+ const asm = script_1.Script.decode(script);
345
+ if (asm.length < 1) {
346
+ throw new Error(`Invalid script: too short (expected at least 1)`);
347
+ }
348
+ let verifyIndex = -1;
349
+ for (let i = asm.length - 1; i >= 0; i--) {
350
+ if (asm[i] === "VERIFY") {
351
+ verifyIndex = i;
352
+ }
353
+ }
354
+ if (verifyIndex === -1) {
355
+ throw new Error("Invalid script: missing VERIFY operation");
356
+ }
357
+ const conditionScript = new Uint8Array(script_1.Script.encode(asm.slice(0, verifyIndex)));
358
+ const csvMultisigScript = new Uint8Array(script_1.Script.encode(asm.slice(verifyIndex + 1)));
359
+ let csvMultisig;
360
+ try {
361
+ csvMultisig = CSVMultisigTapscript.decode(csvMultisigScript);
362
+ }
363
+ catch (error) {
364
+ throw new Error(`Invalid CSV multisig script: ${error instanceof Error ? error.message : String(error)}`);
365
+ }
366
+ const reconstructed = encode({
367
+ conditionScript,
368
+ ...csvMultisig.params,
369
+ });
370
+ if (base_1.hex.encode(reconstructed.script) !== base_1.hex.encode(script)) {
371
+ throw new Error("Invalid script format: script reconstruction mismatch");
372
+ }
373
+ return {
374
+ type: TapscriptType.ConditionCSVMultisig,
375
+ params: {
376
+ conditionScript,
377
+ ...csvMultisig.params,
378
+ },
379
+ script,
380
+ witnessSize: (conditionSize) => conditionSize + csvMultisig.params.pubkeys.length * 64,
381
+ };
382
+ }
383
+ ConditionCSVMultisigTapscript.decode = decode;
384
+ function is(tapscript) {
385
+ return tapscript.type === TapscriptType.ConditionCSVMultisig;
386
+ }
387
+ ConditionCSVMultisigTapscript.is = is;
388
+ })(ConditionCSVMultisigTapscript || (exports.ConditionCSVMultisigTapscript = ConditionCSVMultisigTapscript = {}));
389
+ /**
390
+ * Combines a condition script with a forfeit closure. The resulting script requires
391
+ * the condition to be met, followed by the standard forfeit closure requirements
392
+ * (multi-signature).
393
+ */
394
+ var ConditionMultisigTapscript;
395
+ (function (ConditionMultisigTapscript) {
396
+ function encode(params) {
397
+ const script = new Uint8Array([
398
+ ...params.conditionScript,
399
+ ...script_1.Script.encode(["VERIFY"]),
400
+ ...MultisigTapscript.encode(params).script,
401
+ ]);
402
+ return {
403
+ type: TapscriptType.ConditionMultisig,
404
+ params,
405
+ script,
406
+ witnessSize: (conditionSize) => conditionSize + params.pubkeys.length * 64,
407
+ };
408
+ }
409
+ ConditionMultisigTapscript.encode = encode;
410
+ function decode(script) {
411
+ if (script.length === 0) {
412
+ throw new Error("Failed to decode: script is empty");
413
+ }
414
+ const asm = script_1.Script.decode(script);
415
+ if (asm.length < 1) {
416
+ throw new Error(`Invalid script: too short (expected at least 1)`);
417
+ }
418
+ let verifyIndex = -1;
419
+ for (let i = asm.length - 1; i >= 0; i--) {
420
+ if (asm[i] === "VERIFY") {
421
+ verifyIndex = i;
422
+ }
423
+ }
424
+ if (verifyIndex === -1) {
425
+ throw new Error("Invalid script: missing VERIFY operation");
426
+ }
427
+ const conditionScript = new Uint8Array(script_1.Script.encode(asm.slice(0, verifyIndex)));
428
+ const multisigScript = new Uint8Array(script_1.Script.encode(asm.slice(verifyIndex + 1)));
429
+ let multisig;
430
+ try {
431
+ multisig = MultisigTapscript.decode(multisigScript);
432
+ }
433
+ catch (error) {
434
+ throw new Error(`Invalid multisig script: ${error instanceof Error ? error.message : String(error)}`);
435
+ }
436
+ const reconstructed = encode({
437
+ conditionScript,
438
+ ...multisig.params,
439
+ });
440
+ if (base_1.hex.encode(reconstructed.script) !== base_1.hex.encode(script)) {
441
+ throw new Error("Invalid script format: script reconstruction mismatch");
442
+ }
443
+ return {
444
+ type: TapscriptType.ConditionMultisig,
445
+ params: {
446
+ conditionScript,
447
+ ...multisig.params,
448
+ },
449
+ script,
450
+ witnessSize: (conditionSize) => conditionSize + multisig.params.pubkeys.length * 64,
451
+ };
452
+ }
453
+ ConditionMultisigTapscript.decode = decode;
454
+ function is(tapscript) {
455
+ return tapscript.type === TapscriptType.ConditionMultisig;
456
+ }
457
+ ConditionMultisigTapscript.is = is;
458
+ })(ConditionMultisigTapscript || (exports.ConditionMultisigTapscript = ConditionMultisigTapscript = {}));
459
+ /**
460
+ * Implements an absolute timelock (CLTV) script combined with a forfeit closure.
461
+ * The script requires waiting until a specific block height/timestamp before the
462
+ * forfeit closure conditions can be met.
463
+ */
464
+ var CLTVMultisigTapscript;
465
+ (function (CLTVMultisigTapscript) {
466
+ function encode(params) {
467
+ const locktime = (0, script_1.ScriptNum)().encode(params.absoluteTimelock);
468
+ const asm = [locktime, "CHECKLOCKTIMEVERIFY", "DROP"];
469
+ const timelockedScript = script_1.Script.encode(asm);
470
+ const script = new Uint8Array([
471
+ ...timelockedScript,
472
+ ...MultisigTapscript.encode(params).script,
473
+ ]);
474
+ return {
475
+ type: TapscriptType.CLTVMultisig,
476
+ params,
477
+ script,
478
+ witnessSize: () => params.pubkeys.length * 64,
479
+ };
480
+ }
481
+ CLTVMultisigTapscript.encode = encode;
482
+ function decode(script) {
483
+ if (script.length === 0) {
484
+ throw new Error("Failed to decode: script is empty");
485
+ }
486
+ const asm = script_1.Script.decode(script);
487
+ if (asm.length < 3) {
488
+ throw new Error(`Invalid script: too short (expected at least 3)`);
489
+ }
490
+ const locktime = asm[0];
491
+ if (typeof locktime === "string" || typeof locktime === "number") {
492
+ throw new Error("Invalid script: expected locktime number");
493
+ }
494
+ if (asm[1] !== "CHECKLOCKTIMEVERIFY" || asm[2] !== "DROP") {
495
+ throw new Error("Invalid script: expected CHECKLOCKTIMEVERIFY DROP");
496
+ }
497
+ const multisigScript = new Uint8Array(script_1.Script.encode(asm.slice(3)));
498
+ let multisig;
499
+ try {
500
+ multisig = MultisigTapscript.decode(multisigScript);
501
+ }
502
+ catch (error) {
503
+ throw new Error(`Invalid multisig script: ${error instanceof Error ? error.message : String(error)}`);
504
+ }
505
+ const absoluteTimelock = (0, script_1.ScriptNum)().decode(locktime);
506
+ const reconstructed = encode({
507
+ absoluteTimelock,
508
+ ...multisig.params,
509
+ });
510
+ if (base_1.hex.encode(reconstructed.script) !== base_1.hex.encode(script)) {
511
+ throw new Error("Invalid script format: script reconstruction mismatch");
512
+ }
513
+ return {
514
+ type: TapscriptType.CLTVMultisig,
515
+ params: {
516
+ absoluteTimelock,
517
+ ...multisig.params,
518
+ },
519
+ script,
520
+ witnessSize: () => multisig.params.pubkeys.length * 64,
521
+ };
522
+ }
523
+ CLTVMultisigTapscript.decode = decode;
524
+ function is(tapscript) {
525
+ return tapscript.type === TapscriptType.CLTVMultisig;
526
+ }
527
+ CLTVMultisigTapscript.is = is;
528
+ })(CLTVMultisigTapscript || (exports.CLTVMultisigTapscript = CLTVMultisigTapscript = {}));
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VHTLC = void 0;
4
+ const btc_signer_1 = require("@scure/btc-signer");
5
+ const tapscript_1 = require("./tapscript");
6
+ const base_1 = require("@scure/base");
7
+ const base_2 = require("./base");
8
+ // VHTLC is an Hashed Timelock Contract VtxoScript implementation
9
+ // - claim (preimage + receiver)
10
+ // - refund (sender + receiver + server)
11
+ // - refundWithoutReceiver (at refundLocktime, sender + receiver + server)
12
+ // - unilateralClaim (preimage + receiver after unilateralClaimDelay)
13
+ // - unilateralRefund (sender + receiver after unilateralRefundDelay)
14
+ // - unilateralRefundWithoutReceiver (sender after unilateralRefundWithoutReceiverDelay)
15
+ var VHTLC;
16
+ (function (VHTLC) {
17
+ class Script extends base_2.VtxoScript {
18
+ constructor(options) {
19
+ const { sender, receiver, server, preimageHash, refundLocktime, unilateralClaimDelay, unilateralRefundDelay, unilateralRefundWithoutReceiverDelay, } = options;
20
+ const conditionScript = preimageConditionScript(preimageHash);
21
+ const claimScript = tapscript_1.ConditionMultisigTapscript.encode({
22
+ conditionScript,
23
+ pubkeys: [receiver, server],
24
+ }).script;
25
+ const refundScript = tapscript_1.MultisigTapscript.encode({
26
+ pubkeys: [sender, receiver, server],
27
+ }).script;
28
+ const refundWithoutReceiverScript = tapscript_1.CLTVMultisigTapscript.encode({
29
+ absoluteTimelock: refundLocktime,
30
+ pubkeys: [sender, server],
31
+ }).script;
32
+ const unilateralClaimScript = tapscript_1.ConditionCSVMultisigTapscript.encode({
33
+ conditionScript,
34
+ timelock: unilateralClaimDelay,
35
+ pubkeys: [receiver],
36
+ }).script;
37
+ const unilateralRefundScript = tapscript_1.CSVMultisigTapscript.encode({
38
+ timelock: unilateralRefundDelay,
39
+ pubkeys: [sender, receiver],
40
+ }).script;
41
+ const unilateralRefundWithoutReceiverScript = tapscript_1.CSVMultisigTapscript.encode({
42
+ timelock: unilateralRefundWithoutReceiverDelay,
43
+ pubkeys: [sender],
44
+ }).script;
45
+ super([
46
+ claimScript,
47
+ refundScript,
48
+ refundWithoutReceiverScript,
49
+ unilateralClaimScript,
50
+ unilateralRefundScript,
51
+ unilateralRefundWithoutReceiverScript,
52
+ ]);
53
+ this.options = options;
54
+ this.claimScript = base_1.hex.encode(claimScript);
55
+ this.refundScript = base_1.hex.encode(refundScript);
56
+ this.refundWithoutReceiverScript = base_1.hex.encode(refundWithoutReceiverScript);
57
+ this.unilateralClaimScript = base_1.hex.encode(unilateralClaimScript);
58
+ this.unilateralRefundScript = base_1.hex.encode(unilateralRefundScript);
59
+ this.unilateralRefundWithoutReceiverScript = base_1.hex.encode(unilateralRefundWithoutReceiverScript);
60
+ }
61
+ claim() {
62
+ return this.findLeaf(this.claimScript);
63
+ }
64
+ refund() {
65
+ return this.findLeaf(this.refundScript);
66
+ }
67
+ refundWithoutReceiver() {
68
+ return this.findLeaf(this.refundWithoutReceiverScript);
69
+ }
70
+ unilateralClaim() {
71
+ return this.findLeaf(this.unilateralClaimScript);
72
+ }
73
+ unilateralRefund() {
74
+ return this.findLeaf(this.unilateralRefundScript);
75
+ }
76
+ unilateralRefundWithoutReceiver() {
77
+ return this.findLeaf(this.unilateralRefundWithoutReceiverScript);
78
+ }
79
+ }
80
+ VHTLC.Script = Script;
81
+ })(VHTLC || (exports.VHTLC = VHTLC = {}));
82
+ function preimageConditionScript(preimageHash) {
83
+ return btc_signer_1.Script.encode(["HASH160", preimageHash, "EQUAL"]);
84
+ }