@arkade-os/sdk 0.5.0-rc.2 → 0.5.0-rc.21

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 (126) hide show
  1. package/README.md +90 -83
  2. package/dist/adapters/expo.cjs +5 -6
  3. package/dist/adapters/expo.d.cts +4 -4
  4. package/dist/adapters/expo.d.ts +4 -4
  5. package/dist/adapters/expo.js +3 -4
  6. package/dist/{asyncStorageTaskQueue-C5rBYlru.d.ts → asyncStorageTaskQueue-aL7K14e4.d.ts} +2 -2
  7. package/dist/{asyncStorageTaskQueue-BuDvgWh6.d.cts → asyncStorageTaskQueue-x8ok3tJy.d.cts} +2 -2
  8. package/dist/{chunk-ISO4TI5J.js → chunk-4FDNOLBO.js} +566 -459
  9. package/dist/chunk-4FDNOLBO.js.map +1 -0
  10. package/dist/{chunk-JZWLXNHV.cjs → chunk-5XBH5SAL.cjs} +574 -464
  11. package/dist/chunk-5XBH5SAL.cjs.map +1 -0
  12. package/dist/{chunk-3R476TDV.js → chunk-CXHJGED6.js} +293 -1071
  13. package/dist/chunk-CXHJGED6.js.map +1 -0
  14. package/dist/{chunk-ZRNQV6HV.js → chunk-EXFU6MTA.js} +4578 -4396
  15. package/dist/chunk-EXFU6MTA.js.map +1 -0
  16. package/dist/{chunk-43FKNLX4.cjs → chunk-GVF4OCTL.cjs} +357 -1114
  17. package/dist/chunk-GVF4OCTL.cjs.map +1 -0
  18. package/dist/{chunk-HLCGYOIH.cjs → chunk-HIZNPHB2.cjs} +37 -36
  19. package/dist/chunk-HIZNPHB2.cjs.map +1 -0
  20. package/dist/{chunk-4PKLULWT.js → chunk-JZAEFOE4.js} +109 -246
  21. package/dist/chunk-JZAEFOE4.js.map +1 -0
  22. package/dist/{chunk-ZOTXDOS5.js → chunk-LNJPVLIC.js} +30 -29
  23. package/dist/chunk-LNJPVLIC.js.map +1 -0
  24. package/dist/{chunk-NVZJSKZS.cjs → chunk-Q7PC3NHX.cjs} +121 -257
  25. package/dist/chunk-Q7PC3NHX.cjs.map +1 -0
  26. package/dist/{chunk-GMZZQXV5.cjs → chunk-R5OFJ23O.cjs} +4961 -4767
  27. package/dist/chunk-R5OFJ23O.cjs.map +1 -0
  28. package/dist/{chunk-6DNR46C7.js → chunk-S2WWOVFC.js} +7 -5
  29. package/dist/chunk-S2WWOVFC.js.map +1 -0
  30. package/dist/{chunk-D25O4EGY.cjs → chunk-VZMLADXQ.cjs} +12 -10
  31. package/dist/chunk-VZMLADXQ.cjs.map +1 -0
  32. package/dist/contracts/handlers/index.cjs +9 -10
  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 -3
  36. package/dist/{delegate-BAX5QftB.d.ts → delegate-BT5iON1T.d.ts} +1 -1
  37. package/dist/{delegate-1yp1HyP7.d.cts → delegate-u6kXTtWY.d.cts} +1 -1
  38. package/dist/index-BCnhItOQ.d.cts +639 -0
  39. package/dist/{index-DUxufw76.d.cts → index-CK5QbTmZ.d.cts} +1387 -2404
  40. package/dist/{index-DUxufw76.d.ts → index-CK5QbTmZ.d.ts} +1387 -2404
  41. package/dist/index-D1D4cR-G.d.ts +639 -0
  42. package/dist/index.cjs +375 -340
  43. package/dist/index.d.cts +784 -1197
  44. package/dist/index.d.ts +784 -1197
  45. package/dist/index.js +4 -5
  46. package/dist/repositories/realm/index.cjs +201 -106
  47. package/dist/repositories/realm/index.cjs.map +1 -1
  48. package/dist/repositories/realm/index.d.cts +28 -16
  49. package/dist/repositories/realm/index.d.ts +28 -16
  50. package/dist/repositories/realm/index.js +190 -95
  51. package/dist/repositories/realm/index.js.map +1 -1
  52. package/dist/repositories/sqlite/index.cjs +301 -189
  53. package/dist/repositories/sqlite/index.cjs.map +1 -1
  54. package/dist/repositories/sqlite/index.d.cts +32 -21
  55. package/dist/repositories/sqlite/index.d.ts +32 -21
  56. package/dist/repositories/sqlite/index.js +294 -182
  57. package/dist/repositories/sqlite/index.js.map +1 -1
  58. package/dist/{taskRunner-D_iPiZIi.d.ts → taskRunner-BeYR6NpQ.d.ts} +2 -2
  59. package/dist/{taskRunner-Dr3NStc0.d.cts → taskRunner-Csey3EYJ.d.cts} +2 -2
  60. package/dist/wallet/expo/background.cjs +14 -15
  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 -7
  65. package/dist/wallet/expo/background.js.map +1 -1
  66. package/dist/wallet/expo/index.cjs +16 -23
  67. package/dist/wallet/expo/index.cjs.map +1 -1
  68. package/dist/wallet/expo/index.d.cts +6 -9
  69. package/dist/wallet/expo/index.d.ts +6 -9
  70. package/dist/wallet/expo/index.js +8 -15
  71. package/dist/wallet/expo/index.js.map +1 -1
  72. package/dist/wallet-DG3Qmbmt.d.cts +1848 -0
  73. package/dist/wallet-DzSLMxBZ.d.ts +1848 -0
  74. package/dist/worker/expo/index.cjs +9 -10
  75. package/dist/worker/expo/index.cjs.map +1 -1
  76. package/dist/worker/expo/index.d.cts +6 -6
  77. package/dist/worker/expo/index.d.ts +6 -6
  78. package/dist/worker/expo/index.js +5 -6
  79. package/dist/worker/expo/index.js.map +1 -1
  80. package/package.json +12 -51
  81. package/dist/adapters/asyncStorage.cjs +0 -48
  82. package/dist/adapters/asyncStorage.cjs.map +0 -1
  83. package/dist/adapters/asyncStorage.d.cts +0 -16
  84. package/dist/adapters/asyncStorage.d.ts +0 -16
  85. package/dist/adapters/asyncStorage.js +0 -46
  86. package/dist/adapters/asyncStorage.js.map +0 -1
  87. package/dist/adapters/fileSystem.cjs +0 -116
  88. package/dist/adapters/fileSystem.cjs.map +0 -1
  89. package/dist/adapters/fileSystem.d.cts +0 -17
  90. package/dist/adapters/fileSystem.d.ts +0 -17
  91. package/dist/adapters/fileSystem.js +0 -93
  92. package/dist/adapters/fileSystem.js.map +0 -1
  93. package/dist/adapters/indexedDB.cjs +0 -103
  94. package/dist/adapters/indexedDB.cjs.map +0 -1
  95. package/dist/adapters/indexedDB.d.cts +0 -18
  96. package/dist/adapters/indexedDB.d.ts +0 -18
  97. package/dist/adapters/indexedDB.js +0 -101
  98. package/dist/adapters/indexedDB.js.map +0 -1
  99. package/dist/adapters/localStorage.cjs +0 -50
  100. package/dist/adapters/localStorage.cjs.map +0 -1
  101. package/dist/adapters/localStorage.d.cts +0 -14
  102. package/dist/adapters/localStorage.d.ts +0 -14
  103. package/dist/adapters/localStorage.js +0 -48
  104. package/dist/adapters/localStorage.js.map +0 -1
  105. package/dist/chunk-3R476TDV.js.map +0 -1
  106. package/dist/chunk-43FKNLX4.cjs.map +0 -1
  107. package/dist/chunk-4PKLULWT.js.map +0 -1
  108. package/dist/chunk-5BLDMQED.cjs +0 -18
  109. package/dist/chunk-5BLDMQED.cjs.map +0 -1
  110. package/dist/chunk-6DNR46C7.js.map +0 -1
  111. package/dist/chunk-D25O4EGY.cjs.map +0 -1
  112. package/dist/chunk-GMZZQXV5.cjs.map +0 -1
  113. package/dist/chunk-HLCGYOIH.cjs.map +0 -1
  114. package/dist/chunk-ISO4TI5J.js.map +0 -1
  115. package/dist/chunk-JZWLXNHV.cjs.map +0 -1
  116. package/dist/chunk-NSBPE2FW.js +0 -15
  117. package/dist/chunk-NSBPE2FW.js.map +0 -1
  118. package/dist/chunk-NVZJSKZS.cjs.map +0 -1
  119. package/dist/chunk-ZOTXDOS5.js.map +0 -1
  120. package/dist/chunk-ZRNQV6HV.js.map +0 -1
  121. package/dist/hdWalletCapable-CmEU0NP1.d.ts +0 -2232
  122. package/dist/hdWalletCapable-eJgaT-ec.d.cts +0 -2232
  123. package/dist/index-Bem5vKzX.d.ts +0 -850
  124. package/dist/index-C0IanN1m.d.cts +0 -11
  125. package/dist/index-C0IanN1m.d.ts +0 -11
  126. package/dist/index-W_oMcOmG.d.cts +0 -850
@@ -1,44 +1,47 @@
1
1
  'use strict';
2
2
 
3
- var chunkJZWLXNHV_cjs = require('./chunk-JZWLXNHV.cjs');
4
- var chunk5BLDMQED_cjs = require('./chunk-5BLDMQED.cjs');
3
+ var chunk5XBH5SAL_cjs = require('./chunk-5XBH5SAL.cjs');
5
4
  var base = require('@scure/base');
6
5
  var descriptorsScure = require('@bitcoinerlab/descriptors-scure');
7
6
  var btcSigner = require('@scure/btc-signer');
7
+ var P = require('micro-packed');
8
8
  var secp256k1_js = require('@noble/curves/secp256k1.js');
9
9
  var utils_js = require('@noble/curves/utils.js');
10
10
 
11
+ function _interopNamespace(e) {
12
+ if (e && e.__esModule) return e;
13
+ var n = Object.create(null);
14
+ if (e) {
15
+ Object.keys(e).forEach(function (k) {
16
+ if (k !== 'default') {
17
+ var d = Object.getOwnPropertyDescriptor(e, k);
18
+ Object.defineProperty(n, k, d.get ? d : {
19
+ enumerable: true,
20
+ get: function () { return e[k]; }
21
+ });
22
+ }
23
+ });
24
+ }
25
+ n.default = e;
26
+ return Object.freeze(n);
27
+ }
28
+
29
+ var P__namespace = /*#__PURE__*/_interopNamespace(P);
30
+
11
31
  // src/contracts/handlers/registry.ts
12
32
  var ContractHandlerRegistry = class {
13
33
  handlers = /* @__PURE__ */ new Map();
14
- /**
15
- * Register a contract handler.
16
- *
17
- * @param handler - The handler to register
18
- * @throws If a handler for this type is already registered
19
- */
34
+ /** @throws If a handler for this type is already registered */
20
35
  register(handler) {
21
36
  if (this.handlers.has(handler.type)) {
22
37
  throw new Error(`Contract handler for type '${handler.type}' is already registered`);
23
38
  }
24
39
  this.handlers.set(handler.type, handler);
25
40
  }
26
- /**
27
- * Get a handler by type.
28
- *
29
- * @param type - The contract type
30
- * @returns The handler, or undefined if not found
31
- */
32
41
  get(type) {
33
42
  return this.handlers.get(type);
34
43
  }
35
- /**
36
- * Get a handler by type, throwing if not found.
37
- *
38
- * @param type - The contract type
39
- * @returns The handler
40
- * @throws If no handler is registered for this type
41
- */
44
+ /** @throws If no handler is registered for this type */
42
45
  getOrThrow(type) {
43
46
  const handler = this.get(type);
44
47
  if (!handler) {
@@ -46,29 +49,17 @@ var ContractHandlerRegistry = class {
46
49
  }
47
50
  return handler;
48
51
  }
49
- /**
50
- * Check if a handler is registered.
51
- *
52
- * @param type - The contract type
53
- */
54
52
  has(type) {
55
53
  return this.handlers.has(type);
56
54
  }
57
- /**
58
- * Get all registered types.
59
- */
60
55
  getRegisteredTypes() {
61
56
  return Array.from(this.handlers.keys());
62
57
  }
63
- /**
64
- * Unregister a handler (mainly for testing).
65
- */
58
+ /** Unregister a handler (mainly for testing). */
66
59
  unregister(type) {
67
60
  return this.handlers.delete(type);
68
61
  }
69
- /**
70
- * Clear all handlers (mainly for testing).
71
- */
62
+ /** Clear all handlers (mainly for testing). */
72
63
  clear() {
73
64
  this.handlers.clear();
74
65
  }
@@ -76,14 +67,14 @@ var ContractHandlerRegistry = class {
76
67
  var contractHandlers = new ContractHandlerRegistry();
77
68
  exports.DefaultVtxo = void 0;
78
69
  ((DefaultVtxo2) => {
79
- class Script3 extends chunkJZWLXNHV_cjs.VtxoScript {
70
+ class Script3 extends chunk5XBH5SAL_cjs.VtxoScript {
80
71
  /** Create the default virtual output script with one forfeit path and one exit path. */
81
72
  constructor(options) {
82
73
  const { pubKey, serverPubKey, csvTimelock } = options;
83
- const forfeitScript = chunkJZWLXNHV_cjs.MultisigTapscript.encode({
74
+ const forfeitScript = chunk5XBH5SAL_cjs.MultisigTapscript.encode({
84
75
  pubkeys: [pubKey, serverPubKey]
85
76
  }).script;
86
- const exitScript = chunkJZWLXNHV_cjs.CSVMultisigTapscript.encode({
77
+ const exitScript = chunk5XBH5SAL_cjs.CSVMultisigTapscript.encode({
87
78
  timelock: csvTimelock,
88
79
  pubkeys: [pubKey]
89
80
  }).script;
@@ -268,27 +259,14 @@ function resolveRole(contract, context) {
268
259
  }
269
260
  return void 0;
270
261
  };
271
- if (context.walletDescriptor) {
272
- const walletDescriptorKey = extractRawPubKey(context.walletDescriptor);
273
- const matchedRole = matchRole(walletDescriptorKey);
274
- if (matchedRole) {
275
- return matchedRole;
276
- }
277
- if (!walletDescriptorKey && context.walletPubKey) {
278
- return matchRole(extractRawPubKey(context.walletPubKey));
279
- }
280
- return void 0;
281
- }
282
- if (context.walletPubKey) {
283
- return matchRole(extractRawPubKey(context.walletPubKey));
284
- }
285
- return void 0;
262
+ if (!context.walletDescriptor) return void 0;
263
+ return matchRole(extractRawPubKey(context.walletDescriptor));
286
264
  }
287
265
  function extractPubKeyBytes(value) {
288
266
  return base.hex.decode(extractPubKey(normalizeToDescriptor(value)));
289
267
  }
290
268
  function deserializeCsvTimelock(value) {
291
- return value !== void 0 && value !== "" ? chunkJZWLXNHV_cjs.sequenceToTimelock(Number(value)) : exports.DefaultVtxo.Script.DEFAULT_TIMELOCK;
269
+ return value !== void 0 && value !== "" ? chunk5XBH5SAL_cjs.sequenceToTimelock(Number(value)) : exports.DefaultVtxo.Script.DEFAULT_TIMELOCK;
292
270
  }
293
271
  var CLTV_HEIGHT_THRESHOLD = 500000000n;
294
272
  function isCltvSatisfied(context, locktime) {
@@ -327,10 +305,139 @@ function assertVhtlcSpendableNow(contract, context) {
327
305
  `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.`
328
306
  );
329
307
  }
308
+ function selectVhtlcPath(script, contract, context) {
309
+ const role = resolveRole(contract, context);
310
+ const preimage = contract.params?.preimage;
311
+ const refundLocktime = BigInt(contract.params.refundLocktime);
312
+ if (!role) {
313
+ return null;
314
+ }
315
+ if (context.collaborative) {
316
+ if (role === "receiver" && preimage) {
317
+ return {
318
+ leaf: script.claim(),
319
+ extraWitness: [base.hex.decode(preimage)]
320
+ };
321
+ }
322
+ if (role === "sender" && isCltvSatisfied(context, refundLocktime)) {
323
+ return {
324
+ leaf: script.refundWithoutReceiver()
325
+ };
326
+ }
327
+ return null;
328
+ }
329
+ if (role === "receiver" && preimage) {
330
+ const sequence = Number(contract.params.claimDelay);
331
+ if (!isCsvSpendable(context, sequence)) return null;
332
+ return {
333
+ leaf: script.unilateralClaim(),
334
+ extraWitness: [base.hex.decode(preimage)],
335
+ sequence
336
+ };
337
+ }
338
+ if (role === "sender") {
339
+ const sequence = Number(contract.params.refundNoReceiverDelay);
340
+ if (!isCsvSpendable(context, sequence)) return null;
341
+ return {
342
+ leaf: script.unilateralRefundWithoutReceiver(),
343
+ sequence
344
+ };
345
+ }
346
+ return null;
347
+ }
348
+ function vhtlcAllSpendingPaths(script, contract, context) {
349
+ const role = resolveRole(contract, context);
350
+ const paths = [];
351
+ if (!role) {
352
+ return paths;
353
+ }
354
+ const preimage = contract.params?.preimage;
355
+ if (context.collaborative) {
356
+ if (role === "receiver" && preimage) {
357
+ paths.push({
358
+ leaf: script.claim(),
359
+ extraWitness: [base.hex.decode(preimage)]
360
+ });
361
+ }
362
+ if (role === "sender") {
363
+ paths.push({
364
+ leaf: script.refundWithoutReceiver()
365
+ });
366
+ }
367
+ } else {
368
+ if (role === "receiver" && preimage) {
369
+ const sequence = Number(contract.params.claimDelay);
370
+ paths.push({
371
+ leaf: script.unilateralClaim(),
372
+ extraWitness: [base.hex.decode(preimage)],
373
+ sequence
374
+ });
375
+ }
376
+ if (role === "sender") {
377
+ const sequence = Number(contract.params.refundNoReceiverDelay);
378
+ paths.push({
379
+ leaf: script.unilateralRefundWithoutReceiver(),
380
+ sequence
381
+ });
382
+ }
383
+ }
384
+ return paths;
385
+ }
386
+ function vhtlcSpendablePaths(script, contract, context) {
387
+ const role = resolveRole(contract, context);
388
+ const paths = [];
389
+ if (!role) {
390
+ return paths;
391
+ }
392
+ const preimage = contract.params?.preimage;
393
+ const refundLocktime = BigInt(contract.params.refundLocktime);
394
+ if (context.collaborative) {
395
+ if (role === "receiver" && preimage) {
396
+ paths.push({
397
+ leaf: script.claim(),
398
+ extraWitness: [base.hex.decode(preimage)]
399
+ });
400
+ }
401
+ if (role === "sender" && isCltvSatisfied(context, refundLocktime)) {
402
+ paths.push({
403
+ leaf: script.refundWithoutReceiver()
404
+ });
405
+ }
406
+ return paths;
407
+ }
408
+ if (role === "receiver" && preimage) {
409
+ const sequence = Number(contract.params.claimDelay);
410
+ if (isCsvSpendable(context, sequence)) {
411
+ paths.push({
412
+ leaf: script.unilateralClaim(),
413
+ extraWitness: [base.hex.decode(preimage)],
414
+ sequence
415
+ });
416
+ }
417
+ }
418
+ if (role === "sender") {
419
+ const sequence = Number(contract.params.refundNoReceiverDelay);
420
+ if (isCsvSpendable(context, sequence)) {
421
+ paths.push({
422
+ leaf: script.unilateralRefundWithoutReceiver(),
423
+ sequence
424
+ });
425
+ }
426
+ }
427
+ return paths;
428
+ }
429
+ function deriveVhtlcTapscripts(script) {
430
+ const leaf = script.refundWithoutReceiver();
431
+ return {
432
+ forfeitTapLeafScript: leaf,
433
+ intentTapLeafScript: leaf,
434
+ tapTree: script.encode()
435
+ };
436
+ }
330
437
  function isCsvSpendable(context, sequence) {
331
438
  if (sequence === void 0) return true;
332
439
  if (!context.vtxo) return false;
333
- const timelock = chunkJZWLXNHV_cjs.sequenceToTimelock(sequence);
440
+ const timelock = chunk5XBH5SAL_cjs.sequenceToTimelock(sequence);
334
441
  if (timelock.type === "blocks") {
335
442
  if (context.blockHeight === void 0 || context.vtxo.status.block_height === void 0) {
336
443
  return false;
@@ -388,21 +495,21 @@ function forfeitExitSpendablePaths(script, contract, context) {
388
495
  async function detectUsedScripts(indexerProvider, scriptHexes) {
389
496
  const used = /* @__PURE__ */ new Set();
390
497
  const unique = [...new Set(scriptHexes)];
391
- for (let offset = 0; offset < unique.length; offset += chunkJZWLXNHV_cjs.SCRIPT_QUERY_CHUNK_SIZE) {
392
- const scripts = unique.slice(offset, offset + chunkJZWLXNHV_cjs.SCRIPT_QUERY_CHUNK_SIZE);
498
+ for (let offset = 0; offset < unique.length; offset += chunk5XBH5SAL_cjs.SCRIPT_QUERY_CHUNK_SIZE) {
499
+ const scripts = unique.slice(offset, offset + chunk5XBH5SAL_cjs.SCRIPT_QUERY_CHUNK_SIZE);
393
500
  const remaining = new Set(scripts);
394
501
  let pageIndex = 0;
395
502
  let hasMore = true;
396
503
  while (hasMore && remaining.size > 0) {
397
- const { vtxos, page } = await chunkJZWLXNHV_cjs.getNormalizedVtxos(indexerProvider, {
504
+ const { vtxos, page } = await chunk5XBH5SAL_cjs.getNormalizedVtxos(indexerProvider, {
398
505
  scripts,
399
506
  pageIndex,
400
- pageSize: chunkJZWLXNHV_cjs.DEFAULT_PAGE_SIZE
507
+ pageSize: chunk5XBH5SAL_cjs.DEFAULT_PAGE_SIZE
401
508
  });
402
509
  for (const vtxo of vtxos) {
403
510
  if (remaining.delete(vtxo.script)) used.add(vtxo.script);
404
511
  }
405
- hasMore = page ? vtxos.length === chunkJZWLXNHV_cjs.DEFAULT_PAGE_SIZE : false;
512
+ hasMore = page ? vtxos.length === chunk5XBH5SAL_cjs.DEFAULT_PAGE_SIZE : false;
406
513
  pageIndex++;
407
514
  }
408
515
  }
@@ -463,7 +570,7 @@ var DefaultContractHandler = {
463
570
  return {
464
571
  pubKey: base.hex.encode(params.pubKey),
465
572
  serverPubKey: base.hex.encode(params.serverPubKey),
466
- csvTimelock: chunkJZWLXNHV_cjs.timelockToSequence(params.csvTimelock).toString()
573
+ csvTimelock: chunk5XBH5SAL_cjs.timelockToSequence(params.csvTimelock).toString()
467
574
  };
468
575
  },
469
576
  deserializeParams(params) {
@@ -495,11 +602,7 @@ function defaultCandidatesAt(_index, descriptor, deps) {
495
602
  (opts) => new exports.DefaultVtxo.Script(opts)
496
603
  ).map((c) => ({
497
604
  type: "default",
498
- params: {
499
- pubKey: base.hex.encode(c.pubKey),
500
- serverPubKey: base.hex.encode(c.serverPubKey),
501
- csvTimelock: chunkJZWLXNHV_cjs.timelockToSequence(c.csvTimelock).toString()
502
- },
605
+ params: DefaultContractHandler.serializeParams(c),
503
606
  script: c.scriptHex,
504
607
  address: c.script.address(deps.network.hrp, c.serverPubKey).encode()
505
608
  }));
@@ -514,12 +617,12 @@ function discoverDefaultRange(entries, deps) {
514
617
  }
515
618
  exports.DelegateVtxo = void 0;
516
619
  ((DelegateVtxo2) => {
517
- class Script3 extends chunkJZWLXNHV_cjs.VtxoScript {
620
+ class Script3 extends chunk5XBH5SAL_cjs.VtxoScript {
518
621
  /** Create a delegated virtual output script with forfeit, exit, and delegate paths. */
519
622
  constructor(options) {
520
623
  const defaultVtxo = new exports.DefaultVtxo.Script(options);
521
624
  const { delegatePubKey, pubKey, serverPubKey } = options;
522
- const delegateScript = chunkJZWLXNHV_cjs.MultisigTapscript.encode({
625
+ const delegateScript = chunk5XBH5SAL_cjs.MultisigTapscript.encode({
523
626
  pubkeys: [pubKey, delegatePubKey, serverPubKey]
524
627
  }).script;
525
628
  super([...defaultVtxo.scripts, delegateScript]);
@@ -558,7 +661,7 @@ var DelegateContractHandler = {
558
661
  pubKey: base.hex.encode(params.pubKey),
559
662
  serverPubKey: base.hex.encode(params.serverPubKey),
560
663
  delegatePubKey: base.hex.encode(params.delegatePubKey),
561
- csvTimelock: chunkJZWLXNHV_cjs.timelockToSequence(params.csvTimelock).toString()
664
+ csvTimelock: chunk5XBH5SAL_cjs.timelockToSequence(params.csvTimelock).toString()
562
665
  };
563
666
  },
564
667
  deserializeParams(params) {
@@ -598,12 +701,7 @@ function delegateCandidatesAt(_index, descriptor, deps) {
598
701
  (opts) => new exports.DelegateVtxo.Script({ ...opts, delegatePubKey })
599
702
  ).map((c) => ({
600
703
  type: "delegate",
601
- params: {
602
- pubKey: base.hex.encode(c.pubKey),
603
- serverPubKey: base.hex.encode(c.serverPubKey),
604
- delegatePubKey: base.hex.encode(delegatePubKey),
605
- csvTimelock: chunkJZWLXNHV_cjs.timelockToSequence(c.csvTimelock).toString()
606
- },
704
+ params: DelegateContractHandler.serializeParams({ ...c, delegatePubKey }),
607
705
  script: c.scriptHex,
608
706
  address: c.script.address(deps.network.hrp, c.serverPubKey).encode()
609
707
  }));
@@ -619,515 +717,10 @@ function discoverDelegateRange(entries, deps) {
619
717
  (c, index, descriptor) => ({ ...c, ...rotatedReceiveMetadata(index, descriptor) })
620
718
  );
621
719
  }
622
- function equalBytes(a, b) {
623
- if (a.length !== b.length)
624
- return false;
625
- for (let i = 0; i < a.length; i++)
626
- if (a[i] !== b[i])
627
- return false;
628
- return true;
629
- }
630
- function isBytes(a) {
631
- return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
632
- }
633
- var createView = (arr) => new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
634
- function isPlainObject(obj) {
635
- return Object.prototype.toString.call(obj) === "[object Object]";
636
- }
637
- function isNum(num) {
638
- return Number.isSafeInteger(num);
639
- }
640
- var Bitset = {
641
- BITS: 32,
642
- FULL_MASK: -1 >>> 0,
643
- // 1<<32 will overflow
644
- len: (len) => Math.ceil(len / 32),
645
- create: (len) => new Uint32Array(Bitset.len(len)),
646
- clean: (bs) => bs.fill(0),
647
- debug: (bs) => Array.from(bs).map((i) => (i >>> 0).toString(2).padStart(32, "0")),
648
- checkLen: (bs, len) => {
649
- if (Bitset.len(len) === bs.length)
650
- return;
651
- throw new Error(`wrong length=${bs.length}. Expected: ${Bitset.len(len)}`);
652
- },
653
- chunkLen: (bsLen, pos, len) => {
654
- if (pos < 0)
655
- throw new Error(`wrong pos=${pos}`);
656
- if (pos + len > bsLen)
657
- throw new Error(`wrong range=${pos}/${len} of ${bsLen}`);
658
- },
659
- set: (bs, chunk, value, allowRewrite = true) => {
660
- if (!allowRewrite && (bs[chunk] & value) !== 0)
661
- return false;
662
- bs[chunk] |= value;
663
- return true;
664
- },
665
- pos: (pos, i) => ({
666
- chunk: Math.floor((pos + i) / 32),
667
- mask: 1 << 32 - (pos + i) % 32 - 1
668
- }),
669
- indices: (bs, len, invert = false) => {
670
- Bitset.checkLen(bs, len);
671
- const { FULL_MASK, BITS } = Bitset;
672
- const left = BITS - len % BITS;
673
- const lastMask = left ? FULL_MASK >>> left << left : FULL_MASK;
674
- const res = [];
675
- for (let i = 0; i < bs.length; i++) {
676
- let c = bs[i];
677
- if (invert)
678
- c = ~c;
679
- if (i === bs.length - 1)
680
- c &= lastMask;
681
- if (c === 0)
682
- continue;
683
- for (let j = 0; j < BITS; j++) {
684
- const m = 1 << BITS - j - 1;
685
- if (c & m)
686
- res.push(i * BITS + j);
687
- }
688
- }
689
- return res;
690
- },
691
- range: (arr) => {
692
- const res = [];
693
- let cur;
694
- for (const i of arr) {
695
- if (cur === void 0 || i !== cur.pos + cur.length)
696
- res.push(cur = { pos: i, length: 1 });
697
- else
698
- cur.length += 1;
699
- }
700
- return res;
701
- },
702
- rangeDebug: (bs, len, invert = false) => `[${Bitset.range(Bitset.indices(bs, len, invert)).map((i) => `(${i.pos}/${i.length})`).join(", ")}]`,
703
- setRange: (bs, bsLen, pos, len, allowRewrite = true) => {
704
- Bitset.chunkLen(bsLen, pos, len);
705
- const { FULL_MASK, BITS } = Bitset;
706
- const first = pos % BITS ? Math.floor(pos / BITS) : void 0;
707
- const lastPos = pos + len;
708
- const last = lastPos % BITS ? Math.floor(lastPos / BITS) : void 0;
709
- if (first !== void 0 && first === last)
710
- return Bitset.set(bs, first, FULL_MASK >>> BITS - len << BITS - len - pos, allowRewrite);
711
- if (first !== void 0) {
712
- if (!Bitset.set(bs, first, FULL_MASK >>> pos % BITS, allowRewrite))
713
- return false;
714
- }
715
- const start = first !== void 0 ? first + 1 : pos / BITS;
716
- const end = last !== void 0 ? last : lastPos / BITS;
717
- for (let i = start; i < end; i++)
718
- if (!Bitset.set(bs, i, FULL_MASK, allowRewrite))
719
- return false;
720
- if (last !== void 0 && first !== last) {
721
- if (!Bitset.set(bs, last, FULL_MASK << BITS - lastPos % BITS, allowRewrite))
722
- return false;
723
- }
724
- return true;
725
- }
726
- };
727
- var Path = {
728
- /**
729
- * Internal method for handling stack of paths (debug, errors, dynamic fields via path)
730
- * This is looks ugly (callback), but allows us to force stack cleaning by construction (.pop always after function).
731
- * Also, this makes impossible:
732
- * - pushing field when stack is empty
733
- * - pushing field inside of field (real bug)
734
- * NOTE: we don't want to do '.pop' on error!
735
- */
736
- pushObj: (stack, obj, objFn) => {
737
- const last = { obj };
738
- stack.push(last);
739
- objFn((field, fieldFn) => {
740
- last.field = field;
741
- fieldFn();
742
- last.field = void 0;
743
- });
744
- stack.pop();
745
- },
746
- path: (stack) => {
747
- const res = [];
748
- for (const i of stack)
749
- if (i.field !== void 0)
750
- res.push(i.field);
751
- return res.join("/");
752
- },
753
- err: (name, stack, msg) => {
754
- const err = new Error(`${name}(${Path.path(stack)}): ${typeof msg === "string" ? msg : msg.message}`);
755
- if (msg instanceof Error && msg.stack)
756
- err.stack = msg.stack;
757
- return err;
758
- },
759
- resolve: (stack, path) => {
760
- const parts = path.split("/");
761
- const objPath = stack.map((i2) => i2.obj);
762
- let i = 0;
763
- for (; i < parts.length; i++) {
764
- if (parts[i] === "..")
765
- objPath.pop();
766
- else
767
- break;
768
- }
769
- let cur = objPath.pop();
770
- for (; i < parts.length; i++) {
771
- if (!cur || cur[parts[i]] === void 0)
772
- return void 0;
773
- cur = cur[parts[i]];
774
- }
775
- return cur;
776
- }
777
- };
778
- var _Reader = class __Reader {
779
- pos = 0;
780
- data;
781
- opts;
782
- stack;
783
- parent;
784
- parentOffset;
785
- bitBuf = 0;
786
- bitPos = 0;
787
- bs;
788
- // bitset
789
- view;
790
- constructor(data, opts = {}, stack = [], parent = void 0, parentOffset = 0) {
791
- this.data = data;
792
- this.opts = opts;
793
- this.stack = stack;
794
- this.parent = parent;
795
- this.parentOffset = parentOffset;
796
- this.view = createView(data);
797
- }
798
- /** Internal method for pointers. */
799
- _enablePointers() {
800
- if (this.parent)
801
- return this.parent._enablePointers();
802
- if (this.bs)
803
- return;
804
- this.bs = Bitset.create(this.data.length);
805
- Bitset.setRange(this.bs, this.data.length, 0, this.pos, this.opts.allowMultipleReads);
806
- }
807
- markBytesBS(pos, len) {
808
- if (this.parent)
809
- return this.parent.markBytesBS(this.parentOffset + pos, len);
810
- if (!len)
811
- return true;
812
- if (!this.bs)
813
- return true;
814
- return Bitset.setRange(this.bs, this.data.length, pos, len, false);
815
- }
816
- markBytes(len) {
817
- const pos = this.pos;
818
- this.pos += len;
819
- const res = this.markBytesBS(pos, len);
820
- if (!this.opts.allowMultipleReads && !res)
821
- throw this.err(`multiple read pos=${this.pos} len=${len}`);
822
- return res;
823
- }
824
- pushObj(obj, objFn) {
825
- return Path.pushObj(this.stack, obj, objFn);
826
- }
827
- readView(n, fn) {
828
- if (!Number.isFinite(n))
829
- throw this.err(`readView: wrong length=${n}`);
830
- if (this.pos + n > this.data.length)
831
- throw this.err("readView: Unexpected end of buffer");
832
- const res = fn(this.view, this.pos);
833
- this.markBytes(n);
834
- return res;
835
- }
836
- // read bytes by absolute offset
837
- absBytes(n) {
838
- if (n > this.data.length)
839
- throw new Error("Unexpected end of buffer");
840
- return this.data.subarray(n);
841
- }
842
- finish() {
843
- if (this.opts.allowUnreadBytes)
844
- return;
845
- if (this.bitPos) {
846
- throw this.err(`${this.bitPos} bits left after unpack: ${base.hex.encode(this.data.slice(this.pos))}`);
847
- }
848
- if (this.bs && !this.parent) {
849
- const notRead = Bitset.indices(this.bs, this.data.length, true);
850
- if (notRead.length) {
851
- const formatted = Bitset.range(notRead).map(({ pos, length }) => `(${pos}/${length})[${base.hex.encode(this.data.subarray(pos, pos + length))}]`).join(", ");
852
- throw this.err(`unread byte ranges: ${formatted} (total=${this.data.length})`);
853
- } else
854
- return;
855
- }
856
- if (!this.isEnd()) {
857
- throw this.err(`${this.leftBytes} bytes ${this.bitPos} bits left after unpack: ${base.hex.encode(this.data.slice(this.pos))}`);
858
- }
859
- }
860
- // User methods
861
- err(msg) {
862
- return Path.err("Reader", this.stack, msg);
863
- }
864
- offsetReader(n) {
865
- if (n > this.data.length)
866
- throw this.err("offsetReader: Unexpected end of buffer");
867
- return new __Reader(this.absBytes(n), this.opts, this.stack, this, n);
868
- }
869
- bytes(n, peek = false) {
870
- if (this.bitPos)
871
- throw this.err("readBytes: bitPos not empty");
872
- if (!Number.isFinite(n))
873
- throw this.err(`readBytes: wrong length=${n}`);
874
- if (this.pos + n > this.data.length)
875
- throw this.err("readBytes: Unexpected end of buffer");
876
- const slice = this.data.subarray(this.pos, this.pos + n);
877
- if (!peek)
878
- this.markBytes(n);
879
- return slice;
880
- }
881
- byte(peek = false) {
882
- if (this.bitPos)
883
- throw this.err("readByte: bitPos not empty");
884
- if (this.pos + 1 > this.data.length)
885
- throw this.err("readBytes: Unexpected end of buffer");
886
- const data = this.data[this.pos];
887
- if (!peek)
888
- this.markBytes(1);
889
- return data;
890
- }
891
- get leftBytes() {
892
- return this.data.length - this.pos;
893
- }
894
- get totalBytes() {
895
- return this.data.length;
896
- }
897
- isEnd() {
898
- return this.pos >= this.data.length && !this.bitPos;
899
- }
900
- // bits are read in BE mode (left to right): (0b1000_0000).readBits(1) == 1
901
- bits(bits) {
902
- if (bits > 32)
903
- throw this.err("BitReader: cannot read more than 32 bits in single call");
904
- let out = 0;
905
- while (bits) {
906
- if (!this.bitPos) {
907
- this.bitBuf = this.byte();
908
- this.bitPos = 8;
909
- }
910
- const take = Math.min(bits, this.bitPos);
911
- this.bitPos -= take;
912
- out = out << take | this.bitBuf >> this.bitPos & 2 ** take - 1;
913
- this.bitBuf &= 2 ** this.bitPos - 1;
914
- bits -= take;
915
- }
916
- return out >>> 0;
917
- }
918
- find(needle, pos = this.pos) {
919
- if (!isBytes(needle))
920
- throw this.err(`find: needle is not bytes! ${needle}`);
921
- if (this.bitPos)
922
- throw this.err("findByte: bitPos not empty");
923
- if (!needle.length)
924
- throw this.err(`find: needle is empty`);
925
- for (let idx = pos; (idx = this.data.indexOf(needle[0], idx)) !== -1; idx++) {
926
- if (idx === -1)
927
- return;
928
- const leftBytes = this.data.length - idx;
929
- if (leftBytes < needle.length)
930
- return;
931
- if (equalBytes(needle, this.data.subarray(idx, idx + needle.length)))
932
- return idx;
933
- }
934
- return;
935
- }
936
- };
937
- var _Writer = class {
938
- pos = 0;
939
- stack;
940
- // We could have a single buffer here and re-alloc it with
941
- // x1.5-2 size each time it full, but it will be slower:
942
- // basic/encode bench: 395ns -> 560ns
943
- buffers = [];
944
- ptrs = [];
945
- bitBuf = 0;
946
- bitPos = 0;
947
- viewBuf = new Uint8Array(8);
948
- view;
949
- finished = false;
950
- constructor(stack = []) {
951
- this.stack = stack;
952
- this.view = createView(this.viewBuf);
953
- }
954
- pushObj(obj, objFn) {
955
- return Path.pushObj(this.stack, obj, objFn);
956
- }
957
- writeView(len, fn) {
958
- if (this.finished)
959
- throw this.err("buffer: finished");
960
- if (!isNum(len) || len > 8)
961
- throw new Error(`wrong writeView length=${len}`);
962
- fn(this.view);
963
- this.bytes(this.viewBuf.slice(0, len));
964
- this.viewBuf.fill(0);
965
- }
966
- // User methods
967
- err(msg) {
968
- if (this.finished)
969
- throw this.err("buffer: finished");
970
- return Path.err("Reader", this.stack, msg);
971
- }
972
- bytes(b) {
973
- if (this.finished)
974
- throw this.err("buffer: finished");
975
- if (this.bitPos)
976
- throw this.err("writeBytes: ends with non-empty bit buffer");
977
- this.buffers.push(b);
978
- this.pos += b.length;
979
- }
980
- byte(b) {
981
- if (this.finished)
982
- throw this.err("buffer: finished");
983
- if (this.bitPos)
984
- throw this.err("writeByte: ends with non-empty bit buffer");
985
- this.buffers.push(new Uint8Array([b]));
986
- this.pos++;
987
- }
988
- finish(clean = true) {
989
- if (this.finished)
990
- throw this.err("buffer: finished");
991
- if (this.bitPos)
992
- throw this.err("buffer: ends with non-empty bit buffer");
993
- const buffers = this.buffers.concat(this.ptrs.map((i) => i.buffer));
994
- const sum = buffers.map((b) => b.length).reduce((a, b) => a + b, 0);
995
- const buf = new Uint8Array(sum);
996
- for (let i = 0, pad = 0; i < buffers.length; i++) {
997
- const a = buffers[i];
998
- buf.set(a, pad);
999
- pad += a.length;
1000
- }
1001
- for (let pos = this.pos, i = 0; i < this.ptrs.length; i++) {
1002
- const ptr = this.ptrs[i];
1003
- buf.set(ptr.ptr.encode(pos), ptr.pos);
1004
- pos += ptr.buffer.length;
1005
- }
1006
- if (clean) {
1007
- this.buffers = [];
1008
- for (const p of this.ptrs)
1009
- p.buffer.fill(0);
1010
- this.ptrs = [];
1011
- this.finished = true;
1012
- this.bitBuf = 0;
1013
- }
1014
- return buf;
1015
- }
1016
- bits(value, bits) {
1017
- if (bits > 32)
1018
- throw this.err("writeBits: cannot write more than 32 bits in single call");
1019
- if (value >= 2 ** bits)
1020
- throw this.err(`writeBits: value (${value}) >= 2**bits (${bits})`);
1021
- while (bits) {
1022
- const take = Math.min(bits, 8 - this.bitPos);
1023
- this.bitBuf = this.bitBuf << take | value >> bits - take;
1024
- this.bitPos += take;
1025
- bits -= take;
1026
- value &= 2 ** bits - 1;
1027
- if (this.bitPos === 8) {
1028
- this.bitPos = 0;
1029
- this.buffers.push(new Uint8Array([this.bitBuf]));
1030
- this.pos++;
1031
- }
1032
- }
1033
- }
1034
- };
1035
- function _wrap(inner) {
1036
- return {
1037
- // NOTE: we cannot export validate here, since it is likely mistake.
1038
- encodeStream: inner.encodeStream,
1039
- decodeStream: inner.decodeStream,
1040
- size: inner.size,
1041
- encode: (value) => {
1042
- const w = new _Writer();
1043
- inner.encodeStream(w, value);
1044
- return w.finish();
1045
- },
1046
- decode: (data, opts = {}) => {
1047
- const r = new _Reader(data, opts);
1048
- const res = inner.decodeStream(r);
1049
- r.finish();
1050
- return res;
1051
- }
1052
- };
1053
- }
1054
- function validate(inner, fn) {
1055
- if (!isCoder(inner))
1056
- throw new Error(`validate: invalid inner value ${inner}`);
1057
- if (typeof fn !== "function")
1058
- throw new Error("validate: fn should be function");
1059
- return _wrap({
1060
- size: inner.size,
1061
- encodeStream: (w, value) => {
1062
- let res;
1063
- try {
1064
- res = fn(value);
1065
- } catch (e) {
1066
- throw w.err(e);
1067
- }
1068
- inner.encodeStream(w, res);
1069
- },
1070
- decodeStream: (r) => {
1071
- const res = inner.decodeStream(r);
1072
- try {
1073
- return fn(res);
1074
- } catch (e) {
1075
- throw r.err(e);
1076
- }
1077
- }
1078
- });
1079
- }
1080
- var wrap = (inner) => {
1081
- const res = _wrap(inner);
1082
- return inner.validate ? validate(res, inner.validate) : res;
1083
- };
1084
- var isBaseCoder = (elm) => isPlainObject(elm) && typeof elm.decode === "function" && typeof elm.encode === "function";
1085
- function isCoder(elm) {
1086
- return isPlainObject(elm) && isBaseCoder(elm) && typeof elm.encodeStream === "function" && typeof elm.decodeStream === "function" && (elm.size === void 0 || isNum(elm.size));
1087
- }
1088
- var view = (len, opts) => wrap({
1089
- size: len,
1090
- encodeStream: (w, value) => w.writeView(len, (view2) => opts.write(view2, value)),
1091
- decodeStream: (r) => r.readView(len, opts.read),
1092
- validate: (value) => {
1093
- if (typeof value !== "number")
1094
- throw new Error(`viewCoder: expected number, got ${typeof value}`);
1095
- if (opts.validate)
1096
- opts.validate(value);
1097
- return value;
1098
- }
1099
- });
1100
- var intView = (len, signed, opts) => {
1101
- const bits = len * 8;
1102
- const maxVal = 2 ** bits;
1103
- const validateUnsigned = (value) => {
1104
- if (!isNum(value))
1105
- throw new Error(`uintView: value is not safe integer: ${value}`);
1106
- if (0 > value || value >= maxVal) {
1107
- throw new Error(`uintView: value out of bounds. Expected 0 <= ${value} < ${maxVal}`);
1108
- }
1109
- };
1110
- return view(len, {
1111
- write: opts.write,
1112
- read: opts.read,
1113
- validate: validateUnsigned
1114
- });
1115
- };
1116
- var U32LE = /* @__PURE__ */ intView(4, false, {
1117
- read: (view2, pos) => view2.getUint32(pos, true),
1118
- write: (view2, value) => view2.setUint32(0, value, true)
1119
- });
1120
- var U16LE = /* @__PURE__ */ intView(2, false, {
1121
- read: (view2, pos) => view2.getUint16(pos, true),
1122
- write: (view2, value) => view2.setUint16(0, value, true)
1123
- });
1124
- var U8 = /* @__PURE__ */ intView(1, false, {
1125
- read: (view2, pos) => view2.getUint8(pos),
1126
- write: (view2, value) => view2.setUint8(0, value)
1127
- });
1128
720
  var ARKADE_OP = {
1129
721
  // Merkle Branch Verification (0xb3 — repurposed NOP4 slot)
1130
722
  MERKLEBRANCHVERIFY: 179,
723
+ PUT: 187,
1131
724
  // Digest (0xc3)
1132
725
  DIGEST: 195,
1133
726
  // SHA256 Streaming (0xc4-0xc6)
@@ -1159,7 +752,10 @@ var ARKADE_OP = {
1159
752
  BIN2NUM: 216,
1160
753
  REVERSEBYTES: 217,
1161
754
  MODEXP: 218,
1162
- // 0xdb-0xdf are unassigned (OP_UNKNOWN219-223)
755
+ // VTXO Expiry & Emulator Clock (0xdb-0xdc)
756
+ PUSHEXPIRY: 219,
757
+ CHECKTIME: 220,
758
+ // 0xdd-0xdf are unassigned (OP_UNKNOWN221-223)
1163
759
  // EC Operations (0xe0-0xe2)
1164
760
  ECADD: 224,
1165
761
  ECMUL: 225,
@@ -1188,7 +784,10 @@ var ARKADE_OP = {
1188
784
  INSPECTPACKET: 244,
1189
785
  INSPECTINPUTPACKET: 245,
1190
786
  // Signature Hash (0xf6)
1191
- SIGHASH: 246
787
+ SIGHASH: 246,
788
+ // Continuation & Intent Introspection (0xf7-0xf8)
789
+ TUNNEL: 247,
790
+ INSPECTINTENTMESSAGE: 248
1192
791
  };
1193
792
  var ARKADE_OPCODES = Object.values(ARKADE_OP);
1194
793
  var ARKADE_OPCODE_NAMES = Object.fromEntries(
@@ -1256,7 +855,7 @@ function getOpcodeValue(name) {
1256
855
 
1257
856
  // src/arkade/bignum.ts
1258
857
  var bignum_exports = {};
1259
- chunk5BLDMQED_cjs.__export(bignum_exports, {
858
+ chunk5XBH5SAL_cjs.__export(bignum_exports, {
1260
859
  BIGNUM_MAX_BYTES: () => BIGNUM_MAX_BYTES,
1261
860
  decode: () => decode,
1262
861
  encode: () => encode
@@ -1284,7 +883,7 @@ var ArkadeOPNames = {};
1284
883
  for (const [k, v] of Object.entries(ARKADE_OPS)) {
1285
884
  if (typeof v === "number") ArkadeOPNames[v] = k;
1286
885
  }
1287
- var ArkadeScript = wrap({
886
+ var ArkadeScript = P__namespace.wrap({
1288
887
  encodeStream: (w, value) => {
1289
888
  for (let o of value) {
1290
889
  if (typeof o === "string") {
@@ -1310,10 +909,10 @@ var ArkadeScript = wrap({
1310
909
  w.byte(len);
1311
910
  } else if (len <= 65535) {
1312
911
  w.byte(btcSigner.OP.PUSHDATA2);
1313
- w.bytes(U16LE.encode(len));
912
+ w.bytes(P__namespace.U16LE.encode(len));
1314
913
  } else {
1315
914
  w.byte(btcSigner.OP.PUSHDATA4);
1316
- w.bytes(U32LE.encode(len));
915
+ w.bytes(P__namespace.U32LE.encode(len));
1317
916
  }
1318
917
  w.bytes(o);
1319
918
  }
@@ -1325,9 +924,9 @@ var ArkadeScript = wrap({
1325
924
  if (btcSigner.OP.OP_0 < cur && cur <= btcSigner.OP.PUSHDATA4) {
1326
925
  let len;
1327
926
  if (cur < btcSigner.OP.PUSHDATA1) len = cur;
1328
- else if (cur === btcSigner.OP.PUSHDATA1) len = U8.decodeStream(r);
1329
- else if (cur === btcSigner.OP.PUSHDATA2) len = U16LE.decodeStream(r);
1330
- else if (cur === btcSigner.OP.PUSHDATA4) len = U32LE.decodeStream(r);
927
+ else if (cur === btcSigner.OP.PUSHDATA1) len = P__namespace.U8.decodeStream(r);
928
+ else if (cur === btcSigner.OP.PUSHDATA2) len = P__namespace.U16LE.decodeStream(r);
929
+ else if (cur === btcSigner.OP.PUSHDATA4) len = P__namespace.U32LE.decodeStream(r);
1331
930
  else throw new Error("Should be not possible");
1332
931
  out.push(r.bytes(len));
1333
932
  } else if (cur === 0) {
@@ -1445,7 +1044,7 @@ function computeArkadeScriptPublicKey(pubKey, script) {
1445
1044
  // src/script/vhtlc.ts
1446
1045
  exports.VHTLC = void 0;
1447
1046
  ((VHTLC2) => {
1448
- class BaseScript extends chunkJZWLXNHV_cjs.VtxoScript {
1047
+ class BaseScript extends chunk5XBH5SAL_cjs.VtxoScript {
1449
1048
  options;
1450
1049
  claimScript;
1451
1050
  refundScript;
@@ -1472,27 +1071,27 @@ exports.VHTLC = void 0;
1472
1071
  unilateralRefundWithoutReceiverDelay
1473
1072
  } = options;
1474
1073
  const conditionScript = preimageCondition(preimageHash);
1475
- const claimScript = chunkJZWLXNHV_cjs.ConditionMultisigTapscript.encode({
1074
+ const claimScript = chunk5XBH5SAL_cjs.ConditionMultisigTapscript.encode({
1476
1075
  conditionScript,
1477
1076
  pubkeys: [receiver, server]
1478
1077
  }).script;
1479
- const refundScript = chunkJZWLXNHV_cjs.MultisigTapscript.encode({
1078
+ const refundScript = chunk5XBH5SAL_cjs.MultisigTapscript.encode({
1480
1079
  pubkeys: [sender, receiver, server]
1481
1080
  }).script;
1482
- const refundWithoutReceiverScript = chunkJZWLXNHV_cjs.CLTVMultisigTapscript.encode({
1081
+ const refundWithoutReceiverScript = chunk5XBH5SAL_cjs.CLTVMultisigTapscript.encode({
1483
1082
  absoluteTimelock: refundLocktime,
1484
1083
  pubkeys: [sender, server]
1485
1084
  }).script;
1486
- const unilateralClaimScript = chunkJZWLXNHV_cjs.ConditionCSVMultisigTapscript.encode({
1085
+ const unilateralClaimScript = chunk5XBH5SAL_cjs.ConditionCSVMultisigTapscript.encode({
1487
1086
  conditionScript,
1488
1087
  timelock: unilateralClaimDelay,
1489
1088
  pubkeys: [receiver]
1490
1089
  }).script;
1491
- const unilateralRefundScript = chunkJZWLXNHV_cjs.CSVMultisigTapscript.encode({
1090
+ const unilateralRefundScript = chunk5XBH5SAL_cjs.CSVMultisigTapscript.encode({
1492
1091
  timelock: unilateralRefundDelay,
1493
1092
  pubkeys: [sender, receiver]
1494
1093
  }).script;
1495
- const unilateralRefundWithoutReceiverScript = chunkJZWLXNHV_cjs.CSVMultisigTapscript.encode({
1094
+ const unilateralRefundWithoutReceiverScript = chunk5XBH5SAL_cjs.CSVMultisigTapscript.encode({
1496
1095
  timelock: unilateralRefundWithoutReceiverDelay,
1497
1096
  pubkeys: [sender]
1498
1097
  }).script;
@@ -1512,7 +1111,7 @@ exports.VHTLC = void 0;
1512
1111
  const covenants = options.nonInteractiveParameters;
1513
1112
  if (covenants) {
1514
1113
  arkadeScriptNic = enforcePayToMaybeAsset(covenants.receiverPkScript, options.asset);
1515
- nonInteractiveClaimScript = chunkJZWLXNHV_cjs.ConditionMultisigTapscript.encode({
1114
+ nonInteractiveClaimScript = chunk5XBH5SAL_cjs.ConditionMultisigTapscript.encode({
1516
1115
  conditionScript,
1517
1116
  pubkeys: [
1518
1117
  server,
@@ -1525,12 +1124,12 @@ exports.VHTLC = void 0;
1525
1124
  covenants.emulatorPubkey,
1526
1125
  arkadeScriptNir
1527
1126
  );
1528
- nonInteractiveRefundScript = chunkJZWLXNHV_cjs.MultisigTapscript.encode({
1127
+ nonInteractiveRefundScript = chunk5XBH5SAL_cjs.MultisigTapscript.encode({
1529
1128
  pubkeys: [server, receiver, nirCosigner]
1530
1129
  }).script;
1531
1130
  scripts.push(nonInteractiveRefundScript);
1532
1131
  if (covenants.legacy !== "preTimelockedRefund") {
1533
- nonInteractiveRefundWithoutReceiverScript = chunkJZWLXNHV_cjs.CLTVMultisigTapscript.encode({
1132
+ nonInteractiveRefundWithoutReceiverScript = chunk5XBH5SAL_cjs.CLTVMultisigTapscript.encode({
1534
1133
  absoluteTimelock: refundLocktime,
1535
1134
  pubkeys: [server, nirCosigner]
1536
1135
  }).script;
@@ -1609,54 +1208,19 @@ exports.VHTLC = void 0;
1609
1208
  /**
1610
1209
  * Return the timelocked non-interactive refund tapleaf and its ArkadeScript.
1611
1210
  *
1612
- * SPENDING THIS LEAF, CONCRETELY — confirmed from this SDK's own
1613
- * emulator client and covenant-spend builder ({@link
1614
- * EmulatorProvider} in `src/providers/emulator.ts`, and {@link
1615
- * ArkadeTransactionBuilder} in `src/arkade/contract.ts`), which is
1616
- * the general machinery every covenant leaf in this file goes
1617
- * through:
1618
- *
1619
- * 1. Build the ark tx spending this leaf (this method's {@link
1620
- * TapLeafScript} as `tapLeafScript`, this script's {@link
1621
- * VtxoScript.encode} as `tapTree`), plus its checkpoint tx.
1622
- * 2. Attach the ArkadeScript this method returns to the spent
1623
- * input via an `EmulatorPacket` (type 1) — `{ vin, script:
1624
- * <this ArkadeScript>, witness: <empty> }`, empty because the
1625
- * script pushes its own input/output index with
1626
- * `PUSHCURRENTINPUTINDEX` rather than reading one from the
1627
- * witness — wrapped in an `Extension` OP_RETURN output on the
1628
- * ark tx.
1629
- * 3. Attach the spent input's OWN creating ark tx as `PrevArkTx` on
1630
- * input 0 — required so the emulator can resolve that input's
1631
- * prevout pkScript/value; it does not otherwise have them.
1632
- * 4. POST the (base64-PSBT) ark tx and checkpoint(s) as `{ arkTx,
1633
- * checkpointTxs }` to the emulator's `POST /v1/tx`.
1211
+ * Spent through the generic covenant path ({@link EmulatorProvider},
1212
+ * {@link ArkadeTransactionBuilder}): build the ark tx on this leaf plus its checkpoint;
1213
+ * attach this ArkadeScript to the input in an `EmulatorPacket` (type 1, empty witness:
1214
+ * the script pushes its own index with `PUSHCURRENTINPUTINDEX`) inside an `Extension`
1215
+ * OP_RETURN; attach the input's creating ark tx as `PrevArkTx` (the emulator can't
1216
+ * otherwise resolve its prevout); POST to the emulator's `/v1/tx`. The emulator co-signs
1217
+ * for `nirCosigner` only if `enforcePayTo(senderPkScript)` holds, and finalizes with arkd.
1218
+ * `server`'s signature is still required at consensus level, outside the covenant.
1634
1219
  *
1635
- * THE COVENANT CHECK the emulator runs against that ArkadeScript —
1636
- * `enforcePayTo(senderPkScript)`, see that function above — is: the
1637
- * output at this SAME input's index is a v1 P2TR output paying
1638
- * `senderPkScript`, with a value at least the input's. Only on that
1639
- * check passing does the emulator sign for `nirCosigner` (the
1640
- * `emulatorPubkey` tweaked by this ArkadeScript's hash); the
1641
- * response carries the fully co-signed `signedArkTx` and
1642
- * `signedCheckpointTxs` — `ArkadeTransactionBuilder.send()`'s own
1643
- * comment on this path: "the emulator executes the arkade script
1644
- * and finalizes with arkd" — no separate call to arkd is made by
1645
- * this SDK for a covenant spend.
1646
- * Neither `server` nor `receiver` play any part in that check: this
1647
- * leaf's tapscript still requires `server`'s own signature
1648
- * alongside `nirCosigner`'s (see the class doc above), but that is
1649
- * consensus-level multisig, not something the covenant enforces.
1650
- *
1651
- * NOT SPENDABLE UNTIL `refundLocktime` MATURES — the tapscript's
1652
- * `OP_CHECKLOCKTIMEVERIFY` is arkd's concern, not the emulator's;
1653
- * the emulator will happily co-sign an immature spend and arkd will
1654
- * then refuse it. A block-height-typed `refundLocktime` (below the
1655
- * standard height/timestamp boundary this SDK names
1656
- * `CLTV_HEIGHT_THRESHOLD`, 500,000,000, in
1657
- * `src/contracts/handlers/helpers.ts`) is refused by arkd for a
1658
- * forfeit-eligible leaf independent of maturity — use a
1659
- * seconds-typed (absolute Unix timestamp) value.
1220
+ * The emulator does not check `refundLocktime`: it co-signs an immature spend and arkd's
1221
+ * CLTV refuses it. arkd also refuses a block-height `refundLocktime`
1222
+ * (< `CLTV_HEIGHT_THRESHOLD`, 500,000,000) on a forfeit-eligible leaf regardless of
1223
+ * maturity: use a seconds-typed (Unix timestamp) value.
1660
1224
  */
1661
1225
  nonInteractiveRefundWithoutReceiver() {
1662
1226
  if (!this.nonInteractiveRefundWithoutReceiverScript || !this.nonInteractiveRefundWithoutReceiverArkadeScript) {
@@ -1799,10 +1363,7 @@ function enforcePayToAsset(destinationPkScript, asset) {
1799
1363
  }
1800
1364
  const inspectionTxid = Uint8Array.from(asset.txid).reverse();
1801
1365
  return ArkadeScript.encode([
1802
- // The output carries at least as much of the asset as the input did.
1803
- // Output index is the input's -- the same index alignment the sat
1804
- // covenant relies on, and the same liveness obligation on whoever
1805
- // assembles the spend.
1366
+ // The output at the input's index carries at least the input's amount of the asset.
1806
1367
  "PUSHCURRENTINPUTINDEX",
1807
1368
  inspectionTxid,
1808
1369
  asset.groupIndex,
@@ -1844,9 +1405,9 @@ var VHTLCContractHandler = {
1844
1405
  server: base.hex.encode(params.server),
1845
1406
  hash: base.hex.encode(params.preimageHash),
1846
1407
  refundLocktime: params.refundLocktime.toString(),
1847
- claimDelay: chunkJZWLXNHV_cjs.timelockToSequence(params.unilateralClaimDelay).toString(),
1848
- refundDelay: chunkJZWLXNHV_cjs.timelockToSequence(params.unilateralRefundDelay).toString(),
1849
- refundNoReceiverDelay: chunkJZWLXNHV_cjs.timelockToSequence(
1408
+ claimDelay: chunk5XBH5SAL_cjs.timelockToSequence(params.unilateralClaimDelay).toString(),
1409
+ refundDelay: chunk5XBH5SAL_cjs.timelockToSequence(params.unilateralRefundDelay).toString(),
1410
+ refundNoReceiverDelay: chunk5XBH5SAL_cjs.timelockToSequence(
1850
1411
  params.unilateralRefundWithoutReceiverDelay
1851
1412
  ).toString()
1852
1413
  };
@@ -1858,147 +1419,26 @@ var VHTLCContractHandler = {
1858
1419
  server: base.hex.decode(params.server),
1859
1420
  preimageHash: base.hex.decode(params.hash),
1860
1421
  refundLocktime: BigInt(params.refundLocktime),
1861
- unilateralClaimDelay: chunkJZWLXNHV_cjs.sequenceToTimelock(Number(params.claimDelay)),
1862
- unilateralRefundDelay: chunkJZWLXNHV_cjs.sequenceToTimelock(Number(params.refundDelay)),
1863
- unilateralRefundWithoutReceiverDelay: chunkJZWLXNHV_cjs.sequenceToTimelock(
1422
+ unilateralClaimDelay: chunk5XBH5SAL_cjs.sequenceToTimelock(Number(params.claimDelay)),
1423
+ unilateralRefundDelay: chunk5XBH5SAL_cjs.sequenceToTimelock(Number(params.refundDelay)),
1424
+ unilateralRefundWithoutReceiverDelay: chunk5XBH5SAL_cjs.sequenceToTimelock(
1864
1425
  Number(params.refundNoReceiverDelay)
1865
1426
  )
1866
1427
  };
1867
1428
  },
1868
1429
  /**
1869
- * Select spending path based on context.
1870
- *
1871
- * Role is determined from `context.role` or by matching
1872
- * `context.walletDescriptor` (preferred) / `context.walletPubKey`
1873
- * against sender/receiver in contract params.
1430
+ * Select spending path based on context. Role comes from `context.role` or from matching
1431
+ * `context.walletDescriptor` against sender/receiver.
1874
1432
  */
1875
1433
  selectPath(script, contract, context) {
1876
- const role = resolveRole(contract, context);
1877
- const preimage = contract.params?.preimage;
1878
- const refundLocktime = BigInt(contract.params.refundLocktime);
1879
- if (!role) {
1880
- return null;
1881
- }
1882
- if (context.collaborative) {
1883
- if (role === "receiver" && preimage) {
1884
- return {
1885
- leaf: script.claim(),
1886
- extraWitness: [base.hex.decode(preimage)]
1887
- };
1888
- }
1889
- if (role === "sender" && isCltvSatisfied(context, refundLocktime)) {
1890
- return {
1891
- leaf: script.refundWithoutReceiver()
1892
- };
1893
- }
1894
- return null;
1895
- }
1896
- if (role === "receiver" && preimage) {
1897
- const sequence = Number(contract.params.claimDelay);
1898
- if (!isCsvSpendable(context, sequence)) return null;
1899
- return {
1900
- leaf: script.unilateralClaim(),
1901
- extraWitness: [base.hex.decode(preimage)],
1902
- sequence
1903
- };
1904
- }
1905
- if (role === "sender") {
1906
- const sequence = Number(contract.params.refundNoReceiverDelay);
1907
- if (!isCsvSpendable(context, sequence)) return null;
1908
- return {
1909
- leaf: script.unilateralRefundWithoutReceiver(),
1910
- sequence
1911
- };
1912
- }
1913
- return null;
1434
+ return selectVhtlcPath(script, contract, context);
1914
1435
  },
1915
- /**
1916
- * Get all possible spending paths (no timelock checks).
1917
- *
1918
- * Role is determined from `context.role` or by matching
1919
- * `context.walletDescriptor` (preferred) / `context.walletPubKey`
1920
- * against sender/receiver in contract params.
1921
- */
1436
+ /** All possible spending paths (no timelock checks); role as in {@link selectPath}. */
1922
1437
  getAllSpendingPaths(script, contract, context) {
1923
- const role = resolveRole(contract, context);
1924
- const paths = [];
1925
- if (!role) {
1926
- return paths;
1927
- }
1928
- const preimage = contract.params?.preimage;
1929
- if (context.collaborative) {
1930
- if (role === "receiver" && preimage) {
1931
- paths.push({
1932
- leaf: script.claim(),
1933
- extraWitness: [base.hex.decode(preimage)]
1934
- });
1935
- }
1936
- if (role === "sender") {
1937
- paths.push({
1938
- leaf: script.refundWithoutReceiver()
1939
- });
1940
- }
1941
- } else {
1942
- if (role === "receiver" && preimage) {
1943
- const sequence = Number(contract.params.claimDelay);
1944
- paths.push({
1945
- leaf: script.unilateralClaim(),
1946
- extraWitness: [base.hex.decode(preimage)],
1947
- sequence
1948
- });
1949
- }
1950
- if (role === "sender") {
1951
- const sequence = Number(contract.params.refundNoReceiverDelay);
1952
- paths.push({
1953
- leaf: script.unilateralRefundWithoutReceiver(),
1954
- sequence
1955
- });
1956
- }
1957
- }
1958
- return paths;
1438
+ return vhtlcAllSpendingPaths(script, contract, context);
1959
1439
  },
1960
1440
  getSpendablePaths(script, contract, context) {
1961
- const role = resolveRole(contract, context);
1962
- const paths = [];
1963
- if (!role) {
1964
- return paths;
1965
- }
1966
- const preimage = contract.params?.preimage;
1967
- const refundLocktime = BigInt(contract.params.refundLocktime);
1968
- if (context.collaborative) {
1969
- if (role === "receiver" && preimage) {
1970
- paths.push({
1971
- leaf: script.claim(),
1972
- extraWitness: [base.hex.decode(preimage)]
1973
- });
1974
- }
1975
- if (role === "sender" && isCltvSatisfied(context, refundLocktime)) {
1976
- paths.push({
1977
- leaf: script.refundWithoutReceiver()
1978
- });
1979
- }
1980
- return paths;
1981
- }
1982
- if (role === "receiver" && preimage) {
1983
- const sequence = Number(contract.params.claimDelay);
1984
- if (isCsvSpendable(context, sequence)) {
1985
- paths.push({
1986
- leaf: script.unilateralClaim(),
1987
- extraWitness: [base.hex.decode(preimage)],
1988
- sequence
1989
- });
1990
- }
1991
- }
1992
- if (role === "sender") {
1993
- const sequence = Number(contract.params.refundNoReceiverDelay);
1994
- if (isCsvSpendable(context, sequence)) {
1995
- paths.push({
1996
- leaf: script.unilateralRefundWithoutReceiver(),
1997
- sequence
1998
- });
1999
- }
2000
- }
2001
- return paths;
1441
+ return vhtlcSpendablePaths(script, contract, context);
2002
1442
  },
2003
1443
  /**
2004
1444
  * Refuse an explicit spend of a lockup whose refund path has not opened.
@@ -2009,70 +1449,38 @@ var VHTLCContractHandler = {
2009
1449
  assertVhtlcSpendableNow(contract, context);
2010
1450
  },
2011
1451
  /**
2012
- * Never. A live VHTLC is escrow: the counterparty's claim leaf is armed,
2013
- * and generic selection — send, settle, renewal, offboard — would move the
2014
- * lockup out from under a swap the counterparty is still entitled to
2015
- * complete, or race a claim already in flight.
2016
- *
2017
- * Two narrow reasons, and neither is "spending this would destroy the
2018
- * VTXO". It would not: the leaf {@link deriveTapscripts} stamps is
2019
- * `refundWithoutReceiver` — `CLTV[sender, server]`, the sender's OWN
2020
- * refund, which the server rejects until `refundLocktime` matures. The
2021
- * reasons are that an escrowed lockup must not count toward the
2022
- * `available` balance bucket, and that generic RENEWAL must not silently
2023
- * execute a refund the caller never asked for — `runPeriodicSettle` selects
2024
- * through `getSpendableVtxos`, which this gate filters, and it runs
2025
- * unprompted whenever a wallet is built without an explicit
2026
- * `settlementConfig`.
1452
+ * Never. A live VHTLC is escrow: generic selection (send, settle, renewal, offboard) would
1453
+ * move the lockup out from under a swap the counterparty may still complete, or race a claim.
2027
1454
  *
2028
- * **Inseparable from {@link deriveTapscripts}.** Deriving the leaf without
2029
- * closing the gate hands generic renewal an escrow it had never been
2030
- * offered before; before that method existed the answer here was
2031
- * unobservable, so the two only ever made sense together.
1455
+ * The stamped leaf is the sender's own CLTV refund, so this is not about destroying the
1456
+ * VTXO: an escrowed lockup must not count toward the `available` balance, and generic
1457
+ * renewal (`runPeriodicSettle`, unprompted without an explicit `settlementConfig`) must not
1458
+ * silently execute a refund nobody asked for.
2032
1459
  *
2033
- * Recovery is filtered on {@link assertSpendableNow}, not on this: the gate
2034
- * is permanent, and applying it there would strand a matured lockup.
1460
+ * **Inseparable from {@link deriveTapscripts}**: deriving the leaf without closing this gate
1461
+ * hands renewal an escrow. Recovery filters on {@link assertSpendableNow} instead; this
1462
+ * permanent gate would strand a matured lockup.
2035
1463
  */
2036
1464
  isGenericallySpendable: () => false,
2037
1465
  /**
2038
1466
  * The annotation leaf stamped onto every VTXO locked to this contract.
2039
1467
  *
2040
- * **Without this the contract is unusable, not merely unoptimized.**
2041
- * `deriveContractTapscripts` falls back to `script.forfeit()` for any
2042
- * handler that does not implement {@link TapscriptDeriving}, and no VHTLC
2043
- * script version has a `forfeit()` — `VtxoScript` does not define one and
2044
- * `VHTLC.BaseScript` does not add one. The fallback therefore threw
2045
- * `legacy.forfeit is not a function`, `annotatableIn` caught it, and
2046
- * `fetchContractVtxosBulk` dropped this contract's VTXOs before they were
2047
- * persisted. The row existed and was watched while its balance stayed
2048
- * permanently invisible, and `getSyncState()` reported `degraded` forever.
1468
+ * **Required, not an optimization.** Without it `deriveContractTapscripts` falls back to
1469
+ * `script.forfeit()`, which no VHTLC script has, so the contract's VTXOs are dropped before
1470
+ * persisting: balance invisible, `getSyncState()` degraded forever.
2049
1471
  *
2050
- * `refundWithoutReceiver` is the leaf, for both roles the annotation
2051
- * serves, because it is the only collaborative path this wallet can
2052
- * actually satisfy as the sender — the same conclusion `selectPath`
2053
- * reaches, kept in step with it deliberately. The claim leaves belong to
2054
- * the receiver and need a preimage the sender does not have; `refund` and
2055
- * `unilateralRefund` both need the counterparty's signature, which this
2056
- * protocol has no message to ask for. V1 has no covenant leaves at all.
1472
+ * `refundWithoutReceiver` is the only collaborative path this wallet can satisfy as sender
1473
+ * (kept in step with `selectPath`): the claim leaves need the preimage, and `refund` /
1474
+ * `unilateralRefund` need a counterparty signature the protocol can't request. V1 has no
1475
+ * covenant leaves.
2057
1476
  *
2058
- * **It carries a CLTV, and callers must respect it.** A settlement built
2059
- * on this leaf is only valid once `refundLocktime` has matured, so a
2060
- * recovery round that sweeps this VTXO early is rejected by the server.
2061
- * Nothing in this handler can enforce that, because the annotation is
2062
- * derived per contract and knows no clock; `recoverVtxos` filters on
2063
- * {@link assertSpendableNow} for it.
2064
- *
2065
- * **Role-blind.** A receiver's row gets the same leaf, which names keys that
2066
- * wallet does not hold, so it is satisfiable only by the wallet holding the
2067
- * lockup's `sender` key and fails at intent registration for anyone else.
1477
+ * **It carries a CLTV**: a settlement on it is rejected until `refundLocktime` matures, and
1478
+ * the per-contract annotation knows no clock, so `recoverVtxos` filters on
1479
+ * {@link assertSpendableNow}. **Role-blind**: a receiver's row gets the same leaf, satisfiable
1480
+ * only by the `sender` key holder; anyone else fails at intent registration.
2068
1481
  */
2069
1482
  deriveTapscripts(script) {
2070
- const leaf = script.refundWithoutReceiver();
2071
- return {
2072
- forfeitTapLeafScript: leaf,
2073
- intentTapLeafScript: leaf,
2074
- tapTree: script.encode()
2075
- };
1483
+ return deriveVhtlcTapscripts(script);
2076
1484
  }
2077
1485
  };
2078
1486
  var parseGroupIndex = (raw) => {
@@ -2106,48 +1514,26 @@ var VHTLCV2ContractHandler = {
2106
1514
  server: base.hex.encode(params.server),
2107
1515
  hash: base.hex.encode(params.preimageHash),
2108
1516
  refundLocktime: params.refundLocktime.toString(),
2109
- claimDelay: chunkJZWLXNHV_cjs.timelockToSequence(params.unilateralClaimDelay).toString(),
2110
- refundDelay: chunkJZWLXNHV_cjs.timelockToSequence(params.unilateralRefundDelay).toString(),
2111
- refundNoReceiverDelay: chunkJZWLXNHV_cjs.timelockToSequence(
1517
+ claimDelay: chunk5XBH5SAL_cjs.timelockToSequence(params.unilateralClaimDelay).toString(),
1518
+ refundDelay: chunk5XBH5SAL_cjs.timelockToSequence(params.unilateralRefundDelay).toString(),
1519
+ refundNoReceiverDelay: chunk5XBH5SAL_cjs.timelockToSequence(
2112
1520
  params.unilateralRefundWithoutReceiverDelay
2113
1521
  ).toString(),
2114
- // The on-disk keys keep their per-leaf names even though the typed
2115
- // param is ONE group: rows written by older SDKs carry exactly
2116
- // these keys, and changing the storage encoding would orphan them.
2117
- // The group maps onto them without loss — one emulator key serves
2118
- // both covenant destinations by construction (see the option's doc
2119
- // on VHTLC.Options), so the two emulator-key columns always hold
2120
- // the same value on a row written from here.
2121
- //
2122
- // Spread rather than written as `undefined`: a `Record<string,
2123
- // string>` round-tripped through a repository must not gain keys
2124
- // whose value is the string "undefined".
1522
+ // Per-leaf on-disk keys predate the grouped param and older rows carry exactly these;
1523
+ // both emulator columns hold the same key. Spread, not `undefined`, so a repository
1524
+ // round-trip never gains "undefined" string values.
2125
1525
  ...covenants && {
2126
1526
  nonInteractiveClaimReceiverPkScript: base.hex.encode(covenants.receiverPkScript),
2127
1527
  nonInteractiveClaimEmulatorPubkey: base.hex.encode(covenants.emulatorPubkey),
2128
1528
  nonInteractiveRefundSenderPkScript: base.hex.encode(covenants.senderPkScript),
2129
1529
  nonInteractiveRefundEmulatorPubkey: base.hex.encode(covenants.emulatorPubkey),
2130
- // The legacy marker is precisely the ABSENCE of this key: a
2131
- // row carrying it re-derives the full suite (nine leaves), a
2132
- // row lacking it the pre-timelocked-refund eight — the same
2133
- // encoding older SDKs wrote for eight-leaf rows, so those rows
2134
- // read back unchanged. Spread rather than a "false"/"undefined"
2135
- // string: a dropped flag re-derives the EIGHT-leaf script, a
2136
- // different pkScript, and registration dies at
2137
- // `upsertContractRow` with an opaque `Script mismatch`.
1530
+ // The legacy (eight-leaf) marker is this key's ABSENCE, as older SDKs wrote it.
2138
1531
  ...covenants.legacy === void 0 && {
2139
1532
  nonInteractiveRefundWithoutReceiver: "1"
2140
1533
  }
2141
1534
  },
2142
- // The asset must round-trip, and its absence here used to be silent
2143
- // in the worst way. `ContractManager` re-derives a contract from
2144
- // these params; dropping the asset derives the SAT-ONLY script, so
2145
- // registration died at `upsertContractRow` with a `Script mismatch`
2146
- // naming two hex strings and no cause. Same silent-drop class
2147
- // `validateOptions` refuses one layer up.
2148
- //
2149
- // Two keys rather than one blob, mirroring the script's own view of
2150
- // an Asset ID as a (txid, groupIndex) pair.
1535
+ // Must round-trip: dropping the asset re-derives the sat-only script and registration
1536
+ // dies at `upsertContractRow` with an opaque `Script mismatch`.
2151
1537
  ...params.asset && {
2152
1538
  assetTxid: base.hex.encode(params.asset.txid),
2153
1539
  assetGroupIndex: params.asset.groupIndex.toString()
@@ -2208,9 +1594,9 @@ var VHTLCV2ContractHandler = {
2208
1594
  preimageHash: base.hex.decode(params.hash),
2209
1595
  refundLocktime: BigInt(params.refundLocktime),
2210
1596
  ...asset && { asset },
2211
- unilateralClaimDelay: chunkJZWLXNHV_cjs.sequenceToTimelock(Number(params.claimDelay)),
2212
- unilateralRefundDelay: chunkJZWLXNHV_cjs.sequenceToTimelock(Number(params.refundDelay)),
2213
- unilateralRefundWithoutReceiverDelay: chunkJZWLXNHV_cjs.sequenceToTimelock(
1597
+ unilateralClaimDelay: chunk5XBH5SAL_cjs.sequenceToTimelock(Number(params.claimDelay)),
1598
+ unilateralRefundDelay: chunk5XBH5SAL_cjs.sequenceToTimelock(Number(params.refundDelay)),
1599
+ unilateralRefundWithoutReceiverDelay: chunk5XBH5SAL_cjs.sequenceToTimelock(
2214
1600
  Number(params.refundNoReceiverDelay)
2215
1601
  ),
2216
1602
  ...claim && refund && {
@@ -2218,8 +1604,6 @@ var VHTLCV2ContractHandler = {
2218
1604
  receiverPkScript: claim.destination,
2219
1605
  senderPkScript: refund.destination,
2220
1606
  emulatorPubkey: claim.emulatorPubkey,
2221
- // Absence of the flag IS the legacy marker — the same
2222
- // encoding older SDKs wrote for eight-leaf rows.
2223
1607
  ...params.nonInteractiveRefundWithoutReceiver !== "1" && {
2224
1608
  legacy: "preTimelockedRefund"
2225
1609
  }
@@ -2228,139 +1612,18 @@ var VHTLCV2ContractHandler = {
2228
1612
  };
2229
1613
  },
2230
1614
  /**
2231
- * Select spending path based on context.
2232
- *
2233
- * Role is determined from `context.role` or by matching
2234
- * `context.walletDescriptor` (preferred) / `context.walletPubKey`
2235
- * against sender/receiver in contract params.
1615
+ * Select spending path based on context. Role comes from `context.role` or by matching
1616
+ * `context.walletDescriptor` against sender/receiver.
2236
1617
  */
2237
1618
  selectPath(script, contract, context) {
2238
- const role = resolveRole(contract, context);
2239
- const preimage = contract.params?.preimage;
2240
- const refundLocktime = BigInt(contract.params.refundLocktime);
2241
- if (!role) {
2242
- return null;
2243
- }
2244
- if (context.collaborative) {
2245
- if (role === "receiver" && preimage) {
2246
- return {
2247
- leaf: script.claim(),
2248
- extraWitness: [base.hex.decode(preimage)]
2249
- };
2250
- }
2251
- if (role === "sender" && isCltvSatisfied(context, refundLocktime)) {
2252
- return {
2253
- leaf: script.refundWithoutReceiver()
2254
- };
2255
- }
2256
- return null;
2257
- }
2258
- if (role === "receiver" && preimage) {
2259
- const sequence = Number(contract.params.claimDelay);
2260
- if (!isCsvSpendable(context, sequence)) return null;
2261
- return {
2262
- leaf: script.unilateralClaim(),
2263
- extraWitness: [base.hex.decode(preimage)],
2264
- sequence
2265
- };
2266
- }
2267
- if (role === "sender") {
2268
- const sequence = Number(contract.params.refundNoReceiverDelay);
2269
- if (!isCsvSpendable(context, sequence)) return null;
2270
- return {
2271
- leaf: script.unilateralRefundWithoutReceiver(),
2272
- sequence
2273
- };
2274
- }
2275
- return null;
1619
+ return selectVhtlcPath(script, contract, context);
2276
1620
  },
2277
- /**
2278
- * Get all possible spending paths (no timelock checks).
2279
- *
2280
- * Role is determined from `context.role` or by matching
2281
- * `context.walletDescriptor` (preferred) / `context.walletPubKey`
2282
- * against sender/receiver in contract params.
2283
- */
1621
+ /** Get all possible spending paths (no timelock checks); role resolved as in `selectPath`. */
2284
1622
  getAllSpendingPaths(script, contract, context) {
2285
- const role = resolveRole(contract, context);
2286
- const paths = [];
2287
- if (!role) {
2288
- return paths;
2289
- }
2290
- const preimage = contract.params?.preimage;
2291
- if (context.collaborative) {
2292
- if (role === "receiver" && preimage) {
2293
- paths.push({
2294
- leaf: script.claim(),
2295
- extraWitness: [base.hex.decode(preimage)]
2296
- });
2297
- }
2298
- if (role === "sender") {
2299
- paths.push({
2300
- leaf: script.refundWithoutReceiver()
2301
- });
2302
- }
2303
- } else {
2304
- if (role === "receiver" && preimage) {
2305
- const sequence = Number(contract.params.claimDelay);
2306
- paths.push({
2307
- leaf: script.unilateralClaim(),
2308
- extraWitness: [base.hex.decode(preimage)],
2309
- sequence
2310
- });
2311
- }
2312
- if (role === "sender") {
2313
- const sequence = Number(contract.params.refundNoReceiverDelay);
2314
- paths.push({
2315
- leaf: script.unilateralRefundWithoutReceiver(),
2316
- sequence
2317
- });
2318
- }
2319
- }
2320
- return paths;
1623
+ return vhtlcAllSpendingPaths(script, contract, context);
2321
1624
  },
2322
1625
  getSpendablePaths(script, contract, context) {
2323
- const role = resolveRole(contract, context);
2324
- const paths = [];
2325
- if (!role) {
2326
- return paths;
2327
- }
2328
- const preimage = contract.params?.preimage;
2329
- const refundLocktime = BigInt(contract.params.refundLocktime);
2330
- if (context.collaborative) {
2331
- if (role === "receiver" && preimage) {
2332
- paths.push({
2333
- leaf: script.claim(),
2334
- extraWitness: [base.hex.decode(preimage)]
2335
- });
2336
- }
2337
- if (role === "sender" && isCltvSatisfied(context, refundLocktime)) {
2338
- paths.push({
2339
- leaf: script.refundWithoutReceiver()
2340
- });
2341
- }
2342
- return paths;
2343
- }
2344
- if (role === "receiver" && preimage) {
2345
- const sequence = Number(contract.params.claimDelay);
2346
- if (isCsvSpendable(context, sequence)) {
2347
- paths.push({
2348
- leaf: script.unilateralClaim(),
2349
- extraWitness: [base.hex.decode(preimage)],
2350
- sequence
2351
- });
2352
- }
2353
- }
2354
- if (role === "sender") {
2355
- const sequence = Number(contract.params.refundNoReceiverDelay);
2356
- if (isCsvSpendable(context, sequence)) {
2357
- paths.push({
2358
- leaf: script.unilateralRefundWithoutReceiver(),
2359
- sequence
2360
- });
2361
- }
2362
- }
2363
- return paths;
1626
+ return vhtlcSpendablePaths(script, contract, context);
2364
1627
  },
2365
1628
  /**
2366
1629
  * Refuse an explicit spend of a lockup whose refund path has not opened.
@@ -2370,62 +1633,28 @@ var VHTLCV2ContractHandler = {
2370
1633
  assertVhtlcSpendableNow(contract, context);
2371
1634
  },
2372
1635
  /**
2373
- * Never. A live VHTLC is escrow: the counterparty's claim leaf is armed,
2374
- * and generic selection — send, settle, RENEWAL, offboard — would move the
2375
- * lockup out from under a swap the counterparty is still entitled to
2376
- * complete, or race a claim already in flight. The `vhtlc` handler now
2377
- * answers the same, for the same reason.
2378
- *
2379
- * The gate covers `available` and renewal. Recovery is generic and names
2380
- * nothing, so it is not covered here: `recoverVtxos` filters on
2381
- * {@link assertSpendableNow} instead, which drops a lockup only while its
2382
- * refund path is shut rather than forever. The explicit routes out —
2383
- * `settle({ inputs })`, or `@arkade-os/swap`'s `pushRefundWithoutReceiver`
2384
- * over `findLockupVtxos`' outpoints — are unaffected either way.
1636
+ * Never. A live VHTLC is escrow with the counterparty's claim leaf armed; generic selection
1637
+ * (send, settle, renewal, offboard) would move it out from under the swap or race a claim.
1638
+ * Recovery isn't covered by this gate: `recoverVtxos` filters on {@link assertSpendableNow},
1639
+ * dropping a lockup only while its refund path is shut. Explicit routes (`settle({ inputs })`,
1640
+ * `pushRefundWithoutReceiver`) are unaffected.
2385
1641
  */
2386
1642
  isGenericallySpendable: () => false,
2387
1643
  /**
2388
1644
  * The annotation leaf stamped onto every VTXO locked to this contract.
2389
1645
  *
2390
- * **Without this the contract is unusable, not merely unoptimized.**
2391
- * `deriveContractTapscripts` falls back to `script.forfeit()` for any
2392
- * handler that does not implement {@link TapscriptDeriving}, and no VHTLC
2393
- * script version has a `forfeit()` — `VtxoScript` does not define one and
2394
- * `VHTLC.BaseScript` does not add one. The fallback therefore throws
2395
- * `legacy.forfeit is not a function`, `annotatableIn` catches it, and
2396
- * `fetchContractVtxosBulk` drops this contract's VTXOs before they are
2397
- * persisted. The row would exist and be watched while its balance stayed
2398
- * permanently invisible, and `getSyncState()` would report `degraded`
2399
- * forever. (The `vhtlc` handler had the same gap and now closes it the same
2400
- * way; nothing registers V1 rows through `ContractManager` in this repo, so
2401
- * it was never hit here.)
2402
- *
2403
- * `refundWithoutReceiver` is the leaf, for both roles the annotation
2404
- * serves, because it is the only collaborative path this wallet can
2405
- * actually satisfy as the sender — the same conclusion `selectPath`
2406
- * reaches, kept in step with it deliberately. The claim leaves belong to
2407
- * the receiver and need a preimage the sender does not have; `refund` and
2408
- * `unilateralRefund` need the counterparty; the covenant leaves are the
2409
- * emulator's.
2410
- *
2411
- * **It carries a CLTV, and callers must respect it.** A settlement built on
2412
- * this leaf is only valid once `refundLocktime` has matured, so a recovery
2413
- * round that sweeps this VTXO early is rejected by the server. Nothing in
2414
- * this handler can enforce it, because the annotation is derived per
2415
- * contract and knows no clock. `recoverVtxos` filters on
2416
- * {@link assertSpendableNow} for it.
1646
+ * Required, not an optimization: without {@link TapscriptDeriving} the fallback calls
1647
+ * `script.forfeit()`, which no VHTLC version has, so the VTXOs are silently dropped before
1648
+ * persisting and `getSyncState()` stays `degraded`.
2417
1649
  *
2418
- * **Role-blind.** A receiver's row gets the same leaf, which names keys that
2419
- * wallet does not hold, so it is satisfiable only by the wallet holding the
2420
- * lockup's `sender` key and fails at intent registration for anyone else.
1650
+ * `refundWithoutReceiver` is used (in step with `selectPath`) as the only collaborative leaf
1651
+ * the sender can satisfy. It carries a CLTV: settling on it before `refundLocktime` matures is
1652
+ * rejected, and this handler has no clock, so `recoverVtxos` filters on
1653
+ * {@link assertSpendableNow}. Role-blind: a receiver's row gets the same leaf and fails at
1654
+ * intent registration.
2421
1655
  */
2422
1656
  deriveTapscripts(script) {
2423
- const leaf = script.refundWithoutReceiver();
2424
- return {
2425
- forfeitTapLeafScript: leaf,
2426
- intentTapLeafScript: leaf,
2427
- tapTree: script.encode()
2428
- };
1657
+ return deriveVhtlcTapscripts(script);
2429
1658
  }
2430
1659
  };
2431
1660
  var BoardingContractHandler = {
@@ -2451,24 +1680,10 @@ var BoardingContractHandler = {
2451
1680
  /** Preserves today's settle/board behaviour. */
2452
1681
  isGenericallySpendable: () => true,
2453
1682
  /**
2454
- * Probe the on-chain UTXO set for a boarding output at this HD index.
2455
- *
2456
- * Boarding's source of truth is the **current** on-chain coin set
2457
- * (`OnchainProvider.getCoins`), not the Ark indexer: a boarded (spent)
2458
- * boarding output becomes an L2 VTXO at the receive index, so the
2459
- * indexer probe already keeps the gap window open for it; only an
2460
- * *unspent* boarding output needs the on-chain probe (see plan §2).
2461
- *
2462
- * No-ops (returns `[]`) when boarding discovery is not plumbed — i.e.
2463
- * `deps.boardingTimelock` or `deps.onchainNetwork` is absent — so the
2464
- * scanner unit harness (which sets neither) is unaffected.
2465
- *
2466
- * Always emits `type: "boarding"`, even in the degenerate equal-delay case
2467
- * where the boarding script is byte-identical to a `default` script at this
2468
- * index (`boardingExitDelay === unilateralExitDelay`). The collision is no
2469
- * longer pre-judged in discovery; it is tolerated FIRST-WINS at the
2470
- * persistence layer ({@link ContractManager.upsertContract}). `deps.csvTimelocks`
2471
- * is intentionally not read here.
1683
+ * Probe the **current** on-chain coin set for a boarding output at this HD index. Only an
1684
+ * unspent boarding output needs this: a boarded one became an L2 VTXO at the receive index,
1685
+ * which the indexer probe already covers. Always emits `type: "boarding"` (see the handler
1686
+ * doc on collisions); `deps.csvTimelocks` is intentionally not read.
2472
1687
  */
2473
1688
  async discoverAt(index, descriptor, deps) {
2474
1689
  if (!deps.boardingTimelock || !deps.onchainNetwork) return [];
@@ -2482,26 +1697,19 @@ var BoardingContractHandler = {
2482
1697
  const coins = await deps.onchainProvider.getCoins(onchainAddress);
2483
1698
  if (coins.length === 0) return [];
2484
1699
  const scriptHex = base.hex.encode(script.pkScript);
2485
- const boardingSeq = chunkJZWLXNHV_cjs.timelockToSequence(deps.boardingTimelock);
2486
1700
  return [
2487
1701
  {
2488
1702
  type: "boarding",
2489
- params: {
2490
- pubKey: base.hex.encode(pubKey),
2491
- serverPubKey: base.hex.encode(deps.serverPubKey),
2492
- csvTimelock: boardingSeq.toString()
2493
- },
1703
+ params: BoardingContractHandler.serializeParams({
1704
+ pubKey,
1705
+ serverPubKey: deps.serverPubKey,
1706
+ csvTimelock: deps.boardingTimelock
1707
+ }),
2494
1708
  script: scriptHex,
2495
- // The persisted row's `address` is the *Ark* address (not the
2496
- // on-chain P2TR), matching the row registered at init so the
2497
- // ContractWatcher keeps monitoring the same L2 script and the
2498
- // VTXO repository bucket lines up (plan §6-I.4). The P2TR is
2499
- // recomputed from params only for the `getCoins` probe.
1709
+ // The Ark address, not the P2TR: must match the row registered at init so the
1710
+ // watcher monitors the same L2 script and the VTXO repository bucket lines up.
2500
1711
  address: script.address(deps.network.hrp, deps.serverPubKey).encode(),
2501
- // Tag rotated rows (index > 0) so boot resolution can find the
2502
- // newest boarding address and descriptor-aware signing can
2503
- // recover the per-index key (plan §6-II/§6-III.3). The index-0
2504
- // baseline stays untagged, matching `default`/`delegate`.
1712
+ // Tag rotated rows (index > 0) for boot resolution and per-index signing.
2505
1713
  ...rotatedReceiveMetadata(index, descriptor)
2506
1714
  }
2507
1715
  ];
@@ -2528,6 +1736,17 @@ function resolveTimelockValue(value, args) {
2528
1736
  `invalid timelock value '${value}' \u2014 expected a bigint or a '$param' reference`
2529
1737
  );
2530
1738
  }
1739
+ function resolveCsvTimelock(csv, args) {
1740
+ const value = resolveTimelockValue(csv.value, args);
1741
+ if (csv.type !== "sequence") return { type: csv.type, value };
1742
+ const timelock = chunk5XBH5SAL_cjs.sequenceToCanonicalTimelock(value);
1743
+ if (!timelock) {
1744
+ throw new Error(
1745
+ `csv '${csv.value}' resolved to ${value}, which is not a canonical BIP68 sequence`
1746
+ );
1747
+ }
1748
+ return timelock;
1749
+ }
2531
1750
  function resolveAsm(asm, bind) {
2532
1751
  const tokens = asm.map((t) => {
2533
1752
  if (typeof t === "string" && t.startsWith("$")) {
@@ -2576,6 +1795,7 @@ function collectParamRefs(program) {
2576
1795
  const collect = (items) => {
2577
1796
  for (const t of items ?? []) {
2578
1797
  if (typeof t === "string" && t.startsWith("$")) refs.add(t.slice(1));
1798
+ else if (isTweakedSigner(t) && t.tweak.startsWith("$")) refs.add(t.tweak.slice(1));
2579
1799
  }
2580
1800
  };
2581
1801
  for (const fn of Object.values(program.functions)) {
@@ -2628,10 +1848,15 @@ function validateProgram(program, args) {
2628
1848
  if (typeof p !== "string") validateParamValue(p, args[p.name]);
2629
1849
  }
2630
1850
  }
1851
+ function isTweakedSigner(ref) {
1852
+ if (typeof ref !== "object" || ref === null || ref instanceof Uint8Array) return false;
1853
+ const { tweak, fn } = ref;
1854
+ return typeof tweak === "string" && typeof fn === "string";
1855
+ }
2631
1856
  function resolveSigner(ref, args) {
2632
1857
  if (ref instanceof Uint8Array) return ref;
2633
- if (!ref.startsWith("$")) {
2634
- throw new Error(`unknown signer reference '${ref}' \u2014 use '$${ref}'`);
1858
+ if (typeof ref !== "string" || !ref.startsWith("$")) {
1859
+ throw new Error(`unknown signer reference '${ref}' \u2014 use a '$param' or key bytes`);
2635
1860
  }
2636
1861
  const v = bindValue(args, ref.slice(1));
2637
1862
  if (!(v instanceof Uint8Array)) {
@@ -2641,29 +1866,29 @@ function resolveSigner(ref, args) {
2641
1866
  }
2642
1867
  function encodeTapscriptSegment(seg, pubkeys, args) {
2643
1868
  if (seg.csv) {
2644
- const timelock = { type: seg.csv.type, value: resolveTimelockValue(seg.csv.value, args) };
1869
+ const timelock = resolveCsvTimelock(seg.csv, args);
2645
1870
  if (seg.asm) {
2646
- return chunkJZWLXNHV_cjs.ConditionCSVMultisigTapscript.encode({
1871
+ return chunk5XBH5SAL_cjs.ConditionCSVMultisigTapscript.encode({
2647
1872
  conditionScript: resolveAsm(seg.asm, args),
2648
1873
  timelock,
2649
1874
  pubkeys
2650
1875
  });
2651
1876
  }
2652
- return chunkJZWLXNHV_cjs.CSVMultisigTapscript.encode({ timelock, pubkeys });
1877
+ return chunk5XBH5SAL_cjs.CSVMultisigTapscript.encode({ timelock, pubkeys });
2653
1878
  }
2654
1879
  if (seg.cltv !== void 0) {
2655
- return chunkJZWLXNHV_cjs.CLTVMultisigTapscript.encode({
1880
+ return chunk5XBH5SAL_cjs.CLTVMultisigTapscript.encode({
2656
1881
  absoluteTimelock: resolveTimelockValue(seg.cltv, args),
2657
1882
  pubkeys
2658
1883
  });
2659
1884
  }
2660
1885
  if (seg.asm) {
2661
- return chunkJZWLXNHV_cjs.ConditionMultisigTapscript.encode({
1886
+ return chunk5XBH5SAL_cjs.ConditionMultisigTapscript.encode({
2662
1887
  conditionScript: resolveAsm(seg.asm, args),
2663
1888
  pubkeys
2664
1889
  });
2665
1890
  }
2666
- return chunkJZWLXNHV_cjs.MultisigTapscript.encode({ pubkeys });
1891
+ return chunk5XBH5SAL_cjs.MultisigTapscript.encode({ pubkeys });
2667
1892
  }
2668
1893
  function compileFunctions(program, args, keys) {
2669
1894
  if (program.version !== SUPPORTED_PROGRAM_VERSION) {
@@ -2686,14 +1911,26 @@ function compileFunctions(program, args, keys) {
2686
1911
  }
2687
1912
  return defs.map((def, i) => {
2688
1913
  validateTapscript(def.tapscript);
2689
- const pubkeys = def.tapscript.signers.map((s) => resolveSigner(s, args));
1914
+ const pubkeys = def.tapscript.signers.map((signer) => {
1915
+ if (!isTweakedSigner(signer)) return resolveSigner(signer, args);
1916
+ const asm = functions[signer.fn]?.arkadeScript?.asm;
1917
+ if (!asm) {
1918
+ throw new Error(
1919
+ `ArkadeContract: function '${names[i]}' tweaks '${signer.fn}', which has no arkade script`
1920
+ );
1921
+ }
1922
+ return computeArkadeScriptPublicKey(
1923
+ resolveSigner(signer.tweak, args),
1924
+ resolveAsm(asm, args)
1925
+ );
1926
+ });
2690
1927
  const arkadeScript = def.arkadeScript ? resolveAsm(def.arkadeScript.asm, args) : void 0;
2691
- const leafPubkeys = arkadeScript ? [...pubkeys, computeArkadeScriptPublicKey(keys.emulatorKey, arkadeScript)] : pubkeys;
1928
+ const leafPubkeys = arkadeScript && def.tapscript.emulator !== null ? [...pubkeys, computeArkadeScriptPublicKey(keys.emulatorKey, arkadeScript)] : pubkeys;
2692
1929
  const leafScript = encodeTapscriptSegment(def.tapscript, leafPubkeys, args).script;
2693
1930
  return { name: names[i], def, leafScript, arkadeScript, signerKeys: pubkeys };
2694
1931
  });
2695
1932
  }
2696
- var ArkadeProgramScript = class extends chunkJZWLXNHV_cjs.VtxoScript {
1933
+ var ArkadeProgramScript = class extends chunk5XBH5SAL_cjs.VtxoScript {
2697
1934
  constructor(program, args, keys) {
2698
1935
  const partial = compileFunctions(program, args, keys);
2699
1936
  super(partial.map((p) => p.leafScript));
@@ -2716,17 +1953,31 @@ var ArkadeProgramScript = class extends chunkJZWLXNHV_cjs.VtxoScript {
2716
1953
  }
2717
1954
  };
2718
1955
  function parseArtifact(artifact) {
1956
+ if (Array.isArray(artifact.functions)) {
1957
+ throw new Error(
1958
+ "parseArtifact: `functions` is an array, which is the arkadec artifact shape, not an SDK program \u2014 read it with programFromArtifact instead"
1959
+ );
1960
+ }
1961
+ if (typeof artifact.functions !== "object" || artifact.functions === null) {
1962
+ throw new Error("parseArtifact: `functions` must be an object keyed by function name");
1963
+ }
2719
1964
  const hexToken = (t) => typeof t === "string" && t.startsWith("0x") ? base.hex.decode(t.slice(2)) : t;
1965
+ const signerRef = (s) => {
1966
+ if (s instanceof Uint8Array || typeof s === "string") return hexToken(s);
1967
+ if (isTweakedSigner(s)) return { tweak: s.tweak, fn: s.fn };
1968
+ throw new Error("parseArtifact: a tweaked signer needs string `tweak` and `fn`");
1969
+ };
2720
1970
  const timelockValue = (v) => typeof v === "string" && v.startsWith("$") ? v : BigInt(v);
2721
1971
  const functions = {};
2722
1972
  for (const [name, fn] of Object.entries(artifact.functions)) {
2723
1973
  const tap = fn.tapscript ?? {};
2724
1974
  const tapscript = {
2725
- signers: (tap.signers ?? []).map(hexToken),
1975
+ signers: (tap.signers ?? []).map(signerRef),
2726
1976
  ...tap.asm ? { asm: tap.asm.map(hexToken) } : {},
2727
1977
  ...tap.witness ? { witness: tap.witness.map(hexToken) } : {},
2728
1978
  ...tap.csv ? { csv: { type: tap.csv.type, value: timelockValue(tap.csv.value) } } : {},
2729
- ...tap.cltv !== void 0 ? { cltv: timelockValue(tap.cltv) } : {}
1979
+ ...tap.cltv !== void 0 ? { cltv: timelockValue(tap.cltv) } : {},
1980
+ ..."emulator" in tap ? { emulator: tap.emulator } : {}
2730
1981
  };
2731
1982
  const arkadeScript = fn.arkadeScript ? {
2732
1983
  asm: fn.arkadeScript.asm.map(hexToken),
@@ -2766,7 +2017,8 @@ function stringifyArtifact(program) {
2766
2017
  ...tap.asm ? { asm: tap.asm.map(token) } : {},
2767
2018
  ...tap.witness ? { witness: tap.witness.map(token) } : {},
2768
2019
  ...tap.csv ? { csv: { type: tap.csv.type, value: tap.csv.value.toString() } } : {},
2769
- ...tap.cltv !== void 0 ? { cltv: tap.cltv.toString() } : {}
2020
+ ...tap.cltv !== void 0 ? { cltv: tap.cltv.toString() } : {},
2021
+ ...tap.emulator !== void 0 ? { emulator: tap.emulator } : {}
2770
2022
  },
2771
2023
  ...fn.arkadeScript ? {
2772
2024
  arkadeScript: {
@@ -2852,22 +2104,12 @@ function deserializeArkadeContractParams(params) {
2852
2104
 
2853
2105
  // src/contracts/handlers/arkade.ts
2854
2106
  function walletKeyFrom(context) {
2855
- const extract = (value) => {
2856
- if (!isDescriptor(value)) return value.toLowerCase();
2857
- try {
2858
- return extractPubKey(value).toLowerCase();
2859
- } catch {
2860
- return void 0;
2861
- }
2862
- };
2863
- if (context.walletDescriptor) {
2864
- const key = extract(context.walletDescriptor);
2865
- if (key) return key;
2866
- }
2867
- if (context.walletPubKey) {
2868
- return extract(context.walletPubKey);
2107
+ if (!context.walletDescriptor) return void 0;
2108
+ try {
2109
+ return extractPubKey(context.walletDescriptor).toLowerCase();
2110
+ } catch {
2111
+ return void 0;
2869
2112
  }
2870
- return void 0;
2871
2113
  }
2872
2114
  function staticWitness(fn, script) {
2873
2115
  const refs = fn.def.tapscript.witness ?? [];
@@ -2892,7 +2134,7 @@ function pathsFor(script, context, opts) {
2892
2134
  continue;
2893
2135
  }
2894
2136
  const csvDef = fn.def.tapscript.csv;
2895
- const csv = csvDef ? { type: csvDef.type, value: resolveTimelockValue(csvDef.value, script.args) } : void 0;
2137
+ const csv = csvDef ? resolveCsvTimelock(csvDef, script.args) : void 0;
2896
2138
  const cltv = fn.def.tapscript.cltv !== void 0 ? resolveTimelockValue(fn.def.tapscript.cltv, script.args) : void 0;
2897
2139
  if (context.collaborative) {
2898
2140
  if (csv) continue;
@@ -2906,7 +2148,7 @@ function pathsFor(script, context, opts) {
2906
2148
  continue;
2907
2149
  }
2908
2150
  if (requiresServer) continue;
2909
- const sequence = csv ? Number(chunkJZWLXNHV_cjs.timelockToSequence(csv)) : void 0;
2151
+ const sequence = csv ? Number(chunk5XBH5SAL_cjs.timelockToSequence(csv)) : void 0;
2910
2152
  if (opts.checkTimelocks && csv && !isCsvSpendable(context, sequence)) continue;
2911
2153
  if (opts.checkTimelocks && cltv !== void 0 && !isCltvSatisfied(context, cltv)) {
2912
2154
  continue;
@@ -3016,6 +2258,7 @@ exports.deriveDescriptorLeafCompressedPubKey = deriveDescriptorLeafCompressedPub
3016
2258
  exports.deriveDescriptorLeafPubKey = deriveDescriptorLeafPubKey;
3017
2259
  exports.descriptorIsOurs = descriptorIsOurs;
3018
2260
  exports.deserializeArkadeContractParams = deserializeArkadeContractParams;
2261
+ exports.extractPubKey = extractPubKey;
3019
2262
  exports.fromASM = fromASM;
3020
2263
  exports.getOpcodeName = getOpcodeName;
3021
2264
  exports.getOpcodeValue = getOpcodeValue;
@@ -3035,5 +2278,5 @@ exports.toASM = toASM;
3035
2278
  exports.toXOnly = toXOnly;
3036
2279
  exports.validateProgram = validateProgram;
3037
2280
  exports.witnessRefToBytes = witnessRefToBytes;
3038
- //# sourceMappingURL=chunk-43FKNLX4.cjs.map
3039
- //# sourceMappingURL=chunk-43FKNLX4.cjs.map
2281
+ //# sourceMappingURL=chunk-GVF4OCTL.cjs.map
2282
+ //# sourceMappingURL=chunk-GVF4OCTL.cjs.map