@arkade-os/sdk 0.5.0-rc.9 → 0.5.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.
Files changed (94) hide show
  1. package/README.md +231 -50
  2. package/dist/adapters/expo.cjs +5 -5
  3. package/dist/adapters/expo.d.cts +5 -5
  4. package/dist/adapters/expo.d.ts +5 -5
  5. package/dist/adapters/expo.js +3 -3
  6. package/dist/{asyncStorageTaskQueue-DZYrAWN8.d.ts → asyncStorageTaskQueue-BFv2O1y1.d.ts} +2 -2
  7. package/dist/{asyncStorageTaskQueue-ChKX-D51.d.cts → asyncStorageTaskQueue-qRRQUOE8.d.cts} +2 -2
  8. package/dist/{chunk-PKD5VPYX.cjs → chunk-AU77RYOC.cjs} +6086 -4522
  9. package/dist/chunk-AU77RYOC.cjs.map +1 -0
  10. package/dist/{chunk-VMVHRKXM.cjs → chunk-GN2K4WBP.cjs} +494 -1122
  11. package/dist/chunk-GN2K4WBP.cjs.map +1 -0
  12. package/dist/{chunk-PO2ZDZZC.cjs → chunk-GOM26K6H.cjs} +12 -10
  13. package/dist/chunk-GOM26K6H.cjs.map +1 -0
  14. package/dist/{chunk-3TCWQPAC.js → chunk-GWJWXVUB.js} +5793 -4249
  15. package/dist/chunk-GWJWXVUB.js.map +1 -0
  16. package/dist/{chunk-J2K7WWMJ.js → chunk-HABGVRLF.js} +112 -243
  17. package/dist/chunk-HABGVRLF.js.map +1 -0
  18. package/dist/{chunk-V4JZOFYT.cjs → chunk-IQWLFYT2.cjs} +124 -254
  19. package/dist/chunk-IQWLFYT2.cjs.map +1 -0
  20. package/dist/{chunk-7OL2P5TV.cjs → chunk-JT5YVMCJ.cjs} +39 -46
  21. package/dist/chunk-JT5YVMCJ.cjs.map +1 -0
  22. package/dist/{chunk-FQCMEAWN.js → chunk-K2E6X6JT.js} +32 -39
  23. package/dist/chunk-K2E6X6JT.js.map +1 -0
  24. package/dist/{chunk-R4KRWX7R.js → chunk-K352GMVL.js} +427 -1078
  25. package/dist/chunk-K352GMVL.js.map +1 -0
  26. package/dist/{chunk-Z3QM5XFY.js → chunk-TZSKLERU.js} +7 -5
  27. package/dist/chunk-TZSKLERU.js.map +1 -0
  28. package/dist/{chunk-VTXMC4N7.cjs → chunk-UUSKJOSX.cjs} +548 -399
  29. package/dist/chunk-UUSKJOSX.cjs.map +1 -0
  30. package/dist/{chunk-JFZBKPSV.js → chunk-ZOEB53NQ.js} +541 -400
  31. package/dist/chunk-ZOEB53NQ.js.map +1 -0
  32. package/dist/contracts/handlers/index.cjs +9 -9
  33. package/dist/contracts/handlers/index.d.cts +5 -5
  34. package/dist/contracts/handlers/index.d.ts +5 -5
  35. package/dist/contracts/handlers/index.js +2 -2
  36. package/dist/{delegate-Cyv2suFd.d.cts → delegate-B5BmYkEY.d.cts} +1 -1
  37. package/dist/{delegate-CyBnNY9v.d.ts → delegate-DNbiUgy8.d.ts} +1 -1
  38. package/dist/index-B4QuO9sH.d.cts +645 -0
  39. package/dist/index-CYeyT3kn.d.ts +645 -0
  40. package/dist/{index-BIL9boGL.d.ts → index-CZw-MMfY.d.cts} +1644 -2291
  41. package/dist/{index-BIL9boGL.d.cts → index-CZw-MMfY.d.ts} +1644 -2291
  42. package/dist/index.cjs +399 -311
  43. package/dist/index.d.cts +950 -1124
  44. package/dist/index.d.ts +950 -1124
  45. package/dist/index.js +4 -4
  46. package/dist/repositories/realm/index.cjs +165 -103
  47. package/dist/repositories/realm/index.cjs.map +1 -1
  48. package/dist/repositories/realm/index.d.cts +18 -14
  49. package/dist/repositories/realm/index.d.ts +18 -14
  50. package/dist/repositories/realm/index.js +153 -91
  51. package/dist/repositories/realm/index.js.map +1 -1
  52. package/dist/repositories/sqlite/index.cjs +226 -184
  53. package/dist/repositories/sqlite/index.cjs.map +1 -1
  54. package/dist/repositories/sqlite/index.d.cts +22 -21
  55. package/dist/repositories/sqlite/index.d.ts +22 -21
  56. package/dist/repositories/sqlite/index.js +218 -176
  57. package/dist/repositories/sqlite/index.js.map +1 -1
  58. package/dist/{taskRunner-DxpSuKmh.d.cts → taskRunner-B3SLvUfL.d.cts} +2 -2
  59. package/dist/{taskRunner-Cu4uO1to.d.ts → taskRunner-wm1bhmtP.d.ts} +2 -2
  60. package/dist/wallet/expo/background.cjs +14 -14
  61. package/dist/wallet/expo/background.cjs.map +1 -1
  62. package/dist/wallet/expo/background.d.cts +10 -16
  63. package/dist/wallet/expo/background.d.ts +10 -16
  64. package/dist/wallet/expo/background.js +6 -6
  65. package/dist/wallet/expo/background.js.map +1 -1
  66. package/dist/wallet/expo/index.cjs +19 -14
  67. package/dist/wallet/expo/index.cjs.map +1 -1
  68. package/dist/wallet/expo/index.d.cts +8 -6
  69. package/dist/wallet/expo/index.d.ts +8 -6
  70. package/dist/wallet/expo/index.js +10 -5
  71. package/dist/wallet/expo/index.js.map +1 -1
  72. package/dist/wallet-DCZ2-Bea.d.cts +1874 -0
  73. package/dist/wallet-DGLXuwXT.d.ts +1874 -0
  74. package/dist/worker/expo/index.cjs +9 -9
  75. package/dist/worker/expo/index.d.cts +6 -6
  76. package/dist/worker/expo/index.d.ts +6 -6
  77. package/dist/worker/expo/index.js +5 -5
  78. package/package.json +10 -11
  79. package/dist/chunk-3TCWQPAC.js.map +0 -1
  80. package/dist/chunk-7OL2P5TV.cjs.map +0 -1
  81. package/dist/chunk-FQCMEAWN.js.map +0 -1
  82. package/dist/chunk-J2K7WWMJ.js.map +0 -1
  83. package/dist/chunk-JFZBKPSV.js.map +0 -1
  84. package/dist/chunk-PKD5VPYX.cjs.map +0 -1
  85. package/dist/chunk-PO2ZDZZC.cjs.map +0 -1
  86. package/dist/chunk-R4KRWX7R.js.map +0 -1
  87. package/dist/chunk-V4JZOFYT.cjs.map +0 -1
  88. package/dist/chunk-VMVHRKXM.cjs.map +0 -1
  89. package/dist/chunk-VTXMC4N7.cjs.map +0 -1
  90. package/dist/chunk-Z3QM5XFY.js.map +0 -1
  91. package/dist/hdWalletCapable-D1ImQqlu.d.cts +0 -2214
  92. package/dist/hdWalletCapable-DvumVrKW.d.ts +0 -2214
  93. package/dist/index-DleNQcz5.d.cts +0 -850
  94. package/dist/index-QVhQgYvU.d.ts +0 -850
@@ -1,43 +1,48 @@
1
1
  'use strict';
2
2
 
3
- var chunkVTXMC4N7_cjs = require('./chunk-VTXMC4N7.cjs');
3
+ var chunkUUSKJOSX_cjs = require('./chunk-UUSKJOSX.cjs');
4
4
  var base = require('@scure/base');
5
5
  var descriptorsScure = require('@bitcoinerlab/descriptors-scure');
6
6
  var btcSigner = require('@scure/btc-signer');
7
+ var P = require('micro-packed');
7
8
  var secp256k1_js = require('@noble/curves/secp256k1.js');
8
9
  var utils_js = require('@noble/curves/utils.js');
10
+ var utils_js$1 = require('@scure/btc-signer/utils.js');
11
+
12
+ function _interopNamespace(e) {
13
+ if (e && e.__esModule) return e;
14
+ var n = Object.create(null);
15
+ if (e) {
16
+ Object.keys(e).forEach(function (k) {
17
+ if (k !== 'default') {
18
+ var d = Object.getOwnPropertyDescriptor(e, k);
19
+ Object.defineProperty(n, k, d.get ? d : {
20
+ enumerable: true,
21
+ get: function () { return e[k]; }
22
+ });
23
+ }
24
+ });
25
+ }
26
+ n.default = e;
27
+ return Object.freeze(n);
28
+ }
29
+
30
+ var P__namespace = /*#__PURE__*/_interopNamespace(P);
9
31
 
10
32
  // src/contracts/handlers/registry.ts
11
33
  var ContractHandlerRegistry = class {
12
34
  handlers = /* @__PURE__ */ new Map();
13
- /**
14
- * Register a contract handler.
15
- *
16
- * @param handler - The handler to register
17
- * @throws If a handler for this type is already registered
18
- */
35
+ /** @throws If a handler for this type is already registered */
19
36
  register(handler) {
20
37
  if (this.handlers.has(handler.type)) {
21
38
  throw new Error(`Contract handler for type '${handler.type}' is already registered`);
22
39
  }
23
40
  this.handlers.set(handler.type, handler);
24
41
  }
25
- /**
26
- * Get a handler by type.
27
- *
28
- * @param type - The contract type
29
- * @returns The handler, or undefined if not found
30
- */
31
42
  get(type) {
32
43
  return this.handlers.get(type);
33
44
  }
34
- /**
35
- * Get a handler by type, throwing if not found.
36
- *
37
- * @param type - The contract type
38
- * @returns The handler
39
- * @throws If no handler is registered for this type
40
- */
45
+ /** @throws If no handler is registered for this type */
41
46
  getOrThrow(type) {
42
47
  const handler = this.get(type);
43
48
  if (!handler) {
@@ -45,29 +50,17 @@ var ContractHandlerRegistry = class {
45
50
  }
46
51
  return handler;
47
52
  }
48
- /**
49
- * Check if a handler is registered.
50
- *
51
- * @param type - The contract type
52
- */
53
53
  has(type) {
54
54
  return this.handlers.has(type);
55
55
  }
56
- /**
57
- * Get all registered types.
58
- */
59
56
  getRegisteredTypes() {
60
57
  return Array.from(this.handlers.keys());
61
58
  }
62
- /**
63
- * Unregister a handler (mainly for testing).
64
- */
59
+ /** Unregister a handler (mainly for testing). */
65
60
  unregister(type) {
66
61
  return this.handlers.delete(type);
67
62
  }
68
- /**
69
- * Clear all handlers (mainly for testing).
70
- */
63
+ /** Clear all handlers (mainly for testing). */
71
64
  clear() {
72
65
  this.handlers.clear();
73
66
  }
@@ -75,14 +68,14 @@ var ContractHandlerRegistry = class {
75
68
  var contractHandlers = new ContractHandlerRegistry();
76
69
  exports.DefaultVtxo = void 0;
77
70
  ((DefaultVtxo2) => {
78
- class Script3 extends chunkVTXMC4N7_cjs.VtxoScript {
71
+ class Script3 extends chunkUUSKJOSX_cjs.VtxoScript {
79
72
  /** Create the default virtual output script with one forfeit path and one exit path. */
80
73
  constructor(options) {
81
74
  const { pubKey, serverPubKey, csvTimelock } = options;
82
- const forfeitScript = chunkVTXMC4N7_cjs.MultisigTapscript.encode({
75
+ const forfeitScript = chunkUUSKJOSX_cjs.MultisigTapscript.encode({
83
76
  pubkeys: [pubKey, serverPubKey]
84
77
  }).script;
85
- const exitScript = chunkVTXMC4N7_cjs.CSVMultisigTapscript.encode({
78
+ const exitScript = chunkUUSKJOSX_cjs.CSVMultisigTapscript.encode({
86
79
  timelock: csvTimelock,
87
80
  pubkeys: [pubKey]
88
81
  }).script;
@@ -274,7 +267,7 @@ function extractPubKeyBytes(value) {
274
267
  return base.hex.decode(extractPubKey(normalizeToDescriptor(value)));
275
268
  }
276
269
  function deserializeCsvTimelock(value) {
277
- return value !== void 0 && value !== "" ? chunkVTXMC4N7_cjs.sequenceToTimelock(Number(value)) : exports.DefaultVtxo.Script.DEFAULT_TIMELOCK;
270
+ return value !== void 0 && value !== "" ? chunkUUSKJOSX_cjs.sequenceToTimelock(Number(value)) : exports.DefaultVtxo.Script.DEFAULT_TIMELOCK;
278
271
  }
279
272
  var CLTV_HEIGHT_THRESHOLD = 500000000n;
280
273
  function isCltvSatisfied(context, locktime) {
@@ -313,10 +306,139 @@ function assertVhtlcSpendableNow(contract, context) {
313
306
  `vhtlc ${contract.script} cannot be spent yet: its refund path opens at ${matures}, now ${now}. Until then the lockup is the receiver's to claim, and the server rejects a spend of it. Retry after ${matures}, or wait for the receiver to claim it with the preimage.`
314
307
  );
315
308
  }
309
+ function selectVhtlcPath(script, contract, context) {
310
+ const role = resolveRole(contract, context);
311
+ const preimage = contract.params?.preimage;
312
+ const refundLocktime = BigInt(contract.params.refundLocktime);
313
+ if (!role) {
314
+ return null;
315
+ }
316
+ if (context.collaborative) {
317
+ if (role === "receiver" && preimage) {
318
+ return {
319
+ leaf: script.claim(),
320
+ extraWitness: [base.hex.decode(preimage)]
321
+ };
322
+ }
323
+ if (role === "sender" && isCltvSatisfied(context, refundLocktime)) {
324
+ return {
325
+ leaf: script.refundWithoutReceiver()
326
+ };
327
+ }
328
+ return null;
329
+ }
330
+ if (role === "receiver" && preimage) {
331
+ const sequence = Number(contract.params.claimDelay);
332
+ if (!isCsvSpendable(context, sequence)) return null;
333
+ return {
334
+ leaf: script.unilateralClaim(),
335
+ extraWitness: [base.hex.decode(preimage)],
336
+ sequence
337
+ };
338
+ }
339
+ if (role === "sender") {
340
+ const sequence = Number(contract.params.refundNoReceiverDelay);
341
+ if (!isCsvSpendable(context, sequence)) return null;
342
+ return {
343
+ leaf: script.unilateralRefundWithoutReceiver(),
344
+ sequence
345
+ };
346
+ }
347
+ return null;
348
+ }
349
+ function vhtlcAllSpendingPaths(script, contract, context) {
350
+ const role = resolveRole(contract, context);
351
+ const paths = [];
352
+ if (!role) {
353
+ return paths;
354
+ }
355
+ const preimage = contract.params?.preimage;
356
+ if (context.collaborative) {
357
+ if (role === "receiver" && preimage) {
358
+ paths.push({
359
+ leaf: script.claim(),
360
+ extraWitness: [base.hex.decode(preimage)]
361
+ });
362
+ }
363
+ if (role === "sender") {
364
+ paths.push({
365
+ leaf: script.refundWithoutReceiver()
366
+ });
367
+ }
368
+ } else {
369
+ if (role === "receiver" && preimage) {
370
+ const sequence = Number(contract.params.claimDelay);
371
+ paths.push({
372
+ leaf: script.unilateralClaim(),
373
+ extraWitness: [base.hex.decode(preimage)],
374
+ sequence
375
+ });
376
+ }
377
+ if (role === "sender") {
378
+ const sequence = Number(contract.params.refundNoReceiverDelay);
379
+ paths.push({
380
+ leaf: script.unilateralRefundWithoutReceiver(),
381
+ sequence
382
+ });
383
+ }
384
+ }
385
+ return paths;
386
+ }
387
+ function vhtlcSpendablePaths(script, contract, context) {
388
+ const role = resolveRole(contract, context);
389
+ const paths = [];
390
+ if (!role) {
391
+ return paths;
392
+ }
393
+ const preimage = contract.params?.preimage;
394
+ const refundLocktime = BigInt(contract.params.refundLocktime);
395
+ if (context.collaborative) {
396
+ if (role === "receiver" && preimage) {
397
+ paths.push({
398
+ leaf: script.claim(),
399
+ extraWitness: [base.hex.decode(preimage)]
400
+ });
401
+ }
402
+ if (role === "sender" && isCltvSatisfied(context, refundLocktime)) {
403
+ paths.push({
404
+ leaf: script.refundWithoutReceiver()
405
+ });
406
+ }
407
+ return paths;
408
+ }
409
+ if (role === "receiver" && preimage) {
410
+ const sequence = Number(contract.params.claimDelay);
411
+ if (isCsvSpendable(context, sequence)) {
412
+ paths.push({
413
+ leaf: script.unilateralClaim(),
414
+ extraWitness: [base.hex.decode(preimage)],
415
+ sequence
416
+ });
417
+ }
418
+ }
419
+ if (role === "sender") {
420
+ const sequence = Number(contract.params.refundNoReceiverDelay);
421
+ if (isCsvSpendable(context, sequence)) {
422
+ paths.push({
423
+ leaf: script.unilateralRefundWithoutReceiver(),
424
+ sequence
425
+ });
426
+ }
427
+ }
428
+ return paths;
429
+ }
430
+ function deriveVhtlcTapscripts(script) {
431
+ const leaf = script.refundWithoutReceiver();
432
+ return {
433
+ forfeitTapLeafScript: leaf,
434
+ intentTapLeafScript: leaf,
435
+ tapTree: script.encode()
436
+ };
437
+ }
316
438
  function isCsvSpendable(context, sequence) {
317
439
  if (sequence === void 0) return true;
318
440
  if (!context.vtxo) return false;
319
- const timelock = chunkVTXMC4N7_cjs.sequenceToTimelock(sequence);
441
+ const timelock = chunkUUSKJOSX_cjs.sequenceToTimelock(sequence);
320
442
  if (timelock.type === "blocks") {
321
443
  if (context.blockHeight === void 0 || context.vtxo.status.block_height === void 0) {
322
444
  return false;
@@ -374,21 +496,21 @@ function forfeitExitSpendablePaths(script, contract, context) {
374
496
  async function detectUsedScripts(indexerProvider, scriptHexes) {
375
497
  const used = /* @__PURE__ */ new Set();
376
498
  const unique = [...new Set(scriptHexes)];
377
- for (let offset = 0; offset < unique.length; offset += chunkVTXMC4N7_cjs.SCRIPT_QUERY_CHUNK_SIZE) {
378
- const scripts = unique.slice(offset, offset + chunkVTXMC4N7_cjs.SCRIPT_QUERY_CHUNK_SIZE);
499
+ for (let offset = 0; offset < unique.length; offset += chunkUUSKJOSX_cjs.SCRIPT_QUERY_CHUNK_SIZE) {
500
+ const scripts = unique.slice(offset, offset + chunkUUSKJOSX_cjs.SCRIPT_QUERY_CHUNK_SIZE);
379
501
  const remaining = new Set(scripts);
380
502
  let pageIndex = 0;
381
503
  let hasMore = true;
382
504
  while (hasMore && remaining.size > 0) {
383
- const { vtxos, page } = await chunkVTXMC4N7_cjs.getNormalizedVtxos(indexerProvider, {
505
+ const { vtxos, page } = await chunkUUSKJOSX_cjs.getNormalizedVtxos(indexerProvider, {
384
506
  scripts,
385
507
  pageIndex,
386
- pageSize: chunkVTXMC4N7_cjs.DEFAULT_PAGE_SIZE
508
+ pageSize: chunkUUSKJOSX_cjs.DEFAULT_PAGE_SIZE
387
509
  });
388
510
  for (const vtxo of vtxos) {
389
511
  if (remaining.delete(vtxo.script)) used.add(vtxo.script);
390
512
  }
391
- hasMore = page ? vtxos.length === chunkVTXMC4N7_cjs.DEFAULT_PAGE_SIZE : false;
513
+ hasMore = page ? vtxos.length === chunkUUSKJOSX_cjs.DEFAULT_PAGE_SIZE : false;
392
514
  pageIndex++;
393
515
  }
394
516
  }
@@ -449,7 +571,7 @@ var DefaultContractHandler = {
449
571
  return {
450
572
  pubKey: base.hex.encode(params.pubKey),
451
573
  serverPubKey: base.hex.encode(params.serverPubKey),
452
- csvTimelock: chunkVTXMC4N7_cjs.timelockToSequence(params.csvTimelock).toString()
574
+ csvTimelock: chunkUUSKJOSX_cjs.timelockToSequence(params.csvTimelock).toString()
453
575
  };
454
576
  },
455
577
  deserializeParams(params) {
@@ -481,11 +603,7 @@ function defaultCandidatesAt(_index, descriptor, deps) {
481
603
  (opts) => new exports.DefaultVtxo.Script(opts)
482
604
  ).map((c) => ({
483
605
  type: "default",
484
- params: {
485
- pubKey: base.hex.encode(c.pubKey),
486
- serverPubKey: base.hex.encode(c.serverPubKey),
487
- csvTimelock: chunkVTXMC4N7_cjs.timelockToSequence(c.csvTimelock).toString()
488
- },
606
+ params: DefaultContractHandler.serializeParams(c),
489
607
  script: c.scriptHex,
490
608
  address: c.script.address(deps.network.hrp, c.serverPubKey).encode()
491
609
  }));
@@ -500,12 +618,12 @@ function discoverDefaultRange(entries, deps) {
500
618
  }
501
619
  exports.DelegateVtxo = void 0;
502
620
  ((DelegateVtxo2) => {
503
- class Script3 extends chunkVTXMC4N7_cjs.VtxoScript {
621
+ class Script3 extends chunkUUSKJOSX_cjs.VtxoScript {
504
622
  /** Create a delegated virtual output script with forfeit, exit, and delegate paths. */
505
623
  constructor(options) {
506
624
  const defaultVtxo = new exports.DefaultVtxo.Script(options);
507
625
  const { delegatePubKey, pubKey, serverPubKey } = options;
508
- const delegateScript = chunkVTXMC4N7_cjs.MultisigTapscript.encode({
626
+ const delegateScript = chunkUUSKJOSX_cjs.MultisigTapscript.encode({
509
627
  pubkeys: [pubKey, delegatePubKey, serverPubKey]
510
628
  }).script;
511
629
  super([...defaultVtxo.scripts, delegateScript]);
@@ -544,7 +662,7 @@ var DelegateContractHandler = {
544
662
  pubKey: base.hex.encode(params.pubKey),
545
663
  serverPubKey: base.hex.encode(params.serverPubKey),
546
664
  delegatePubKey: base.hex.encode(params.delegatePubKey),
547
- csvTimelock: chunkVTXMC4N7_cjs.timelockToSequence(params.csvTimelock).toString()
665
+ csvTimelock: chunkUUSKJOSX_cjs.timelockToSequence(params.csvTimelock).toString()
548
666
  };
549
667
  },
550
668
  deserializeParams(params) {
@@ -584,12 +702,7 @@ function delegateCandidatesAt(_index, descriptor, deps) {
584
702
  (opts) => new exports.DelegateVtxo.Script({ ...opts, delegatePubKey })
585
703
  ).map((c) => ({
586
704
  type: "delegate",
587
- params: {
588
- pubKey: base.hex.encode(c.pubKey),
589
- serverPubKey: base.hex.encode(c.serverPubKey),
590
- delegatePubKey: base.hex.encode(delegatePubKey),
591
- csvTimelock: chunkVTXMC4N7_cjs.timelockToSequence(c.csvTimelock).toString()
592
- },
705
+ params: DelegateContractHandler.serializeParams({ ...c, delegatePubKey }),
593
706
  script: c.scriptHex,
594
707
  address: c.script.address(deps.network.hrp, c.serverPubKey).encode()
595
708
  }));
@@ -605,515 +718,10 @@ function discoverDelegateRange(entries, deps) {
605
718
  (c, index, descriptor) => ({ ...c, ...rotatedReceiveMetadata(index, descriptor) })
606
719
  );
607
720
  }
608
- function equalBytes(a, b) {
609
- if (a.length !== b.length)
610
- return false;
611
- for (let i = 0; i < a.length; i++)
612
- if (a[i] !== b[i])
613
- return false;
614
- return true;
615
- }
616
- function isBytes(a) {
617
- return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
618
- }
619
- var createView = (arr) => new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
620
- function isPlainObject(obj) {
621
- return Object.prototype.toString.call(obj) === "[object Object]";
622
- }
623
- function isNum(num) {
624
- return Number.isSafeInteger(num);
625
- }
626
- var Bitset = {
627
- BITS: 32,
628
- FULL_MASK: -1 >>> 0,
629
- // 1<<32 will overflow
630
- len: (len) => Math.ceil(len / 32),
631
- create: (len) => new Uint32Array(Bitset.len(len)),
632
- clean: (bs) => bs.fill(0),
633
- debug: (bs) => Array.from(bs).map((i) => (i >>> 0).toString(2).padStart(32, "0")),
634
- checkLen: (bs, len) => {
635
- if (Bitset.len(len) === bs.length)
636
- return;
637
- throw new Error(`wrong length=${bs.length}. Expected: ${Bitset.len(len)}`);
638
- },
639
- chunkLen: (bsLen, pos, len) => {
640
- if (pos < 0)
641
- throw new Error(`wrong pos=${pos}`);
642
- if (pos + len > bsLen)
643
- throw new Error(`wrong range=${pos}/${len} of ${bsLen}`);
644
- },
645
- set: (bs, chunk, value, allowRewrite = true) => {
646
- if (!allowRewrite && (bs[chunk] & value) !== 0)
647
- return false;
648
- bs[chunk] |= value;
649
- return true;
650
- },
651
- pos: (pos, i) => ({
652
- chunk: Math.floor((pos + i) / 32),
653
- mask: 1 << 32 - (pos + i) % 32 - 1
654
- }),
655
- indices: (bs, len, invert = false) => {
656
- Bitset.checkLen(bs, len);
657
- const { FULL_MASK, BITS } = Bitset;
658
- const left = BITS - len % BITS;
659
- const lastMask = left ? FULL_MASK >>> left << left : FULL_MASK;
660
- const res = [];
661
- for (let i = 0; i < bs.length; i++) {
662
- let c = bs[i];
663
- if (invert)
664
- c = ~c;
665
- if (i === bs.length - 1)
666
- c &= lastMask;
667
- if (c === 0)
668
- continue;
669
- for (let j = 0; j < BITS; j++) {
670
- const m = 1 << BITS - j - 1;
671
- if (c & m)
672
- res.push(i * BITS + j);
673
- }
674
- }
675
- return res;
676
- },
677
- range: (arr) => {
678
- const res = [];
679
- let cur;
680
- for (const i of arr) {
681
- if (cur === void 0 || i !== cur.pos + cur.length)
682
- res.push(cur = { pos: i, length: 1 });
683
- else
684
- cur.length += 1;
685
- }
686
- return res;
687
- },
688
- rangeDebug: (bs, len, invert = false) => `[${Bitset.range(Bitset.indices(bs, len, invert)).map((i) => `(${i.pos}/${i.length})`).join(", ")}]`,
689
- setRange: (bs, bsLen, pos, len, allowRewrite = true) => {
690
- Bitset.chunkLen(bsLen, pos, len);
691
- const { FULL_MASK, BITS } = Bitset;
692
- const first = pos % BITS ? Math.floor(pos / BITS) : void 0;
693
- const lastPos = pos + len;
694
- const last = lastPos % BITS ? Math.floor(lastPos / BITS) : void 0;
695
- if (first !== void 0 && first === last)
696
- return Bitset.set(bs, first, FULL_MASK >>> BITS - len << BITS - len - pos, allowRewrite);
697
- if (first !== void 0) {
698
- if (!Bitset.set(bs, first, FULL_MASK >>> pos % BITS, allowRewrite))
699
- return false;
700
- }
701
- const start = first !== void 0 ? first + 1 : pos / BITS;
702
- const end = last !== void 0 ? last : lastPos / BITS;
703
- for (let i = start; i < end; i++)
704
- if (!Bitset.set(bs, i, FULL_MASK, allowRewrite))
705
- return false;
706
- if (last !== void 0 && first !== last) {
707
- if (!Bitset.set(bs, last, FULL_MASK << BITS - lastPos % BITS, allowRewrite))
708
- return false;
709
- }
710
- return true;
711
- }
712
- };
713
- var Path = {
714
- /**
715
- * Internal method for handling stack of paths (debug, errors, dynamic fields via path)
716
- * This is looks ugly (callback), but allows us to force stack cleaning by construction (.pop always after function).
717
- * Also, this makes impossible:
718
- * - pushing field when stack is empty
719
- * - pushing field inside of field (real bug)
720
- * NOTE: we don't want to do '.pop' on error!
721
- */
722
- pushObj: (stack, obj, objFn) => {
723
- const last = { obj };
724
- stack.push(last);
725
- objFn((field, fieldFn) => {
726
- last.field = field;
727
- fieldFn();
728
- last.field = void 0;
729
- });
730
- stack.pop();
731
- },
732
- path: (stack) => {
733
- const res = [];
734
- for (const i of stack)
735
- if (i.field !== void 0)
736
- res.push(i.field);
737
- return res.join("/");
738
- },
739
- err: (name, stack, msg) => {
740
- const err = new Error(`${name}(${Path.path(stack)}): ${typeof msg === "string" ? msg : msg.message}`);
741
- if (msg instanceof Error && msg.stack)
742
- err.stack = msg.stack;
743
- return err;
744
- },
745
- resolve: (stack, path) => {
746
- const parts = path.split("/");
747
- const objPath = stack.map((i2) => i2.obj);
748
- let i = 0;
749
- for (; i < parts.length; i++) {
750
- if (parts[i] === "..")
751
- objPath.pop();
752
- else
753
- break;
754
- }
755
- let cur = objPath.pop();
756
- for (; i < parts.length; i++) {
757
- if (!cur || cur[parts[i]] === void 0)
758
- return void 0;
759
- cur = cur[parts[i]];
760
- }
761
- return cur;
762
- }
763
- };
764
- var _Reader = class __Reader {
765
- pos = 0;
766
- data;
767
- opts;
768
- stack;
769
- parent;
770
- parentOffset;
771
- bitBuf = 0;
772
- bitPos = 0;
773
- bs;
774
- // bitset
775
- view;
776
- constructor(data, opts = {}, stack = [], parent = void 0, parentOffset = 0) {
777
- this.data = data;
778
- this.opts = opts;
779
- this.stack = stack;
780
- this.parent = parent;
781
- this.parentOffset = parentOffset;
782
- this.view = createView(data);
783
- }
784
- /** Internal method for pointers. */
785
- _enablePointers() {
786
- if (this.parent)
787
- return this.parent._enablePointers();
788
- if (this.bs)
789
- return;
790
- this.bs = Bitset.create(this.data.length);
791
- Bitset.setRange(this.bs, this.data.length, 0, this.pos, this.opts.allowMultipleReads);
792
- }
793
- markBytesBS(pos, len) {
794
- if (this.parent)
795
- return this.parent.markBytesBS(this.parentOffset + pos, len);
796
- if (!len)
797
- return true;
798
- if (!this.bs)
799
- return true;
800
- return Bitset.setRange(this.bs, this.data.length, pos, len, false);
801
- }
802
- markBytes(len) {
803
- const pos = this.pos;
804
- this.pos += len;
805
- const res = this.markBytesBS(pos, len);
806
- if (!this.opts.allowMultipleReads && !res)
807
- throw this.err(`multiple read pos=${this.pos} len=${len}`);
808
- return res;
809
- }
810
- pushObj(obj, objFn) {
811
- return Path.pushObj(this.stack, obj, objFn);
812
- }
813
- readView(n, fn) {
814
- if (!Number.isFinite(n))
815
- throw this.err(`readView: wrong length=${n}`);
816
- if (this.pos + n > this.data.length)
817
- throw this.err("readView: Unexpected end of buffer");
818
- const res = fn(this.view, this.pos);
819
- this.markBytes(n);
820
- return res;
821
- }
822
- // read bytes by absolute offset
823
- absBytes(n) {
824
- if (n > this.data.length)
825
- throw new Error("Unexpected end of buffer");
826
- return this.data.subarray(n);
827
- }
828
- finish() {
829
- if (this.opts.allowUnreadBytes)
830
- return;
831
- if (this.bitPos) {
832
- throw this.err(`${this.bitPos} bits left after unpack: ${base.hex.encode(this.data.slice(this.pos))}`);
833
- }
834
- if (this.bs && !this.parent) {
835
- const notRead = Bitset.indices(this.bs, this.data.length, true);
836
- if (notRead.length) {
837
- const formatted = Bitset.range(notRead).map(({ pos, length }) => `(${pos}/${length})[${base.hex.encode(this.data.subarray(pos, pos + length))}]`).join(", ");
838
- throw this.err(`unread byte ranges: ${formatted} (total=${this.data.length})`);
839
- } else
840
- return;
841
- }
842
- if (!this.isEnd()) {
843
- throw this.err(`${this.leftBytes} bytes ${this.bitPos} bits left after unpack: ${base.hex.encode(this.data.slice(this.pos))}`);
844
- }
845
- }
846
- // User methods
847
- err(msg) {
848
- return Path.err("Reader", this.stack, msg);
849
- }
850
- offsetReader(n) {
851
- if (n > this.data.length)
852
- throw this.err("offsetReader: Unexpected end of buffer");
853
- return new __Reader(this.absBytes(n), this.opts, this.stack, this, n);
854
- }
855
- bytes(n, peek = false) {
856
- if (this.bitPos)
857
- throw this.err("readBytes: bitPos not empty");
858
- if (!Number.isFinite(n))
859
- throw this.err(`readBytes: wrong length=${n}`);
860
- if (this.pos + n > this.data.length)
861
- throw this.err("readBytes: Unexpected end of buffer");
862
- const slice = this.data.subarray(this.pos, this.pos + n);
863
- if (!peek)
864
- this.markBytes(n);
865
- return slice;
866
- }
867
- byte(peek = false) {
868
- if (this.bitPos)
869
- throw this.err("readByte: bitPos not empty");
870
- if (this.pos + 1 > this.data.length)
871
- throw this.err("readBytes: Unexpected end of buffer");
872
- const data = this.data[this.pos];
873
- if (!peek)
874
- this.markBytes(1);
875
- return data;
876
- }
877
- get leftBytes() {
878
- return this.data.length - this.pos;
879
- }
880
- get totalBytes() {
881
- return this.data.length;
882
- }
883
- isEnd() {
884
- return this.pos >= this.data.length && !this.bitPos;
885
- }
886
- // bits are read in BE mode (left to right): (0b1000_0000).readBits(1) == 1
887
- bits(bits) {
888
- if (bits > 32)
889
- throw this.err("BitReader: cannot read more than 32 bits in single call");
890
- let out = 0;
891
- while (bits) {
892
- if (!this.bitPos) {
893
- this.bitBuf = this.byte();
894
- this.bitPos = 8;
895
- }
896
- const take = Math.min(bits, this.bitPos);
897
- this.bitPos -= take;
898
- out = out << take | this.bitBuf >> this.bitPos & 2 ** take - 1;
899
- this.bitBuf &= 2 ** this.bitPos - 1;
900
- bits -= take;
901
- }
902
- return out >>> 0;
903
- }
904
- find(needle, pos = this.pos) {
905
- if (!isBytes(needle))
906
- throw this.err(`find: needle is not bytes! ${needle}`);
907
- if (this.bitPos)
908
- throw this.err("findByte: bitPos not empty");
909
- if (!needle.length)
910
- throw this.err(`find: needle is empty`);
911
- for (let idx = pos; (idx = this.data.indexOf(needle[0], idx)) !== -1; idx++) {
912
- if (idx === -1)
913
- return;
914
- const leftBytes = this.data.length - idx;
915
- if (leftBytes < needle.length)
916
- return;
917
- if (equalBytes(needle, this.data.subarray(idx, idx + needle.length)))
918
- return idx;
919
- }
920
- return;
921
- }
922
- };
923
- var _Writer = class {
924
- pos = 0;
925
- stack;
926
- // We could have a single buffer here and re-alloc it with
927
- // x1.5-2 size each time it full, but it will be slower:
928
- // basic/encode bench: 395ns -> 560ns
929
- buffers = [];
930
- ptrs = [];
931
- bitBuf = 0;
932
- bitPos = 0;
933
- viewBuf = new Uint8Array(8);
934
- view;
935
- finished = false;
936
- constructor(stack = []) {
937
- this.stack = stack;
938
- this.view = createView(this.viewBuf);
939
- }
940
- pushObj(obj, objFn) {
941
- return Path.pushObj(this.stack, obj, objFn);
942
- }
943
- writeView(len, fn) {
944
- if (this.finished)
945
- throw this.err("buffer: finished");
946
- if (!isNum(len) || len > 8)
947
- throw new Error(`wrong writeView length=${len}`);
948
- fn(this.view);
949
- this.bytes(this.viewBuf.slice(0, len));
950
- this.viewBuf.fill(0);
951
- }
952
- // User methods
953
- err(msg) {
954
- if (this.finished)
955
- throw this.err("buffer: finished");
956
- return Path.err("Reader", this.stack, msg);
957
- }
958
- bytes(b) {
959
- if (this.finished)
960
- throw this.err("buffer: finished");
961
- if (this.bitPos)
962
- throw this.err("writeBytes: ends with non-empty bit buffer");
963
- this.buffers.push(b);
964
- this.pos += b.length;
965
- }
966
- byte(b) {
967
- if (this.finished)
968
- throw this.err("buffer: finished");
969
- if (this.bitPos)
970
- throw this.err("writeByte: ends with non-empty bit buffer");
971
- this.buffers.push(new Uint8Array([b]));
972
- this.pos++;
973
- }
974
- finish(clean = true) {
975
- if (this.finished)
976
- throw this.err("buffer: finished");
977
- if (this.bitPos)
978
- throw this.err("buffer: ends with non-empty bit buffer");
979
- const buffers = this.buffers.concat(this.ptrs.map((i) => i.buffer));
980
- const sum = buffers.map((b) => b.length).reduce((a, b) => a + b, 0);
981
- const buf = new Uint8Array(sum);
982
- for (let i = 0, pad = 0; i < buffers.length; i++) {
983
- const a = buffers[i];
984
- buf.set(a, pad);
985
- pad += a.length;
986
- }
987
- for (let pos = this.pos, i = 0; i < this.ptrs.length; i++) {
988
- const ptr = this.ptrs[i];
989
- buf.set(ptr.ptr.encode(pos), ptr.pos);
990
- pos += ptr.buffer.length;
991
- }
992
- if (clean) {
993
- this.buffers = [];
994
- for (const p of this.ptrs)
995
- p.buffer.fill(0);
996
- this.ptrs = [];
997
- this.finished = true;
998
- this.bitBuf = 0;
999
- }
1000
- return buf;
1001
- }
1002
- bits(value, bits) {
1003
- if (bits > 32)
1004
- throw this.err("writeBits: cannot write more than 32 bits in single call");
1005
- if (value >= 2 ** bits)
1006
- throw this.err(`writeBits: value (${value}) >= 2**bits (${bits})`);
1007
- while (bits) {
1008
- const take = Math.min(bits, 8 - this.bitPos);
1009
- this.bitBuf = this.bitBuf << take | value >> bits - take;
1010
- this.bitPos += take;
1011
- bits -= take;
1012
- value &= 2 ** bits - 1;
1013
- if (this.bitPos === 8) {
1014
- this.bitPos = 0;
1015
- this.buffers.push(new Uint8Array([this.bitBuf]));
1016
- this.pos++;
1017
- }
1018
- }
1019
- }
1020
- };
1021
- function _wrap(inner) {
1022
- return {
1023
- // NOTE: we cannot export validate here, since it is likely mistake.
1024
- encodeStream: inner.encodeStream,
1025
- decodeStream: inner.decodeStream,
1026
- size: inner.size,
1027
- encode: (value) => {
1028
- const w = new _Writer();
1029
- inner.encodeStream(w, value);
1030
- return w.finish();
1031
- },
1032
- decode: (data, opts = {}) => {
1033
- const r = new _Reader(data, opts);
1034
- const res = inner.decodeStream(r);
1035
- r.finish();
1036
- return res;
1037
- }
1038
- };
1039
- }
1040
- function validate(inner, fn) {
1041
- if (!isCoder(inner))
1042
- throw new Error(`validate: invalid inner value ${inner}`);
1043
- if (typeof fn !== "function")
1044
- throw new Error("validate: fn should be function");
1045
- return _wrap({
1046
- size: inner.size,
1047
- encodeStream: (w, value) => {
1048
- let res;
1049
- try {
1050
- res = fn(value);
1051
- } catch (e) {
1052
- throw w.err(e);
1053
- }
1054
- inner.encodeStream(w, res);
1055
- },
1056
- decodeStream: (r) => {
1057
- const res = inner.decodeStream(r);
1058
- try {
1059
- return fn(res);
1060
- } catch (e) {
1061
- throw r.err(e);
1062
- }
1063
- }
1064
- });
1065
- }
1066
- var wrap = (inner) => {
1067
- const res = _wrap(inner);
1068
- return inner.validate ? validate(res, inner.validate) : res;
1069
- };
1070
- var isBaseCoder = (elm) => isPlainObject(elm) && typeof elm.decode === "function" && typeof elm.encode === "function";
1071
- function isCoder(elm) {
1072
- return isPlainObject(elm) && isBaseCoder(elm) && typeof elm.encodeStream === "function" && typeof elm.decodeStream === "function" && (elm.size === void 0 || isNum(elm.size));
1073
- }
1074
- var view = (len, opts) => wrap({
1075
- size: len,
1076
- encodeStream: (w, value) => w.writeView(len, (view2) => opts.write(view2, value)),
1077
- decodeStream: (r) => r.readView(len, opts.read),
1078
- validate: (value) => {
1079
- if (typeof value !== "number")
1080
- throw new Error(`viewCoder: expected number, got ${typeof value}`);
1081
- if (opts.validate)
1082
- opts.validate(value);
1083
- return value;
1084
- }
1085
- });
1086
- var intView = (len, signed, opts) => {
1087
- const bits = len * 8;
1088
- const maxVal = 2 ** bits;
1089
- const validateUnsigned = (value) => {
1090
- if (!isNum(value))
1091
- throw new Error(`uintView: value is not safe integer: ${value}`);
1092
- if (0 > value || value >= maxVal) {
1093
- throw new Error(`uintView: value out of bounds. Expected 0 <= ${value} < ${maxVal}`);
1094
- }
1095
- };
1096
- return view(len, {
1097
- write: opts.write,
1098
- read: opts.read,
1099
- validate: validateUnsigned
1100
- });
1101
- };
1102
- var U32LE = /* @__PURE__ */ intView(4, false, {
1103
- read: (view2, pos) => view2.getUint32(pos, true),
1104
- write: (view2, value) => view2.setUint32(0, value, true)
1105
- });
1106
- var U16LE = /* @__PURE__ */ intView(2, false, {
1107
- read: (view2, pos) => view2.getUint16(pos, true),
1108
- write: (view2, value) => view2.setUint16(0, value, true)
1109
- });
1110
- var U8 = /* @__PURE__ */ intView(1, false, {
1111
- read: (view2, pos) => view2.getUint8(pos),
1112
- write: (view2, value) => view2.setUint8(0, value)
1113
- });
1114
721
  var ARKADE_OP = {
1115
722
  // Merkle Branch Verification (0xb3 — repurposed NOP4 slot)
1116
723
  MERKLEBRANCHVERIFY: 179,
724
+ PUT: 187,
1117
725
  // Digest (0xc3)
1118
726
  DIGEST: 195,
1119
727
  // SHA256 Streaming (0xc4-0xc6)
@@ -1145,7 +753,10 @@ var ARKADE_OP = {
1145
753
  BIN2NUM: 216,
1146
754
  REVERSEBYTES: 217,
1147
755
  MODEXP: 218,
1148
- // 0xdb-0xdf are unassigned (OP_UNKNOWN219-223)
756
+ // VTXO Expiry & Emulator Clock (0xdb-0xdc)
757
+ PUSHEXPIRY: 219,
758
+ CHECKTIME: 220,
759
+ // 0xdd-0xdf are unassigned (OP_UNKNOWN221-223)
1149
760
  // EC Operations (0xe0-0xe2)
1150
761
  ECADD: 224,
1151
762
  ECMUL: 225,
@@ -1174,7 +785,10 @@ var ARKADE_OP = {
1174
785
  INSPECTPACKET: 244,
1175
786
  INSPECTINPUTPACKET: 245,
1176
787
  // Signature Hash (0xf6)
1177
- SIGHASH: 246
788
+ SIGHASH: 246,
789
+ // Continuation & Intent Introspection (0xf7-0xf8)
790
+ TUNNEL: 247,
791
+ INSPECTINTENTMESSAGE: 248
1178
792
  };
1179
793
  var ARKADE_OPCODES = Object.values(ARKADE_OP);
1180
794
  var ARKADE_OPCODE_NAMES = Object.fromEntries(
@@ -1242,7 +856,7 @@ function getOpcodeValue(name) {
1242
856
 
1243
857
  // src/arkade/bignum.ts
1244
858
  var bignum_exports = {};
1245
- chunkVTXMC4N7_cjs.__export(bignum_exports, {
859
+ chunkUUSKJOSX_cjs.__export(bignum_exports, {
1246
860
  BIGNUM_MAX_BYTES: () => BIGNUM_MAX_BYTES,
1247
861
  decode: () => decode,
1248
862
  encode: () => encode
@@ -1270,7 +884,7 @@ var ArkadeOPNames = {};
1270
884
  for (const [k, v] of Object.entries(ARKADE_OPS)) {
1271
885
  if (typeof v === "number") ArkadeOPNames[v] = k;
1272
886
  }
1273
- var ArkadeScript = wrap({
887
+ var ArkadeScript = P__namespace.wrap({
1274
888
  encodeStream: (w, value) => {
1275
889
  for (let o of value) {
1276
890
  if (typeof o === "string") {
@@ -1296,10 +910,10 @@ var ArkadeScript = wrap({
1296
910
  w.byte(len);
1297
911
  } else if (len <= 65535) {
1298
912
  w.byte(btcSigner.OP.PUSHDATA2);
1299
- w.bytes(U16LE.encode(len));
913
+ w.bytes(P__namespace.U16LE.encode(len));
1300
914
  } else {
1301
915
  w.byte(btcSigner.OP.PUSHDATA4);
1302
- w.bytes(U32LE.encode(len));
916
+ w.bytes(P__namespace.U32LE.encode(len));
1303
917
  }
1304
918
  w.bytes(o);
1305
919
  }
@@ -1311,9 +925,9 @@ var ArkadeScript = wrap({
1311
925
  if (btcSigner.OP.OP_0 < cur && cur <= btcSigner.OP.PUSHDATA4) {
1312
926
  let len;
1313
927
  if (cur < btcSigner.OP.PUSHDATA1) len = cur;
1314
- else if (cur === btcSigner.OP.PUSHDATA1) len = U8.decodeStream(r);
1315
- else if (cur === btcSigner.OP.PUSHDATA2) len = U16LE.decodeStream(r);
1316
- else if (cur === btcSigner.OP.PUSHDATA4) len = U32LE.decodeStream(r);
928
+ else if (cur === btcSigner.OP.PUSHDATA1) len = P__namespace.U8.decodeStream(r);
929
+ else if (cur === btcSigner.OP.PUSHDATA2) len = P__namespace.U16LE.decodeStream(r);
930
+ else if (cur === btcSigner.OP.PUSHDATA4) len = P__namespace.U32LE.decodeStream(r);
1317
931
  else throw new Error("Should be not possible");
1318
932
  out.push(r.bytes(len));
1319
933
  } else if (cur === 0) {
@@ -1431,7 +1045,7 @@ function computeArkadeScriptPublicKey(pubKey, script) {
1431
1045
  // src/script/vhtlc.ts
1432
1046
  exports.VHTLC = void 0;
1433
1047
  ((VHTLC2) => {
1434
- class BaseScript extends chunkVTXMC4N7_cjs.VtxoScript {
1048
+ class BaseScript extends chunkUUSKJOSX_cjs.VtxoScript {
1435
1049
  options;
1436
1050
  claimScript;
1437
1051
  refundScript;
@@ -1458,27 +1072,27 @@ exports.VHTLC = void 0;
1458
1072
  unilateralRefundWithoutReceiverDelay
1459
1073
  } = options;
1460
1074
  const conditionScript = preimageCondition(preimageHash);
1461
- const claimScript = chunkVTXMC4N7_cjs.ConditionMultisigTapscript.encode({
1075
+ const claimScript = chunkUUSKJOSX_cjs.ConditionMultisigTapscript.encode({
1462
1076
  conditionScript,
1463
1077
  pubkeys: [receiver, server]
1464
1078
  }).script;
1465
- const refundScript = chunkVTXMC4N7_cjs.MultisigTapscript.encode({
1079
+ const refundScript = chunkUUSKJOSX_cjs.MultisigTapscript.encode({
1466
1080
  pubkeys: [sender, receiver, server]
1467
1081
  }).script;
1468
- const refundWithoutReceiverScript = chunkVTXMC4N7_cjs.CLTVMultisigTapscript.encode({
1082
+ const refundWithoutReceiverScript = chunkUUSKJOSX_cjs.CLTVMultisigTapscript.encode({
1469
1083
  absoluteTimelock: refundLocktime,
1470
1084
  pubkeys: [sender, server]
1471
1085
  }).script;
1472
- const unilateralClaimScript = chunkVTXMC4N7_cjs.ConditionCSVMultisigTapscript.encode({
1086
+ const unilateralClaimScript = chunkUUSKJOSX_cjs.ConditionCSVMultisigTapscript.encode({
1473
1087
  conditionScript,
1474
1088
  timelock: unilateralClaimDelay,
1475
1089
  pubkeys: [receiver]
1476
1090
  }).script;
1477
- const unilateralRefundScript = chunkVTXMC4N7_cjs.CSVMultisigTapscript.encode({
1091
+ const unilateralRefundScript = chunkUUSKJOSX_cjs.CSVMultisigTapscript.encode({
1478
1092
  timelock: unilateralRefundDelay,
1479
1093
  pubkeys: [sender, receiver]
1480
1094
  }).script;
1481
- const unilateralRefundWithoutReceiverScript = chunkVTXMC4N7_cjs.CSVMultisigTapscript.encode({
1095
+ const unilateralRefundWithoutReceiverScript = chunkUUSKJOSX_cjs.CSVMultisigTapscript.encode({
1482
1096
  timelock: unilateralRefundWithoutReceiverDelay,
1483
1097
  pubkeys: [sender]
1484
1098
  }).script;
@@ -1498,7 +1112,7 @@ exports.VHTLC = void 0;
1498
1112
  const covenants = options.nonInteractiveParameters;
1499
1113
  if (covenants) {
1500
1114
  arkadeScriptNic = enforcePayToMaybeAsset(covenants.receiverPkScript, options.asset);
1501
- nonInteractiveClaimScript = chunkVTXMC4N7_cjs.ConditionMultisigTapscript.encode({
1115
+ nonInteractiveClaimScript = chunkUUSKJOSX_cjs.ConditionMultisigTapscript.encode({
1502
1116
  conditionScript,
1503
1117
  pubkeys: [
1504
1118
  server,
@@ -1511,12 +1125,12 @@ exports.VHTLC = void 0;
1511
1125
  covenants.emulatorPubkey,
1512
1126
  arkadeScriptNir
1513
1127
  );
1514
- nonInteractiveRefundScript = chunkVTXMC4N7_cjs.MultisigTapscript.encode({
1128
+ nonInteractiveRefundScript = chunkUUSKJOSX_cjs.MultisigTapscript.encode({
1515
1129
  pubkeys: [server, receiver, nirCosigner]
1516
1130
  }).script;
1517
1131
  scripts.push(nonInteractiveRefundScript);
1518
1132
  if (covenants.legacy !== "preTimelockedRefund") {
1519
- nonInteractiveRefundWithoutReceiverScript = chunkVTXMC4N7_cjs.CLTVMultisigTapscript.encode({
1133
+ nonInteractiveRefundWithoutReceiverScript = chunkUUSKJOSX_cjs.CLTVMultisigTapscript.encode({
1520
1134
  absoluteTimelock: refundLocktime,
1521
1135
  pubkeys: [server, nirCosigner]
1522
1136
  }).script;
@@ -1595,54 +1209,19 @@ exports.VHTLC = void 0;
1595
1209
  /**
1596
1210
  * Return the timelocked non-interactive refund tapleaf and its ArkadeScript.
1597
1211
  *
1598
- * SPENDING THIS LEAF, CONCRETELY — confirmed from this SDK's own
1599
- * emulator client and covenant-spend builder ({@link
1600
- * EmulatorProvider} in `src/providers/emulator.ts`, and {@link
1601
- * ArkadeTransactionBuilder} in `src/arkade/contract.ts`), which is
1602
- * the general machinery every covenant leaf in this file goes
1603
- * through:
1212
+ * Spent through the generic covenant path ({@link EmulatorProvider},
1213
+ * {@link ArkadeTransactionBuilder}): build the ark tx on this leaf plus its checkpoint;
1214
+ * attach this ArkadeScript to the input in an `EmulatorPacket` (type 1, empty witness:
1215
+ * the script pushes its own index with `PUSHCURRENTINPUTINDEX`) inside an `Extension`
1216
+ * OP_RETURN; attach the input's creating ark tx as `PrevArkTx` (the emulator can't
1217
+ * otherwise resolve its prevout); POST to the emulator's `/v1/tx`. The emulator co-signs
1218
+ * for `nirCosigner` only if `enforcePayTo(senderPkScript)` holds, and finalizes with arkd.
1219
+ * `server`'s signature is still required at consensus level, outside the covenant.
1604
1220
  *
1605
- * 1. Build the ark tx spending this leaf (this method's {@link
1606
- * TapLeafScript} as `tapLeafScript`, this script's {@link
1607
- * VtxoScript.encode} as `tapTree`), plus its checkpoint tx.
1608
- * 2. Attach the ArkadeScript this method returns to the spent
1609
- * input via an `EmulatorPacket` (type 1) — `{ vin, script:
1610
- * <this ArkadeScript>, witness: <empty> }`, empty because the
1611
- * script pushes its own input/output index with
1612
- * `PUSHCURRENTINPUTINDEX` rather than reading one from the
1613
- * witness — wrapped in an `Extension` OP_RETURN output on the
1614
- * ark tx.
1615
- * 3. Attach the spent input's OWN creating ark tx as `PrevArkTx` on
1616
- * input 0 — required so the emulator can resolve that input's
1617
- * prevout pkScript/value; it does not otherwise have them.
1618
- * 4. POST the (base64-PSBT) ark tx and checkpoint(s) as `{ arkTx,
1619
- * checkpointTxs }` to the emulator's `POST /v1/tx`.
1620
- *
1621
- * THE COVENANT CHECK the emulator runs against that ArkadeScript —
1622
- * `enforcePayTo(senderPkScript)`, see that function above — is: the
1623
- * output at this SAME input's index is a v1 P2TR output paying
1624
- * `senderPkScript`, with a value at least the input's. Only on that
1625
- * check passing does the emulator sign for `nirCosigner` (the
1626
- * `emulatorPubkey` tweaked by this ArkadeScript's hash); the
1627
- * response carries the fully co-signed `signedArkTx` and
1628
- * `signedCheckpointTxs` — `ArkadeTransactionBuilder.send()`'s own
1629
- * comment on this path: "the emulator executes the arkade script
1630
- * and finalizes with arkd" — no separate call to arkd is made by
1631
- * this SDK for a covenant spend.
1632
- * Neither `server` nor `receiver` play any part in that check: this
1633
- * leaf's tapscript still requires `server`'s own signature
1634
- * alongside `nirCosigner`'s (see the class doc above), but that is
1635
- * consensus-level multisig, not something the covenant enforces.
1636
- *
1637
- * NOT SPENDABLE UNTIL `refundLocktime` MATURES — the tapscript's
1638
- * `OP_CHECKLOCKTIMEVERIFY` is arkd's concern, not the emulator's;
1639
- * the emulator will happily co-sign an immature spend and arkd will
1640
- * then refuse it. A block-height-typed `refundLocktime` (below the
1641
- * standard height/timestamp boundary this SDK names
1642
- * `CLTV_HEIGHT_THRESHOLD`, 500,000,000, in
1643
- * `src/contracts/handlers/helpers.ts`) is refused by arkd for a
1644
- * forfeit-eligible leaf independent of maturity — use a
1645
- * seconds-typed (absolute Unix timestamp) value.
1221
+ * The emulator does not check `refundLocktime`: it co-signs an immature spend and arkd's
1222
+ * CLTV refuses it. arkd also refuses a block-height `refundLocktime`
1223
+ * (< `CLTV_HEIGHT_THRESHOLD`, 500,000,000) on a forfeit-eligible leaf regardless of
1224
+ * maturity: use a seconds-typed (Unix timestamp) value.
1646
1225
  */
1647
1226
  nonInteractiveRefundWithoutReceiver() {
1648
1227
  if (!this.nonInteractiveRefundWithoutReceiverScript || !this.nonInteractiveRefundWithoutReceiverArkadeScript) {
@@ -1785,10 +1364,7 @@ function enforcePayToAsset(destinationPkScript, asset) {
1785
1364
  }
1786
1365
  const inspectionTxid = Uint8Array.from(asset.txid).reverse();
1787
1366
  return ArkadeScript.encode([
1788
- // The output carries at least as much of the asset as the input did.
1789
- // Output index is the input's -- the same index alignment the sat
1790
- // covenant relies on, and the same liveness obligation on whoever
1791
- // assembles the spend.
1367
+ // The output at the input's index carries at least the input's amount of the asset.
1792
1368
  "PUSHCURRENTINPUTINDEX",
1793
1369
  inspectionTxid,
1794
1370
  asset.groupIndex,
@@ -1830,9 +1406,9 @@ var VHTLCContractHandler = {
1830
1406
  server: base.hex.encode(params.server),
1831
1407
  hash: base.hex.encode(params.preimageHash),
1832
1408
  refundLocktime: params.refundLocktime.toString(),
1833
- claimDelay: chunkVTXMC4N7_cjs.timelockToSequence(params.unilateralClaimDelay).toString(),
1834
- refundDelay: chunkVTXMC4N7_cjs.timelockToSequence(params.unilateralRefundDelay).toString(),
1835
- refundNoReceiverDelay: chunkVTXMC4N7_cjs.timelockToSequence(
1409
+ claimDelay: chunkUUSKJOSX_cjs.timelockToSequence(params.unilateralClaimDelay).toString(),
1410
+ refundDelay: chunkUUSKJOSX_cjs.timelockToSequence(params.unilateralRefundDelay).toString(),
1411
+ refundNoReceiverDelay: chunkUUSKJOSX_cjs.timelockToSequence(
1836
1412
  params.unilateralRefundWithoutReceiverDelay
1837
1413
  ).toString()
1838
1414
  };
@@ -1844,147 +1420,26 @@ var VHTLCContractHandler = {
1844
1420
  server: base.hex.decode(params.server),
1845
1421
  preimageHash: base.hex.decode(params.hash),
1846
1422
  refundLocktime: BigInt(params.refundLocktime),
1847
- unilateralClaimDelay: chunkVTXMC4N7_cjs.sequenceToTimelock(Number(params.claimDelay)),
1848
- unilateralRefundDelay: chunkVTXMC4N7_cjs.sequenceToTimelock(Number(params.refundDelay)),
1849
- unilateralRefundWithoutReceiverDelay: chunkVTXMC4N7_cjs.sequenceToTimelock(
1423
+ unilateralClaimDelay: chunkUUSKJOSX_cjs.sequenceToTimelock(Number(params.claimDelay)),
1424
+ unilateralRefundDelay: chunkUUSKJOSX_cjs.sequenceToTimelock(Number(params.refundDelay)),
1425
+ unilateralRefundWithoutReceiverDelay: chunkUUSKJOSX_cjs.sequenceToTimelock(
1850
1426
  Number(params.refundNoReceiverDelay)
1851
1427
  )
1852
1428
  };
1853
1429
  },
1854
1430
  /**
1855
- * Select spending path based on context.
1856
- *
1857
- * Role is determined from `context.role` or by matching
1858
- * `context.walletDescriptor`
1859
- * against sender/receiver in contract params.
1431
+ * Select spending path based on context. Role comes from `context.role` or from matching
1432
+ * `context.walletDescriptor` against sender/receiver.
1860
1433
  */
1861
1434
  selectPath(script, contract, context) {
1862
- const role = resolveRole(contract, context);
1863
- const preimage = contract.params?.preimage;
1864
- const refundLocktime = BigInt(contract.params.refundLocktime);
1865
- if (!role) {
1866
- return null;
1867
- }
1868
- if (context.collaborative) {
1869
- if (role === "receiver" && preimage) {
1870
- return {
1871
- leaf: script.claim(),
1872
- extraWitness: [base.hex.decode(preimage)]
1873
- };
1874
- }
1875
- if (role === "sender" && isCltvSatisfied(context, refundLocktime)) {
1876
- return {
1877
- leaf: script.refundWithoutReceiver()
1878
- };
1879
- }
1880
- return null;
1881
- }
1882
- if (role === "receiver" && preimage) {
1883
- const sequence = Number(contract.params.claimDelay);
1884
- if (!isCsvSpendable(context, sequence)) return null;
1885
- return {
1886
- leaf: script.unilateralClaim(),
1887
- extraWitness: [base.hex.decode(preimage)],
1888
- sequence
1889
- };
1890
- }
1891
- if (role === "sender") {
1892
- const sequence = Number(contract.params.refundNoReceiverDelay);
1893
- if (!isCsvSpendable(context, sequence)) return null;
1894
- return {
1895
- leaf: script.unilateralRefundWithoutReceiver(),
1896
- sequence
1897
- };
1898
- }
1899
- return null;
1435
+ return selectVhtlcPath(script, contract, context);
1900
1436
  },
1901
- /**
1902
- * Get all possible spending paths (no timelock checks).
1903
- *
1904
- * Role is determined from `context.role` or by matching
1905
- * `context.walletDescriptor`
1906
- * against sender/receiver in contract params.
1907
- */
1437
+ /** All possible spending paths (no timelock checks); role as in {@link selectPath}. */
1908
1438
  getAllSpendingPaths(script, contract, context) {
1909
- const role = resolveRole(contract, context);
1910
- const paths = [];
1911
- if (!role) {
1912
- return paths;
1913
- }
1914
- const preimage = contract.params?.preimage;
1915
- if (context.collaborative) {
1916
- if (role === "receiver" && preimage) {
1917
- paths.push({
1918
- leaf: script.claim(),
1919
- extraWitness: [base.hex.decode(preimage)]
1920
- });
1921
- }
1922
- if (role === "sender") {
1923
- paths.push({
1924
- leaf: script.refundWithoutReceiver()
1925
- });
1926
- }
1927
- } else {
1928
- if (role === "receiver" && preimage) {
1929
- const sequence = Number(contract.params.claimDelay);
1930
- paths.push({
1931
- leaf: script.unilateralClaim(),
1932
- extraWitness: [base.hex.decode(preimage)],
1933
- sequence
1934
- });
1935
- }
1936
- if (role === "sender") {
1937
- const sequence = Number(contract.params.refundNoReceiverDelay);
1938
- paths.push({
1939
- leaf: script.unilateralRefundWithoutReceiver(),
1940
- sequence
1941
- });
1942
- }
1943
- }
1944
- return paths;
1439
+ return vhtlcAllSpendingPaths(script, contract, context);
1945
1440
  },
1946
1441
  getSpendablePaths(script, contract, context) {
1947
- const role = resolveRole(contract, context);
1948
- const paths = [];
1949
- if (!role) {
1950
- return paths;
1951
- }
1952
- const preimage = contract.params?.preimage;
1953
- const refundLocktime = BigInt(contract.params.refundLocktime);
1954
- if (context.collaborative) {
1955
- if (role === "receiver" && preimage) {
1956
- paths.push({
1957
- leaf: script.claim(),
1958
- extraWitness: [base.hex.decode(preimage)]
1959
- });
1960
- }
1961
- if (role === "sender" && isCltvSatisfied(context, refundLocktime)) {
1962
- paths.push({
1963
- leaf: script.refundWithoutReceiver()
1964
- });
1965
- }
1966
- return paths;
1967
- }
1968
- if (role === "receiver" && preimage) {
1969
- const sequence = Number(contract.params.claimDelay);
1970
- if (isCsvSpendable(context, sequence)) {
1971
- paths.push({
1972
- leaf: script.unilateralClaim(),
1973
- extraWitness: [base.hex.decode(preimage)],
1974
- sequence
1975
- });
1976
- }
1977
- }
1978
- if (role === "sender") {
1979
- const sequence = Number(contract.params.refundNoReceiverDelay);
1980
- if (isCsvSpendable(context, sequence)) {
1981
- paths.push({
1982
- leaf: script.unilateralRefundWithoutReceiver(),
1983
- sequence
1984
- });
1985
- }
1986
- }
1987
- return paths;
1442
+ return vhtlcSpendablePaths(script, contract, context);
1988
1443
  },
1989
1444
  /**
1990
1445
  * Refuse an explicit spend of a lockup whose refund path has not opened.
@@ -1995,70 +1450,38 @@ var VHTLCContractHandler = {
1995
1450
  assertVhtlcSpendableNow(contract, context);
1996
1451
  },
1997
1452
  /**
1998
- * Never. A live VHTLC is escrow: the counterparty's claim leaf is armed,
1999
- * and generic selection — send, settle, renewal, offboard — would move the
2000
- * lockup out from under a swap the counterparty is still entitled to
2001
- * complete, or race a claim already in flight.
1453
+ * Never. A live VHTLC is escrow: generic selection (send, settle, renewal, offboard) would
1454
+ * move the lockup out from under a swap the counterparty may still complete, or race a claim.
2002
1455
  *
2003
- * Two narrow reasons, and neither is "spending this would destroy the
2004
- * VTXO". It would not: the leaf {@link deriveTapscripts} stamps is
2005
- * `refundWithoutReceiver` — `CLTV[sender, server]`, the sender's OWN
2006
- * refund, which the server rejects until `refundLocktime` matures. The
2007
- * reasons are that an escrowed lockup must not count toward the
2008
- * `available` balance bucket, and that generic RENEWAL must not silently
2009
- * execute a refund the caller never asked for — `runPeriodicSettle` selects
2010
- * through `getSpendableVtxos`, which this gate filters, and it runs
2011
- * unprompted whenever a wallet is built without an explicit
2012
- * `settlementConfig`.
1456
+ * The stamped leaf is the sender's own CLTV refund, so this is not about destroying the
1457
+ * VTXO: an escrowed lockup must not count toward the `available` balance, and generic
1458
+ * renewal (`runPeriodicSettle`, unprompted without an explicit `settlementConfig`) must not
1459
+ * silently execute a refund nobody asked for.
2013
1460
  *
2014
- * **Inseparable from {@link deriveTapscripts}.** Deriving the leaf without
2015
- * closing the gate hands generic renewal an escrow it had never been
2016
- * offered before; before that method existed the answer here was
2017
- * unobservable, so the two only ever made sense together.
2018
- *
2019
- * Recovery is filtered on {@link assertSpendableNow}, not on this: the gate
2020
- * is permanent, and applying it there would strand a matured lockup.
1461
+ * **Inseparable from {@link deriveTapscripts}**: deriving the leaf without closing this gate
1462
+ * hands renewal an escrow. Recovery filters on {@link assertSpendableNow} instead; this
1463
+ * permanent gate would strand a matured lockup.
2021
1464
  */
2022
1465
  isGenericallySpendable: () => false,
2023
1466
  /**
2024
1467
  * The annotation leaf stamped onto every VTXO locked to this contract.
2025
1468
  *
2026
- * **Without this the contract is unusable, not merely unoptimized.**
2027
- * `deriveContractTapscripts` falls back to `script.forfeit()` for any
2028
- * handler that does not implement {@link TapscriptDeriving}, and no VHTLC
2029
- * script version has a `forfeit()` — `VtxoScript` does not define one and
2030
- * `VHTLC.BaseScript` does not add one. The fallback therefore threw
2031
- * `legacy.forfeit is not a function`, `annotatableIn` caught it, and
2032
- * `fetchContractVtxosBulk` dropped this contract's VTXOs before they were
2033
- * persisted. The row existed and was watched while its balance stayed
2034
- * permanently invisible, and `getSyncState()` reported `degraded` forever.
2035
- *
2036
- * `refundWithoutReceiver` is the leaf, for both roles the annotation
2037
- * serves, because it is the only collaborative path this wallet can
2038
- * actually satisfy as the sender — the same conclusion `selectPath`
2039
- * reaches, kept in step with it deliberately. The claim leaves belong to
2040
- * the receiver and need a preimage the sender does not have; `refund` and
2041
- * `unilateralRefund` both need the counterparty's signature, which this
2042
- * protocol has no message to ask for. V1 has no covenant leaves at all.
1469
+ * **Required, not an optimization.** Without it `deriveContractTapscripts` falls back to
1470
+ * `script.forfeit()`, which no VHTLC script has, so the contract's VTXOs are dropped before
1471
+ * persisting: balance invisible, `getSyncState()` degraded forever.
2043
1472
  *
2044
- * **It carries a CLTV, and callers must respect it.** A settlement built
2045
- * on this leaf is only valid once `refundLocktime` has matured, so a
2046
- * recovery round that sweeps this VTXO early is rejected by the server.
2047
- * Nothing in this handler can enforce that, because the annotation is
2048
- * derived per contract and knows no clock; `recoverVtxos` filters on
2049
- * {@link assertSpendableNow} for it.
1473
+ * `refundWithoutReceiver` is the only collaborative path this wallet can satisfy as sender
1474
+ * (kept in step with `selectPath`): the claim leaves need the preimage, and `refund` /
1475
+ * `unilateralRefund` need a counterparty signature the protocol can't request. V1 has no
1476
+ * covenant leaves.
2050
1477
  *
2051
- * **Role-blind.** A receiver's row gets the same leaf, which names keys that
2052
- * wallet does not hold, so it is satisfiable only by the wallet holding the
2053
- * lockup's `sender` key and fails at intent registration for anyone else.
1478
+ * **It carries a CLTV**: a settlement on it is rejected until `refundLocktime` matures, and
1479
+ * the per-contract annotation knows no clock, so `recoverVtxos` filters on
1480
+ * {@link assertSpendableNow}. **Role-blind**: a receiver's row gets the same leaf, satisfiable
1481
+ * only by the `sender` key holder; anyone else fails at intent registration.
2054
1482
  */
2055
1483
  deriveTapscripts(script) {
2056
- const leaf = script.refundWithoutReceiver();
2057
- return {
2058
- forfeitTapLeafScript: leaf,
2059
- intentTapLeafScript: leaf,
2060
- tapTree: script.encode()
2061
- };
1484
+ return deriveVhtlcTapscripts(script);
2062
1485
  }
2063
1486
  };
2064
1487
  var parseGroupIndex = (raw) => {
@@ -2092,48 +1515,26 @@ var VHTLCV2ContractHandler = {
2092
1515
  server: base.hex.encode(params.server),
2093
1516
  hash: base.hex.encode(params.preimageHash),
2094
1517
  refundLocktime: params.refundLocktime.toString(),
2095
- claimDelay: chunkVTXMC4N7_cjs.timelockToSequence(params.unilateralClaimDelay).toString(),
2096
- refundDelay: chunkVTXMC4N7_cjs.timelockToSequence(params.unilateralRefundDelay).toString(),
2097
- refundNoReceiverDelay: chunkVTXMC4N7_cjs.timelockToSequence(
1518
+ claimDelay: chunkUUSKJOSX_cjs.timelockToSequence(params.unilateralClaimDelay).toString(),
1519
+ refundDelay: chunkUUSKJOSX_cjs.timelockToSequence(params.unilateralRefundDelay).toString(),
1520
+ refundNoReceiverDelay: chunkUUSKJOSX_cjs.timelockToSequence(
2098
1521
  params.unilateralRefundWithoutReceiverDelay
2099
1522
  ).toString(),
2100
- // The on-disk keys keep their per-leaf names even though the typed
2101
- // param is ONE group: rows written by older SDKs carry exactly
2102
- // these keys, and changing the storage encoding would orphan them.
2103
- // The group maps onto them without loss — one emulator key serves
2104
- // both covenant destinations by construction (see the option's doc
2105
- // on VHTLC.Options), so the two emulator-key columns always hold
2106
- // the same value on a row written from here.
2107
- //
2108
- // Spread rather than written as `undefined`: a `Record<string,
2109
- // string>` round-tripped through a repository must not gain keys
2110
- // whose value is the string "undefined".
1523
+ // Per-leaf on-disk keys predate the grouped param and older rows carry exactly these;
1524
+ // both emulator columns hold the same key. Spread, not `undefined`, so a repository
1525
+ // round-trip never gains "undefined" string values.
2111
1526
  ...covenants && {
2112
1527
  nonInteractiveClaimReceiverPkScript: base.hex.encode(covenants.receiverPkScript),
2113
1528
  nonInteractiveClaimEmulatorPubkey: base.hex.encode(covenants.emulatorPubkey),
2114
1529
  nonInteractiveRefundSenderPkScript: base.hex.encode(covenants.senderPkScript),
2115
1530
  nonInteractiveRefundEmulatorPubkey: base.hex.encode(covenants.emulatorPubkey),
2116
- // The legacy marker is precisely the ABSENCE of this key: a
2117
- // row carrying it re-derives the full suite (nine leaves), a
2118
- // row lacking it the pre-timelocked-refund eight — the same
2119
- // encoding older SDKs wrote for eight-leaf rows, so those rows
2120
- // read back unchanged. Spread rather than a "false"/"undefined"
2121
- // string: a dropped flag re-derives the EIGHT-leaf script, a
2122
- // different pkScript, and registration dies at
2123
- // `upsertContractRow` with an opaque `Script mismatch`.
1531
+ // The legacy (eight-leaf) marker is this key's ABSENCE, as older SDKs wrote it.
2124
1532
  ...covenants.legacy === void 0 && {
2125
1533
  nonInteractiveRefundWithoutReceiver: "1"
2126
1534
  }
2127
1535
  },
2128
- // The asset must round-trip, and its absence here used to be silent
2129
- // in the worst way. `ContractManager` re-derives a contract from
2130
- // these params; dropping the asset derives the SAT-ONLY script, so
2131
- // registration died at `upsertContractRow` with a `Script mismatch`
2132
- // naming two hex strings and no cause. Same silent-drop class
2133
- // `validateOptions` refuses one layer up.
2134
- //
2135
- // Two keys rather than one blob, mirroring the script's own view of
2136
- // an Asset ID as a (txid, groupIndex) pair.
1536
+ // Must round-trip: dropping the asset re-derives the sat-only script and registration
1537
+ // dies at `upsertContractRow` with an opaque `Script mismatch`.
2137
1538
  ...params.asset && {
2138
1539
  assetTxid: base.hex.encode(params.asset.txid),
2139
1540
  assetGroupIndex: params.asset.groupIndex.toString()
@@ -2194,9 +1595,9 @@ var VHTLCV2ContractHandler = {
2194
1595
  preimageHash: base.hex.decode(params.hash),
2195
1596
  refundLocktime: BigInt(params.refundLocktime),
2196
1597
  ...asset && { asset },
2197
- unilateralClaimDelay: chunkVTXMC4N7_cjs.sequenceToTimelock(Number(params.claimDelay)),
2198
- unilateralRefundDelay: chunkVTXMC4N7_cjs.sequenceToTimelock(Number(params.refundDelay)),
2199
- unilateralRefundWithoutReceiverDelay: chunkVTXMC4N7_cjs.sequenceToTimelock(
1598
+ unilateralClaimDelay: chunkUUSKJOSX_cjs.sequenceToTimelock(Number(params.claimDelay)),
1599
+ unilateralRefundDelay: chunkUUSKJOSX_cjs.sequenceToTimelock(Number(params.refundDelay)),
1600
+ unilateralRefundWithoutReceiverDelay: chunkUUSKJOSX_cjs.sequenceToTimelock(
2200
1601
  Number(params.refundNoReceiverDelay)
2201
1602
  ),
2202
1603
  ...claim && refund && {
@@ -2204,8 +1605,6 @@ var VHTLCV2ContractHandler = {
2204
1605
  receiverPkScript: claim.destination,
2205
1606
  senderPkScript: refund.destination,
2206
1607
  emulatorPubkey: claim.emulatorPubkey,
2207
- // Absence of the flag IS the legacy marker — the same
2208
- // encoding older SDKs wrote for eight-leaf rows.
2209
1608
  ...params.nonInteractiveRefundWithoutReceiver !== "1" && {
2210
1609
  legacy: "preTimelockedRefund"
2211
1610
  }
@@ -2214,139 +1613,18 @@ var VHTLCV2ContractHandler = {
2214
1613
  };
2215
1614
  },
2216
1615
  /**
2217
- * Select spending path based on context.
2218
- *
2219
- * Role is determined from `context.role` or by matching
2220
- * `context.walletDescriptor`
2221
- * against sender/receiver in contract params.
1616
+ * Select spending path based on context. Role comes from `context.role` or by matching
1617
+ * `context.walletDescriptor` against sender/receiver.
2222
1618
  */
2223
1619
  selectPath(script, contract, context) {
2224
- const role = resolveRole(contract, context);
2225
- const preimage = contract.params?.preimage;
2226
- const refundLocktime = BigInt(contract.params.refundLocktime);
2227
- if (!role) {
2228
- return null;
2229
- }
2230
- if (context.collaborative) {
2231
- if (role === "receiver" && preimage) {
2232
- return {
2233
- leaf: script.claim(),
2234
- extraWitness: [base.hex.decode(preimage)]
2235
- };
2236
- }
2237
- if (role === "sender" && isCltvSatisfied(context, refundLocktime)) {
2238
- return {
2239
- leaf: script.refundWithoutReceiver()
2240
- };
2241
- }
2242
- return null;
2243
- }
2244
- if (role === "receiver" && preimage) {
2245
- const sequence = Number(contract.params.claimDelay);
2246
- if (!isCsvSpendable(context, sequence)) return null;
2247
- return {
2248
- leaf: script.unilateralClaim(),
2249
- extraWitness: [base.hex.decode(preimage)],
2250
- sequence
2251
- };
2252
- }
2253
- if (role === "sender") {
2254
- const sequence = Number(contract.params.refundNoReceiverDelay);
2255
- if (!isCsvSpendable(context, sequence)) return null;
2256
- return {
2257
- leaf: script.unilateralRefundWithoutReceiver(),
2258
- sequence
2259
- };
2260
- }
2261
- return null;
1620
+ return selectVhtlcPath(script, contract, context);
2262
1621
  },
2263
- /**
2264
- * Get all possible spending paths (no timelock checks).
2265
- *
2266
- * Role is determined from `context.role` or by matching
2267
- * `context.walletDescriptor`
2268
- * against sender/receiver in contract params.
2269
- */
1622
+ /** Get all possible spending paths (no timelock checks); role resolved as in `selectPath`. */
2270
1623
  getAllSpendingPaths(script, contract, context) {
2271
- const role = resolveRole(contract, context);
2272
- const paths = [];
2273
- if (!role) {
2274
- return paths;
2275
- }
2276
- const preimage = contract.params?.preimage;
2277
- if (context.collaborative) {
2278
- if (role === "receiver" && preimage) {
2279
- paths.push({
2280
- leaf: script.claim(),
2281
- extraWitness: [base.hex.decode(preimage)]
2282
- });
2283
- }
2284
- if (role === "sender") {
2285
- paths.push({
2286
- leaf: script.refundWithoutReceiver()
2287
- });
2288
- }
2289
- } else {
2290
- if (role === "receiver" && preimage) {
2291
- const sequence = Number(contract.params.claimDelay);
2292
- paths.push({
2293
- leaf: script.unilateralClaim(),
2294
- extraWitness: [base.hex.decode(preimage)],
2295
- sequence
2296
- });
2297
- }
2298
- if (role === "sender") {
2299
- const sequence = Number(contract.params.refundNoReceiverDelay);
2300
- paths.push({
2301
- leaf: script.unilateralRefundWithoutReceiver(),
2302
- sequence
2303
- });
2304
- }
2305
- }
2306
- return paths;
1624
+ return vhtlcAllSpendingPaths(script, contract, context);
2307
1625
  },
2308
1626
  getSpendablePaths(script, contract, context) {
2309
- const role = resolveRole(contract, context);
2310
- const paths = [];
2311
- if (!role) {
2312
- return paths;
2313
- }
2314
- const preimage = contract.params?.preimage;
2315
- const refundLocktime = BigInt(contract.params.refundLocktime);
2316
- if (context.collaborative) {
2317
- if (role === "receiver" && preimage) {
2318
- paths.push({
2319
- leaf: script.claim(),
2320
- extraWitness: [base.hex.decode(preimage)]
2321
- });
2322
- }
2323
- if (role === "sender" && isCltvSatisfied(context, refundLocktime)) {
2324
- paths.push({
2325
- leaf: script.refundWithoutReceiver()
2326
- });
2327
- }
2328
- return paths;
2329
- }
2330
- if (role === "receiver" && preimage) {
2331
- const sequence = Number(contract.params.claimDelay);
2332
- if (isCsvSpendable(context, sequence)) {
2333
- paths.push({
2334
- leaf: script.unilateralClaim(),
2335
- extraWitness: [base.hex.decode(preimage)],
2336
- sequence
2337
- });
2338
- }
2339
- }
2340
- if (role === "sender") {
2341
- const sequence = Number(contract.params.refundNoReceiverDelay);
2342
- if (isCsvSpendable(context, sequence)) {
2343
- paths.push({
2344
- leaf: script.unilateralRefundWithoutReceiver(),
2345
- sequence
2346
- });
2347
- }
2348
- }
2349
- return paths;
1627
+ return vhtlcSpendablePaths(script, contract, context);
2350
1628
  },
2351
1629
  /**
2352
1630
  * Refuse an explicit spend of a lockup whose refund path has not opened.
@@ -2356,62 +1634,28 @@ var VHTLCV2ContractHandler = {
2356
1634
  assertVhtlcSpendableNow(contract, context);
2357
1635
  },
2358
1636
  /**
2359
- * Never. A live VHTLC is escrow: the counterparty's claim leaf is armed,
2360
- * and generic selection — send, settle, RENEWAL, offboard — would move the
2361
- * lockup out from under a swap the counterparty is still entitled to
2362
- * complete, or race a claim already in flight. The `vhtlc` handler now
2363
- * answers the same, for the same reason.
2364
- *
2365
- * The gate covers `available` and renewal. Recovery is generic and names
2366
- * nothing, so it is not covered here: `recoverVtxos` filters on
2367
- * {@link assertSpendableNow} instead, which drops a lockup only while its
2368
- * refund path is shut rather than forever. The explicit routes out —
2369
- * `settle({ inputs })`, or `@arkade-os/swap`'s `pushRefundWithoutReceiver`
2370
- * over `findLockupVtxos`' outpoints — are unaffected either way.
1637
+ * Never. A live VHTLC is escrow with the counterparty's claim leaf armed; generic selection
1638
+ * (send, settle, renewal, offboard) would move it out from under the swap or race a claim.
1639
+ * Recovery isn't covered by this gate: `recoverVtxos` filters on {@link assertSpendableNow},
1640
+ * dropping a lockup only while its refund path is shut. Explicit routes (`settle({ inputs })`,
1641
+ * `pushRefundWithoutReceiver`) are unaffected.
2371
1642
  */
2372
1643
  isGenericallySpendable: () => false,
2373
1644
  /**
2374
1645
  * The annotation leaf stamped onto every VTXO locked to this contract.
2375
1646
  *
2376
- * **Without this the contract is unusable, not merely unoptimized.**
2377
- * `deriveContractTapscripts` falls back to `script.forfeit()` for any
2378
- * handler that does not implement {@link TapscriptDeriving}, and no VHTLC
2379
- * script version has a `forfeit()` — `VtxoScript` does not define one and
2380
- * `VHTLC.BaseScript` does not add one. The fallback therefore throws
2381
- * `legacy.forfeit is not a function`, `annotatableIn` catches it, and
2382
- * `fetchContractVtxosBulk` drops this contract's VTXOs before they are
2383
- * persisted. The row would exist and be watched while its balance stayed
2384
- * permanently invisible, and `getSyncState()` would report `degraded`
2385
- * forever. (The `vhtlc` handler had the same gap and now closes it the same
2386
- * way; nothing registers V1 rows through `ContractManager` in this repo, so
2387
- * it was never hit here.)
2388
- *
2389
- * `refundWithoutReceiver` is the leaf, for both roles the annotation
2390
- * serves, because it is the only collaborative path this wallet can
2391
- * actually satisfy as the sender — the same conclusion `selectPath`
2392
- * reaches, kept in step with it deliberately. The claim leaves belong to
2393
- * the receiver and need a preimage the sender does not have; `refund` and
2394
- * `unilateralRefund` need the counterparty; the covenant leaves are the
2395
- * emulator's.
2396
- *
2397
- * **It carries a CLTV, and callers must respect it.** A settlement built on
2398
- * this leaf is only valid once `refundLocktime` has matured, so a recovery
2399
- * round that sweeps this VTXO early is rejected by the server. Nothing in
2400
- * this handler can enforce it, because the annotation is derived per
2401
- * contract and knows no clock. `recoverVtxos` filters on
2402
- * {@link assertSpendableNow} for it.
1647
+ * Required, not an optimization: without {@link TapscriptDeriving} the fallback calls
1648
+ * `script.forfeit()`, which no VHTLC version has, so the VTXOs are silently dropped before
1649
+ * persisting and `getSyncState()` stays `degraded`.
2403
1650
  *
2404
- * **Role-blind.** A receiver's row gets the same leaf, which names keys that
2405
- * wallet does not hold, so it is satisfiable only by the wallet holding the
2406
- * lockup's `sender` key and fails at intent registration for anyone else.
1651
+ * `refundWithoutReceiver` is used (in step with `selectPath`) as the only collaborative leaf
1652
+ * the sender can satisfy. It carries a CLTV: settling on it before `refundLocktime` matures is
1653
+ * rejected, and this handler has no clock, so `recoverVtxos` filters on
1654
+ * {@link assertSpendableNow}. Role-blind: a receiver's row gets the same leaf and fails at
1655
+ * intent registration.
2407
1656
  */
2408
1657
  deriveTapscripts(script) {
2409
- const leaf = script.refundWithoutReceiver();
2410
- return {
2411
- forfeitTapLeafScript: leaf,
2412
- intentTapLeafScript: leaf,
2413
- tapTree: script.encode()
2414
- };
1658
+ return deriveVhtlcTapscripts(script);
2415
1659
  }
2416
1660
  };
2417
1661
  var BoardingContractHandler = {
@@ -2437,24 +1681,10 @@ var BoardingContractHandler = {
2437
1681
  /** Preserves today's settle/board behaviour. */
2438
1682
  isGenericallySpendable: () => true,
2439
1683
  /**
2440
- * Probe the on-chain UTXO set for a boarding output at this HD index.
2441
- *
2442
- * Boarding's source of truth is the **current** on-chain coin set
2443
- * (`OnchainProvider.getCoins`), not the Ark indexer: a boarded (spent)
2444
- * boarding output becomes an L2 VTXO at the receive index, so the
2445
- * indexer probe already keeps the gap window open for it; only an
2446
- * *unspent* boarding output needs the on-chain probe (see plan §2).
2447
- *
2448
- * No-ops (returns `[]`) when boarding discovery is not plumbed — i.e.
2449
- * `deps.boardingTimelock` or `deps.onchainNetwork` is absent — so the
2450
- * scanner unit harness (which sets neither) is unaffected.
2451
- *
2452
- * Always emits `type: "boarding"`, even in the degenerate equal-delay case
2453
- * where the boarding script is byte-identical to a `default` script at this
2454
- * index (`boardingExitDelay === unilateralExitDelay`). The collision is no
2455
- * longer pre-judged in discovery; it is tolerated FIRST-WINS at the
2456
- * persistence layer ({@link ContractManager.upsertContract}). `deps.csvTimelocks`
2457
- * is intentionally not read here.
1684
+ * Probe the **current** on-chain coin set for a boarding output at this HD index. Only an
1685
+ * unspent boarding output needs this: a boarded one became an L2 VTXO at the receive index,
1686
+ * which the indexer probe already covers. Always emits `type: "boarding"` (see the handler
1687
+ * doc on collisions); `deps.csvTimelocks` is intentionally not read.
2458
1688
  */
2459
1689
  async discoverAt(index, descriptor, deps) {
2460
1690
  if (!deps.boardingTimelock || !deps.onchainNetwork) return [];
@@ -2468,38 +1698,49 @@ var BoardingContractHandler = {
2468
1698
  const coins = await deps.onchainProvider.getCoins(onchainAddress);
2469
1699
  if (coins.length === 0) return [];
2470
1700
  const scriptHex = base.hex.encode(script.pkScript);
2471
- const boardingSeq = chunkVTXMC4N7_cjs.timelockToSequence(deps.boardingTimelock);
2472
1701
  return [
2473
1702
  {
2474
1703
  type: "boarding",
2475
- params: {
2476
- pubKey: base.hex.encode(pubKey),
2477
- serverPubKey: base.hex.encode(deps.serverPubKey),
2478
- csvTimelock: boardingSeq.toString()
2479
- },
1704
+ params: BoardingContractHandler.serializeParams({
1705
+ pubKey,
1706
+ serverPubKey: deps.serverPubKey,
1707
+ csvTimelock: deps.boardingTimelock
1708
+ }),
2480
1709
  script: scriptHex,
2481
- // The persisted row's `address` is the *Ark* address (not the
2482
- // on-chain P2TR), matching the row registered at init so the
2483
- // ContractWatcher keeps monitoring the same L2 script and the
2484
- // VTXO repository bucket lines up (plan §6-I.4). The P2TR is
2485
- // recomputed from params only for the `getCoins` probe.
1710
+ // The Ark address, not the P2TR: must match the row registered at init so the
1711
+ // watcher monitors the same L2 script and the VTXO repository bucket lines up.
2486
1712
  address: script.address(deps.network.hrp, deps.serverPubKey).encode(),
2487
- // Tag rotated rows (index > 0) so boot resolution can find the
2488
- // newest boarding address and descriptor-aware signing can
2489
- // recover the per-index key (plan §6-II/§6-III.3). The index-0
2490
- // baseline stays untagged, matching `default`/`delegate`.
1713
+ // Tag rotated rows (index > 0) for boot resolution and per-index signing.
2491
1714
  ...rotatedReceiveMetadata(index, descriptor)
2492
1715
  }
2493
1716
  ];
2494
1717
  }
2495
1718
  };
2496
1719
  var MinimalScriptNum = btcSigner.ScriptNum(void 0, true);
2497
- var SUPPORTED_PROGRAM_VERSION = 0;
2498
- function inputName(ref) {
2499
- return typeof ref === "string" ? ref : ref.name;
2500
- }
1720
+ var ARKADE_TYPE_ENCODINGS = {
1721
+ pubkey: "raw",
1722
+ signature: "schnorr-64",
1723
+ bytes: "raw",
1724
+ bytes20: "raw-20",
1725
+ bytes32: "raw-32",
1726
+ asset: "raw-32",
1727
+ int: "scriptnum",
1728
+ bool: "scriptnum",
1729
+ AssetGroup: "scriptnum"
1730
+ };
1731
+ var SUPPORTED_PROGRAM_VERSION = 1;
1732
+ var UnsupportedProgramVersionError = class extends Error {
1733
+ constructor(version, context) {
1734
+ super(
1735
+ `${context}: unsupported program version ${String(version)}; this SDK supports version ${SUPPORTED_PROGRAM_VERSION}. Recover it with an SDK that reads version ${String(version)}, re-create it with current params, or delete it.`
1736
+ );
1737
+ this.version = version;
1738
+ }
1739
+ version;
1740
+ name = "UnsupportedProgramVersionError";
1741
+ };
2501
1742
  function bindValue(bind, name) {
2502
- const v = bind[name];
1743
+ const v = Object.hasOwn(bind, name) ? bind[name] : void 0;
2503
1744
  if (v === void 0) throw new Error(`unbound parameter '${name}'`);
2504
1745
  return v;
2505
1746
  }
@@ -2514,6 +1755,17 @@ function resolveTimelockValue(value, args) {
2514
1755
  `invalid timelock value '${value}' \u2014 expected a bigint or a '$param' reference`
2515
1756
  );
2516
1757
  }
1758
+ function resolveCsvTimelock(csv, args) {
1759
+ const value = resolveTimelockValue(csv.value, args);
1760
+ if (csv.type !== "sequence") return { type: csv.type, value };
1761
+ const timelock = chunkUUSKJOSX_cjs.sequenceToCanonicalTimelock(value);
1762
+ if (!timelock) {
1763
+ throw new Error(
1764
+ `csv '${csv.value}' resolved to ${value}, which is not a canonical BIP68 sequence`
1765
+ );
1766
+ }
1767
+ return timelock;
1768
+ }
2517
1769
  function resolveAsm(asm, bind) {
2518
1770
  const tokens = asm.map((t) => {
2519
1771
  if (typeof t === "string" && t.startsWith("$")) {
@@ -2562,6 +1814,7 @@ function collectParamRefs(program) {
2562
1814
  const collect = (items) => {
2563
1815
  for (const t of items ?? []) {
2564
1816
  if (typeof t === "string" && t.startsWith("$")) refs.add(t.slice(1));
1817
+ else if (isTweakedSigner(t) && t.tweak.startsWith("$")) refs.add(t.tweak.slice(1));
2565
1818
  }
2566
1819
  };
2567
1820
  for (const fn of Object.values(program.functions)) {
@@ -2576,11 +1829,28 @@ function collectParamRefs(program) {
2576
1829
  }
2577
1830
  return refs;
2578
1831
  }
2579
- var TYPED_BYTE_LENGTHS = { pubkey: 32, sig: 64 };
1832
+ var TYPED_BYTE_LENGTHS = {
1833
+ pubkey: 32,
1834
+ signature: 64,
1835
+ bytes20: 20,
1836
+ bytes32: 32,
1837
+ asset: 32
1838
+ };
2580
1839
  function validateParamValue(def, value) {
2581
- if (def.type === "int") {
1840
+ if (typeof def.type !== "string" || !Object.hasOwn(ARKADE_TYPE_ENCODINGS, def.type)) {
1841
+ throw new Error(`program parameter '${def.name}': unknown type '${def.type}'`);
1842
+ }
1843
+ if (ARKADE_TYPE_ENCODINGS[def.type] === "scriptnum") {
2582
1844
  if (typeof value !== "bigint" && typeof value !== "number") {
2583
- throw new Error(`program parameter '${def.name}' expects an int, got bytes`);
1845
+ throw new Error(`program parameter '${def.name}' expects ${def.type}, got bytes`);
1846
+ }
1847
+ if (typeof value === "number" && !Number.isSafeInteger(value)) {
1848
+ throw new Error(
1849
+ `program parameter '${def.name}' expects a safe integer; use bigint for larger values`
1850
+ );
1851
+ }
1852
+ if (def.type === "bool" && value !== 0 && value !== 1 && value !== 0n && value !== 1n) {
1853
+ throw new Error(`program parameter '${def.name}' expects a boolean encoded as 0 or 1`);
2584
1854
  }
2585
1855
  return;
2586
1856
  }
@@ -2597,11 +1867,10 @@ function validateParamValue(def, value) {
2597
1867
  }
2598
1868
  }
2599
1869
  function validateProgram(program, args) {
2600
- const params = program.params;
2601
- if (!params || !params.some((p) => typeof p !== "string")) return;
2602
- const declared = new Set(params.map(inputName));
1870
+ const params = program.params ?? [];
1871
+ const declared = new Set(params.map((p) => p.name));
2603
1872
  for (const name of declared) {
2604
- if (args[name] === void 0) {
1873
+ if (!Object.hasOwn(args, name) || args[name] === void 0) {
2605
1874
  throw new Error(`program parameter '${name}' is declared but not bound in args`);
2606
1875
  }
2607
1876
  }
@@ -2611,13 +1880,21 @@ function validateProgram(program, args) {
2611
1880
  }
2612
1881
  }
2613
1882
  for (const p of params) {
2614
- if (typeof p !== "string") validateParamValue(p, args[p.name]);
1883
+ validateParamValue(p, args[p.name]);
1884
+ }
1885
+ for (const name of Object.keys(args)) {
1886
+ if (!declared.has(name)) throw new Error(`program: undeclared argument '${name}'`);
2615
1887
  }
2616
1888
  }
1889
+ function isTweakedSigner(ref) {
1890
+ if (typeof ref !== "object" || ref === null || ref instanceof Uint8Array) return false;
1891
+ const { tweak, fn } = ref;
1892
+ return typeof tweak === "string" && typeof fn === "string";
1893
+ }
2617
1894
  function resolveSigner(ref, args) {
2618
1895
  if (ref instanceof Uint8Array) return ref;
2619
- if (!ref.startsWith("$")) {
2620
- throw new Error(`unknown signer reference '${ref}' \u2014 use '$${ref}'`);
1896
+ if (typeof ref !== "string" || !ref.startsWith("$")) {
1897
+ throw new Error(`unknown signer reference '${ref}' \u2014 use a '$param' or key bytes`);
2621
1898
  }
2622
1899
  const v = bindValue(args, ref.slice(1));
2623
1900
  if (!(v instanceof Uint8Array)) {
@@ -2627,35 +1904,33 @@ function resolveSigner(ref, args) {
2627
1904
  }
2628
1905
  function encodeTapscriptSegment(seg, pubkeys, args) {
2629
1906
  if (seg.csv) {
2630
- const timelock = { type: seg.csv.type, value: resolveTimelockValue(seg.csv.value, args) };
1907
+ const timelock = resolveCsvTimelock(seg.csv, args);
2631
1908
  if (seg.asm) {
2632
- return chunkVTXMC4N7_cjs.ConditionCSVMultisigTapscript.encode({
1909
+ return chunkUUSKJOSX_cjs.ConditionCSVMultisigTapscript.encode({
2633
1910
  conditionScript: resolveAsm(seg.asm, args),
2634
1911
  timelock,
2635
1912
  pubkeys
2636
1913
  });
2637
1914
  }
2638
- return chunkVTXMC4N7_cjs.CSVMultisigTapscript.encode({ timelock, pubkeys });
1915
+ return chunkUUSKJOSX_cjs.CSVMultisigTapscript.encode({ timelock, pubkeys });
2639
1916
  }
2640
1917
  if (seg.cltv !== void 0) {
2641
- return chunkVTXMC4N7_cjs.CLTVMultisigTapscript.encode({
1918
+ return chunkUUSKJOSX_cjs.CLTVMultisigTapscript.encode({
2642
1919
  absoluteTimelock: resolveTimelockValue(seg.cltv, args),
2643
1920
  pubkeys
2644
1921
  });
2645
1922
  }
2646
1923
  if (seg.asm) {
2647
- return chunkVTXMC4N7_cjs.ConditionMultisigTapscript.encode({
1924
+ return chunkUUSKJOSX_cjs.ConditionMultisigTapscript.encode({
2648
1925
  conditionScript: resolveAsm(seg.asm, args),
2649
1926
  pubkeys
2650
1927
  });
2651
1928
  }
2652
- return chunkVTXMC4N7_cjs.MultisigTapscript.encode({ pubkeys });
1929
+ return chunkUUSKJOSX_cjs.MultisigTapscript.encode({ pubkeys });
2653
1930
  }
2654
1931
  function compileFunctions(program, args, keys) {
2655
1932
  if (program.version !== SUPPORTED_PROGRAM_VERSION) {
2656
- throw new Error(
2657
- `ArkadeContract: unsupported program version ${program.version} \u2014 this SDK supports version ${SUPPORTED_PROGRAM_VERSION}`
2658
- );
1933
+ throw new UnsupportedProgramVersionError(program.version, "ArkadeContract");
2659
1934
  }
2660
1935
  const functions = program.functions;
2661
1936
  const names = Object.keys(functions);
@@ -2663,23 +1938,74 @@ function compileFunctions(program, args, keys) {
2663
1938
  throw new Error("ArkadeContract: program has no functions");
2664
1939
  }
2665
1940
  validateProgram(program, args);
1941
+ if (args.server !== void 0 && (!(args.server instanceof Uint8Array) || !utils_js$1.equalBytes(args.server, keys.serverKey))) {
1942
+ throw new Error(
1943
+ "ArkadeContract: reserved server parameter must match the contract server key"
1944
+ );
1945
+ }
2666
1946
  const defs = names.map((n) => functions[n]);
2667
- const covenant = names.find((_, i) => defs[i].arkadeScript);
1947
+ const covenants = /* @__PURE__ */ new Map();
1948
+ for (const [name, def] of Object.entries(functions)) {
1949
+ if (!def.arkadeScript) continue;
1950
+ const script = resolveAsm(def.arkadeScript.asm, args);
1951
+ for (const target of [name, ...def.group ? [def.group] : []]) {
1952
+ const previous = covenants.get(target);
1953
+ if (previous && !utils_js$1.equalBytes(previous, script)) {
1954
+ throw new Error(`ArkadeContract: ambiguous covenant '${target}'`);
1955
+ }
1956
+ covenants.set(target, script);
1957
+ }
1958
+ }
1959
+ const covenant = names.find(
1960
+ (_, i) => defs[i].arkadeScript && defs[i].tapscript.emulator !== null
1961
+ );
2668
1962
  if (covenant && !keys.emulatorKey) {
2669
1963
  throw new Error(
2670
1964
  `ArkadeContract: function '${covenant}' has an arkadeScript but no emulator is configured \u2014 pass an \`emulator\` to Arkade.connect`
2671
1965
  );
2672
1966
  }
2673
1967
  return defs.map((def, i) => {
2674
- validateTapscript(def.tapscript);
2675
- const pubkeys = def.tapscript.signers.map((s) => resolveSigner(s, args));
2676
- const arkadeScript = def.arkadeScript ? resolveAsm(def.arkadeScript.asm, args) : void 0;
2677
- const leafPubkeys = arkadeScript ? [...pubkeys, computeArkadeScriptPublicKey(keys.emulatorKey, arkadeScript)] : pubkeys;
1968
+ const pubkeys = def.tapscript.signers.map((signer) => {
1969
+ if (!isTweakedSigner(signer)) return resolveSigner(signer, args);
1970
+ const script = covenants.get(signer.fn);
1971
+ if (!script) {
1972
+ throw new Error(
1973
+ `ArkadeContract: function '${names[i]}' tweaks '${signer.fn}', which has no arkade script`
1974
+ );
1975
+ }
1976
+ return computeArkadeScriptPublicKey(resolveSigner(signer.tweak, args), script);
1977
+ });
1978
+ const arkadeScript = def.arkadeScript ? covenants.get(names[i]) : void 0;
1979
+ const leafPubkeys = [...pubkeys];
1980
+ if (arkadeScript && def.tapscript.emulator !== null) {
1981
+ const position = def.tapscript.emulatorIndex ?? pubkeys.length;
1982
+ if (!Number.isInteger(position) || position < 0 || position > pubkeys.length) {
1983
+ throw new Error(
1984
+ `ArkadeContract: function '${names[i]}' has an invalid emulator position ${position}`
1985
+ );
1986
+ }
1987
+ const target = def.group ? covenants.get(def.tapscript.emulator ?? def.group) : arkadeScript;
1988
+ if (!target || !utils_js$1.equalBytes(target, arkadeScript)) {
1989
+ throw new Error(
1990
+ `ArkadeContract: function '${names[i]}' has an invalid emulator covenant '${def.tapscript.emulator}'`
1991
+ );
1992
+ }
1993
+ leafPubkeys.splice(
1994
+ position,
1995
+ 0,
1996
+ computeArkadeScriptPublicKey(keys.emulatorKey, target)
1997
+ );
1998
+ } else if (def.tapscript.emulatorIndex !== void 0) {
1999
+ throw new Error(
2000
+ `ArkadeContract: function '${names[i]}' specifies an emulator position without an emulator`
2001
+ );
2002
+ }
2003
+ validateTapscript({ ...def.tapscript, signers: leafPubkeys });
2678
2004
  const leafScript = encodeTapscriptSegment(def.tapscript, leafPubkeys, args).script;
2679
2005
  return { name: names[i], def, leafScript, arkadeScript, signerKeys: pubkeys };
2680
2006
  });
2681
2007
  }
2682
- var ArkadeProgramScript = class extends chunkVTXMC4N7_cjs.VtxoScript {
2008
+ var ArkadeProgramScript = class extends chunkUUSKJOSX_cjs.VtxoScript {
2683
2009
  constructor(program, args, keys) {
2684
2010
  const partial = compileFunctions(program, args, keys);
2685
2011
  super(partial.map((p) => p.leafScript));
@@ -2702,23 +2028,72 @@ var ArkadeProgramScript = class extends chunkVTXMC4N7_cjs.VtxoScript {
2702
2028
  }
2703
2029
  };
2704
2030
  function parseArtifact(artifact) {
2031
+ if (Array.isArray(artifact.functions)) {
2032
+ throw new Error(
2033
+ "parseArtifact: `functions` is an array, which is the arkadec artifact shape, not an SDK program \u2014 read it with programFromArtifact instead"
2034
+ );
2035
+ }
2036
+ if (typeof artifact.functions !== "object" || artifact.functions === null) {
2037
+ throw new Error("parseArtifact: `functions` must be an object keyed by function name");
2038
+ }
2705
2039
  const hexToken = (t) => typeof t === "string" && t.startsWith("0x") ? base.hex.decode(t.slice(2)) : t;
2040
+ const signerRef = (s) => {
2041
+ if (s instanceof Uint8Array || typeof s === "string") return hexToken(s);
2042
+ if (isTweakedSigner(s)) return { tweak: s.tweak, fn: s.fn };
2043
+ throw new Error("parseArtifact: a tweaked signer needs string `tweak` and `fn`");
2044
+ };
2706
2045
  const timelockValue = (v) => typeof v === "string" && v.startsWith("$") ? v : BigInt(v);
2707
- const functions = {};
2046
+ if (artifact.version !== void 0 && artifact.version !== SUPPORTED_PROGRAM_VERSION) {
2047
+ throw new UnsupportedProgramVersionError(artifact.version, "parseArtifact");
2048
+ }
2049
+ const declarations = [artifact.params];
2050
+ for (const [name, fn] of Object.entries(artifact.functions)) {
2051
+ if (!fn || typeof fn !== "object" || Array.isArray(fn)) {
2052
+ throw new Error(`parseArtifact: function '${name}' must be an object`);
2053
+ }
2054
+ const tap = fn.tapscript;
2055
+ if (tap !== void 0 && (!tap || typeof tap !== "object" || Array.isArray(tap))) {
2056
+ throw new Error(`parseArtifact: function '${name}' tapscript must be an object`);
2057
+ }
2058
+ declarations.push(fn.inputs, tap?.signatures);
2059
+ if (tap?.emulatorIndex !== void 0 && (!Number.isInteger(tap.emulatorIndex) || tap.emulatorIndex < 0)) {
2060
+ throw new Error(`parseArtifact: function '${name}' has an invalid emulator position`);
2061
+ }
2062
+ }
2063
+ for (const defs of declarations) {
2064
+ if (defs === void 0) continue;
2065
+ if (!Array.isArray(defs)) {
2066
+ throw new Error(
2067
+ "parseArtifact: parameters, inputs and signatures require arrays of typed declarations"
2068
+ );
2069
+ }
2070
+ for (const def of defs) {
2071
+ if (!def || typeof def.name !== "string" || def.name.length === 0 || typeof def.type !== "string" || !Object.hasOwn(ARKADE_TYPE_ENCODINGS, def.type)) {
2072
+ throw new Error(
2073
+ "parseArtifact: parameters, inputs and signatures require typed { name, type } declarations"
2074
+ );
2075
+ }
2076
+ }
2077
+ }
2078
+ const functions = /* @__PURE__ */ Object.create(null);
2708
2079
  for (const [name, fn] of Object.entries(artifact.functions)) {
2709
2080
  const tap = fn.tapscript ?? {};
2710
2081
  const tapscript = {
2711
- signers: (tap.signers ?? []).map(hexToken),
2082
+ signers: (tap.signers ?? []).map(signerRef),
2083
+ ...tap.signatures ? { signatures: tap.signatures } : {},
2712
2084
  ...tap.asm ? { asm: tap.asm.map(hexToken) } : {},
2713
2085
  ...tap.witness ? { witness: tap.witness.map(hexToken) } : {},
2714
2086
  ...tap.csv ? { csv: { type: tap.csv.type, value: timelockValue(tap.csv.value) } } : {},
2715
- ...tap.cltv !== void 0 ? { cltv: timelockValue(tap.cltv) } : {}
2087
+ ...tap.cltv !== void 0 ? { cltv: timelockValue(tap.cltv) } : {},
2088
+ ..."emulator" in tap ? { emulator: tap.emulator } : {},
2089
+ ...tap.emulatorIndex !== void 0 ? { emulatorIndex: tap.emulatorIndex } : {}
2716
2090
  };
2717
2091
  const arkadeScript = fn.arkadeScript ? {
2718
2092
  asm: fn.arkadeScript.asm.map(hexToken),
2719
2093
  ...fn.arkadeScript.witness ? { witness: fn.arkadeScript.witness.map(hexToken) } : {}
2720
2094
  } : void 0;
2721
2095
  functions[name] = {
2096
+ ...fn.group !== void 0 ? { group: fn.group } : {},
2722
2097
  ...fn.inputs ? { inputs: fn.inputs } : {},
2723
2098
  tapscript,
2724
2099
  ...arkadeScript ? { arkadeScript } : {}
@@ -2742,17 +2117,21 @@ function stringifyArtifact(program) {
2742
2117
  }
2743
2118
  return t;
2744
2119
  };
2745
- const functions = {};
2120
+ const functions = /* @__PURE__ */ Object.create(null);
2746
2121
  for (const [name, fn] of Object.entries(program.functions)) {
2747
2122
  const tap = fn.tapscript;
2748
2123
  functions[name] = {
2124
+ ...fn.group !== void 0 ? { group: fn.group } : {},
2749
2125
  ...fn.inputs ? { inputs: fn.inputs } : {},
2750
2126
  tapscript: {
2751
2127
  signers: tap.signers.map(token),
2128
+ ...tap.signatures ? { signatures: tap.signatures } : {},
2752
2129
  ...tap.asm ? { asm: tap.asm.map(token) } : {},
2753
2130
  ...tap.witness ? { witness: tap.witness.map(token) } : {},
2754
2131
  ...tap.csv ? { csv: { type: tap.csv.type, value: tap.csv.value.toString() } } : {},
2755
- ...tap.cltv !== void 0 ? { cltv: tap.cltv.toString() } : {}
2132
+ ...tap.cltv !== void 0 ? { cltv: tap.cltv.toString() } : {},
2133
+ ...tap.emulator !== void 0 ? { emulator: tap.emulator } : {},
2134
+ ...tap.emulatorIndex !== void 0 ? { emulatorIndex: tap.emulatorIndex } : {}
2756
2135
  },
2757
2136
  ...fn.arkadeScript ? {
2758
2137
  arkadeScript: {
@@ -2774,20 +2153,12 @@ function serializeArgValue(v) {
2774
2153
  if (typeof v === "bigint") return v.toString();
2775
2154
  return v;
2776
2155
  }
2777
- function parseArgValue(v) {
2778
- if (typeof v === "number") return v;
2779
- if (typeof v === "string") {
2780
- if (v.startsWith("0x")) return base.hex.decode(v.slice(2));
2781
- return BigInt(v);
2782
- }
2783
- throw new Error(`invalid arkade arg value: ${JSON.stringify(v)}`);
2784
- }
2785
2156
  function parseTypedArgValue(name, type, v) {
2786
- if (type === "int") {
2157
+ if (ARKADE_TYPE_ENCODINGS[type] === "scriptnum") {
2787
2158
  if (typeof v === "number") return v;
2788
2159
  if (typeof v === "string") return BigInt(v);
2789
2160
  throw new Error(
2790
- `arkade contract params: '${name}' expects an int, got ${JSON.stringify(v)}`
2161
+ `arkade contract params: '${name}' expects ${type}, got ${JSON.stringify(v)}`
2791
2162
  );
2792
2163
  }
2793
2164
  if (typeof v === "string" && v.startsWith("0x")) return base.hex.decode(v.slice(2));
@@ -2796,7 +2167,7 @@ function parseTypedArgValue(name, type, v) {
2796
2167
  );
2797
2168
  }
2798
2169
  function serializeArkadeContractParams(typed) {
2799
- const args = {};
2170
+ const args = /* @__PURE__ */ Object.create(null);
2800
2171
  for (const [k, v] of Object.entries(typed.args)) {
2801
2172
  args[k] = serializeArgValue(v);
2802
2173
  }
@@ -2816,15 +2187,13 @@ function deserializeArkadeContractParams(params) {
2816
2187
  throw new Error("arkade contract params: missing 'serverKey'");
2817
2188
  }
2818
2189
  const program = parseArtifact(JSON.parse(params.program));
2819
- const paramTypes = /* @__PURE__ */ new Map();
2820
- for (const p of program.params ?? []) {
2821
- if (typeof p !== "string") paramTypes.set(p.name, p.type);
2822
- }
2823
- const args = {};
2190
+ const paramTypes = new Map((program.params ?? []).map((p) => [p.name, p.type]));
2191
+ const args = /* @__PURE__ */ Object.create(null);
2824
2192
  if (params.args) {
2825
2193
  for (const [k, v] of Object.entries(JSON.parse(params.args))) {
2826
2194
  const type = paramTypes.get(k);
2827
- args[k] = type ? parseTypedArgValue(k, type, v) : parseArgValue(v);
2195
+ if (!type) throw new Error(`arkade contract params: undeclared argument '${k}'`);
2196
+ args[k] = parseTypedArgValue(k, type, v);
2828
2197
  }
2829
2198
  }
2830
2199
  return {
@@ -2868,7 +2237,7 @@ function pathsFor(script, context, opts) {
2868
2237
  continue;
2869
2238
  }
2870
2239
  const csvDef = fn.def.tapscript.csv;
2871
- const csv = csvDef ? { type: csvDef.type, value: resolveTimelockValue(csvDef.value, script.args) } : void 0;
2240
+ const csv = csvDef ? resolveCsvTimelock(csvDef, script.args) : void 0;
2872
2241
  const cltv = fn.def.tapscript.cltv !== void 0 ? resolveTimelockValue(fn.def.tapscript.cltv, script.args) : void 0;
2873
2242
  if (context.collaborative) {
2874
2243
  if (csv) continue;
@@ -2882,7 +2251,7 @@ function pathsFor(script, context, opts) {
2882
2251
  continue;
2883
2252
  }
2884
2253
  if (requiresServer) continue;
2885
- const sequence = csv ? Number(chunkVTXMC4N7_cjs.timelockToSequence(csv)) : void 0;
2254
+ const sequence = csv ? Number(chunkUUSKJOSX_cjs.timelockToSequence(csv)) : void 0;
2886
2255
  if (opts.checkTimelocks && csv && !isCsvSpendable(context, sequence)) continue;
2887
2256
  if (opts.checkTimelocks && cltv !== void 0 && !isCltvSatisfied(context, cltv)) {
2888
2257
  continue;
@@ -2969,6 +2338,7 @@ exports.ARKADE_OPCODES = ARKADE_OPCODES;
2969
2338
  exports.ARKADE_OPCODE_NAMES = ARKADE_OPCODE_NAMES;
2970
2339
  exports.ARKADE_OPCODE_VALUES = ARKADE_OPCODE_VALUES;
2971
2340
  exports.ARKADE_OPS = ARKADE_OPS;
2341
+ exports.ARKADE_TYPE_ENCODINGS = ARKADE_TYPE_ENCODINGS;
2972
2342
  exports.ArkadeContractHandler = ArkadeContractHandler;
2973
2343
  exports.ArkadeProgramScript = ArkadeProgramScript;
2974
2344
  exports.ArkadeScript = ArkadeScript;
@@ -2978,6 +2348,7 @@ exports.DelegateContractHandler = DelegateContractHandler;
2978
2348
  exports.OPCODE_NAMES = OPCODE_NAMES;
2979
2349
  exports.OPCODE_VALUES = OPCODE_VALUES;
2980
2350
  exports.SUPPORTED_PROGRAM_VERSION = SUPPORTED_PROGRAM_VERSION;
2351
+ exports.UnsupportedProgramVersionError = UnsupportedProgramVersionError;
2981
2352
  exports.VHTLCContractHandler = VHTLCContractHandler;
2982
2353
  exports.VHTLCV2ContractHandler = VHTLCV2ContractHandler;
2983
2354
  exports.WALLET_RECEIVE_SOURCE = WALLET_RECEIVE_SOURCE;
@@ -2992,11 +2363,11 @@ exports.deriveDescriptorLeafCompressedPubKey = deriveDescriptorLeafCompressedPub
2992
2363
  exports.deriveDescriptorLeafPubKey = deriveDescriptorLeafPubKey;
2993
2364
  exports.descriptorIsOurs = descriptorIsOurs;
2994
2365
  exports.deserializeArkadeContractParams = deserializeArkadeContractParams;
2366
+ exports.extractPubKey = extractPubKey;
2995
2367
  exports.fromASM = fromASM;
2996
2368
  exports.getOpcodeName = getOpcodeName;
2997
2369
  exports.getOpcodeValue = getOpcodeValue;
2998
2370
  exports.identityDescriptor = identityDescriptor;
2999
- exports.inputName = inputName;
3000
2371
  exports.isCltvSatisfied = isCltvSatisfied;
3001
2372
  exports.isCsvSpendable = isCsvSpendable;
3002
2373
  exports.isMainnetDescriptor = isMainnetDescriptor;
@@ -3009,7 +2380,8 @@ exports.speculativeReceiveMetadata = speculativeReceiveMetadata;
3009
2380
  exports.stringifyArtifact = stringifyArtifact;
3010
2381
  exports.toASM = toASM;
3011
2382
  exports.toXOnly = toXOnly;
2383
+ exports.validateParamValue = validateParamValue;
3012
2384
  exports.validateProgram = validateProgram;
3013
2385
  exports.witnessRefToBytes = witnessRefToBytes;
3014
- //# sourceMappingURL=chunk-VMVHRKXM.cjs.map
3015
- //# sourceMappingURL=chunk-VMVHRKXM.cjs.map
2386
+ //# sourceMappingURL=chunk-GN2K4WBP.cjs.map
2387
+ //# sourceMappingURL=chunk-GN2K4WBP.cjs.map