@arkade-os/sdk 0.5.0-rc.3 → 0.5.0-rc.30

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 +223 -83
  2. package/dist/adapters/expo.cjs +5 -6
  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 -4
  6. package/dist/{asyncStorageTaskQueue-DAs_n1xr.d.ts → asyncStorageTaskQueue-DAVf4Fyy.d.ts} +2 -2
  7. package/dist/{asyncStorageTaskQueue-DqGRG66E.d.cts → asyncStorageTaskQueue-fkkUPrhz.d.cts} +2 -2
  8. package/dist/{chunk-FSF2PGTR.cjs → chunk-3SM7BMIE.cjs} +6736 -5189
  9. package/dist/chunk-3SM7BMIE.cjs.map +1 -0
  10. package/dist/{chunk-UCSTNXB4.cjs → chunk-4MCQZYH6.cjs} +501 -1153
  11. package/dist/chunk-4MCQZYH6.cjs.map +1 -0
  12. package/dist/{chunk-BCT7DT2J.cjs → chunk-6BTZ6KFI.cjs} +12 -10
  13. package/dist/chunk-6BTZ6KFI.cjs.map +1 -0
  14. package/dist/{chunk-L4HZK4KK.cjs → chunk-AICUNREA.cjs} +158 -263
  15. package/dist/chunk-AICUNREA.cjs.map +1 -0
  16. package/dist/{chunk-UJTYUYY4.cjs → chunk-ASKOHVGX.cjs} +596 -467
  17. package/dist/chunk-ASKOHVGX.cjs.map +1 -0
  18. package/dist/{chunk-43XGA362.cjs → chunk-DLHE4RCH.cjs} +40 -43
  19. package/dist/chunk-DLHE4RCH.cjs.map +1 -0
  20. package/dist/{chunk-7W6FHWYN.js → chunk-ESEHYZAY.js} +434 -1109
  21. package/dist/chunk-ESEHYZAY.js.map +1 -0
  22. package/dist/{chunk-HSG2GQTM.js → chunk-G6ZPX2GL.js} +586 -462
  23. package/dist/chunk-G6ZPX2GL.js.map +1 -0
  24. package/dist/{chunk-G4UPMCKW.js → chunk-KK6GXY4L.js} +33 -36
  25. package/dist/chunk-KK6GXY4L.js.map +1 -0
  26. package/dist/{chunk-ERUAQGYF.js → chunk-PY3YQNHP.js} +146 -252
  27. package/dist/chunk-PY3YQNHP.js.map +1 -0
  28. package/dist/{chunk-VQCDDGRW.js → chunk-XW72DWYO.js} +6350 -4816
  29. package/dist/chunk-XW72DWYO.js.map +1 -0
  30. package/dist/{chunk-ROD5H7RX.js → chunk-YML2N4SC.js} +7 -5
  31. package/dist/chunk-YML2N4SC.js.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-CZzIduW4.d.cts → delegate-BYoNu3lf.d.cts} +1 -1
  37. package/dist/{delegate-B9Bmrns7.d.ts → delegate-DsqzUVId.d.ts} +1 -1
  38. package/dist/index-CXNTURO_.d.cts +645 -0
  39. package/dist/{index-DnNIOqHS.d.ts → index-DhP68WBD.d.cts} +1698 -2402
  40. package/dist/{index-DnNIOqHS.d.cts → index-DhP68WBD.d.ts} +1698 -2402
  41. package/dist/index-pQr5y77P.d.ts +645 -0
  42. package/dist/index.cjs +407 -356
  43. package/dist/index.d.cts +1045 -1302
  44. package/dist/index.d.ts +1045 -1302
  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-BDb5Ee2J.d.cts → taskRunner-C8H3bSsk.d.cts} +2 -2
  59. package/dist/{taskRunner-F7wNJcF3.d.ts → taskRunner-DKtBy8Yo.d.ts} +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 +20 -23
  67. package/dist/wallet/expo/index.cjs.map +1 -1
  68. package/dist/wallet/expo/index.d.cts +8 -9
  69. package/dist/wallet/expo/index.d.ts +8 -9
  70. package/dist/wallet/expo/index.js +12 -15
  71. package/dist/wallet/expo/index.js.map +1 -1
  72. package/dist/wallet-BmAHDzK3.d.cts +1874 -0
  73. package/dist/wallet-C0W8EOnA.d.ts +1874 -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-43XGA362.cjs.map +0 -1
  106. package/dist/chunk-5BLDMQED.cjs +0 -18
  107. package/dist/chunk-5BLDMQED.cjs.map +0 -1
  108. package/dist/chunk-7W6FHWYN.js.map +0 -1
  109. package/dist/chunk-BCT7DT2J.cjs.map +0 -1
  110. package/dist/chunk-ERUAQGYF.js.map +0 -1
  111. package/dist/chunk-FSF2PGTR.cjs.map +0 -1
  112. package/dist/chunk-G4UPMCKW.js.map +0 -1
  113. package/dist/chunk-HSG2GQTM.js.map +0 -1
  114. package/dist/chunk-L4HZK4KK.cjs.map +0 -1
  115. package/dist/chunk-NSBPE2FW.js +0 -15
  116. package/dist/chunk-NSBPE2FW.js.map +0 -1
  117. package/dist/chunk-ROD5H7RX.js.map +0 -1
  118. package/dist/chunk-UCSTNXB4.cjs.map +0 -1
  119. package/dist/chunk-UJTYUYY4.cjs.map +0 -1
  120. package/dist/chunk-VQCDDGRW.js.map +0 -1
  121. package/dist/hdWalletCapable-BIl3yLVM.d.cts +0 -2232
  122. package/dist/hdWalletCapable-Cr5nGpK5.d.ts +0 -2232
  123. package/dist/index-C0IanN1m.d.cts +0 -11
  124. package/dist/index-C0IanN1m.d.ts +0 -11
  125. package/dist/index-Ci5MmNnK.d.cts +0 -850
  126. package/dist/index-DQ1Hb2w_.d.ts +0 -850
@@ -1,44 +1,48 @@
1
1
  'use strict';
2
2
 
3
- var chunkUJTYUYY4_cjs = require('./chunk-UJTYUYY4.cjs');
4
- var chunk5BLDMQED_cjs = require('./chunk-5BLDMQED.cjs');
3
+ var chunkASKOHVGX_cjs = require('./chunk-ASKOHVGX.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
+ 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);
10
31
 
11
32
  // src/contracts/handlers/registry.ts
12
33
  var ContractHandlerRegistry = class {
13
34
  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
- */
35
+ /** @throws If a handler for this type is already registered */
20
36
  register(handler) {
21
37
  if (this.handlers.has(handler.type)) {
22
38
  throw new Error(`Contract handler for type '${handler.type}' is already registered`);
23
39
  }
24
40
  this.handlers.set(handler.type, handler);
25
41
  }
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
42
  get(type) {
33
43
  return this.handlers.get(type);
34
44
  }
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
- */
45
+ /** @throws If no handler is registered for this type */
42
46
  getOrThrow(type) {
43
47
  const handler = this.get(type);
44
48
  if (!handler) {
@@ -46,29 +50,17 @@ var ContractHandlerRegistry = class {
46
50
  }
47
51
  return handler;
48
52
  }
49
- /**
50
- * Check if a handler is registered.
51
- *
52
- * @param type - The contract type
53
- */
54
53
  has(type) {
55
54
  return this.handlers.has(type);
56
55
  }
57
- /**
58
- * Get all registered types.
59
- */
60
56
  getRegisteredTypes() {
61
57
  return Array.from(this.handlers.keys());
62
58
  }
63
- /**
64
- * Unregister a handler (mainly for testing).
65
- */
59
+ /** Unregister a handler (mainly for testing). */
66
60
  unregister(type) {
67
61
  return this.handlers.delete(type);
68
62
  }
69
- /**
70
- * Clear all handlers (mainly for testing).
71
- */
63
+ /** Clear all handlers (mainly for testing). */
72
64
  clear() {
73
65
  this.handlers.clear();
74
66
  }
@@ -76,14 +68,14 @@ var ContractHandlerRegistry = class {
76
68
  var contractHandlers = new ContractHandlerRegistry();
77
69
  exports.DefaultVtxo = void 0;
78
70
  ((DefaultVtxo2) => {
79
- class Script3 extends chunkUJTYUYY4_cjs.VtxoScript {
71
+ class Script3 extends chunkASKOHVGX_cjs.VtxoScript {
80
72
  /** Create the default virtual output script with one forfeit path and one exit path. */
81
73
  constructor(options) {
82
74
  const { pubKey, serverPubKey, csvTimelock } = options;
83
- const forfeitScript = chunkUJTYUYY4_cjs.MultisigTapscript.encode({
75
+ const forfeitScript = chunkASKOHVGX_cjs.MultisigTapscript.encode({
84
76
  pubkeys: [pubKey, serverPubKey]
85
77
  }).script;
86
- const exitScript = chunkUJTYUYY4_cjs.CSVMultisigTapscript.encode({
78
+ const exitScript = chunkASKOHVGX_cjs.CSVMultisigTapscript.encode({
87
79
  timelock: csvTimelock,
88
80
  pubkeys: [pubKey]
89
81
  }).script;
@@ -268,27 +260,14 @@ function resolveRole(contract, context) {
268
260
  }
269
261
  return void 0;
270
262
  };
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;
263
+ if (!context.walletDescriptor) return void 0;
264
+ return matchRole(extractRawPubKey(context.walletDescriptor));
286
265
  }
287
266
  function extractPubKeyBytes(value) {
288
267
  return base.hex.decode(extractPubKey(normalizeToDescriptor(value)));
289
268
  }
290
269
  function deserializeCsvTimelock(value) {
291
- return value !== void 0 && value !== "" ? chunkUJTYUYY4_cjs.sequenceToTimelock(Number(value)) : exports.DefaultVtxo.Script.DEFAULT_TIMELOCK;
270
+ return value !== void 0 && value !== "" ? chunkASKOHVGX_cjs.sequenceToTimelock(Number(value)) : exports.DefaultVtxo.Script.DEFAULT_TIMELOCK;
292
271
  }
293
272
  var CLTV_HEIGHT_THRESHOLD = 500000000n;
294
273
  function isCltvSatisfied(context, locktime) {
@@ -327,10 +306,139 @@ function assertVhtlcSpendableNow(contract, context) {
327
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.`
328
307
  );
329
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
+ }
330
438
  function isCsvSpendable(context, sequence) {
331
439
  if (sequence === void 0) return true;
332
440
  if (!context.vtxo) return false;
333
- const timelock = chunkUJTYUYY4_cjs.sequenceToTimelock(sequence);
441
+ const timelock = chunkASKOHVGX_cjs.sequenceToTimelock(sequence);
334
442
  if (timelock.type === "blocks") {
335
443
  if (context.blockHeight === void 0 || context.vtxo.status.block_height === void 0) {
336
444
  return false;
@@ -388,21 +496,21 @@ function forfeitExitSpendablePaths(script, contract, context) {
388
496
  async function detectUsedScripts(indexerProvider, scriptHexes) {
389
497
  const used = /* @__PURE__ */ new Set();
390
498
  const unique = [...new Set(scriptHexes)];
391
- for (let offset = 0; offset < unique.length; offset += chunkUJTYUYY4_cjs.SCRIPT_QUERY_CHUNK_SIZE) {
392
- const scripts = unique.slice(offset, offset + chunkUJTYUYY4_cjs.SCRIPT_QUERY_CHUNK_SIZE);
499
+ for (let offset = 0; offset < unique.length; offset += chunkASKOHVGX_cjs.SCRIPT_QUERY_CHUNK_SIZE) {
500
+ const scripts = unique.slice(offset, offset + chunkASKOHVGX_cjs.SCRIPT_QUERY_CHUNK_SIZE);
393
501
  const remaining = new Set(scripts);
394
502
  let pageIndex = 0;
395
503
  let hasMore = true;
396
504
  while (hasMore && remaining.size > 0) {
397
- const { vtxos, page } = await chunkUJTYUYY4_cjs.getNormalizedVtxos(indexerProvider, {
505
+ const { vtxos, page } = await chunkASKOHVGX_cjs.getNormalizedVtxos(indexerProvider, {
398
506
  scripts,
399
507
  pageIndex,
400
- pageSize: chunkUJTYUYY4_cjs.DEFAULT_PAGE_SIZE
508
+ pageSize: chunkASKOHVGX_cjs.DEFAULT_PAGE_SIZE
401
509
  });
402
510
  for (const vtxo of vtxos) {
403
511
  if (remaining.delete(vtxo.script)) used.add(vtxo.script);
404
512
  }
405
- hasMore = page ? vtxos.length === chunkUJTYUYY4_cjs.DEFAULT_PAGE_SIZE : false;
513
+ hasMore = page ? vtxos.length === chunkASKOHVGX_cjs.DEFAULT_PAGE_SIZE : false;
406
514
  pageIndex++;
407
515
  }
408
516
  }
@@ -463,7 +571,7 @@ var DefaultContractHandler = {
463
571
  return {
464
572
  pubKey: base.hex.encode(params.pubKey),
465
573
  serverPubKey: base.hex.encode(params.serverPubKey),
466
- csvTimelock: chunkUJTYUYY4_cjs.timelockToSequence(params.csvTimelock).toString()
574
+ csvTimelock: chunkASKOHVGX_cjs.timelockToSequence(params.csvTimelock).toString()
467
575
  };
468
576
  },
469
577
  deserializeParams(params) {
@@ -495,11 +603,7 @@ function defaultCandidatesAt(_index, descriptor, deps) {
495
603
  (opts) => new exports.DefaultVtxo.Script(opts)
496
604
  ).map((c) => ({
497
605
  type: "default",
498
- params: {
499
- pubKey: base.hex.encode(c.pubKey),
500
- serverPubKey: base.hex.encode(c.serverPubKey),
501
- csvTimelock: chunkUJTYUYY4_cjs.timelockToSequence(c.csvTimelock).toString()
502
- },
606
+ params: DefaultContractHandler.serializeParams(c),
503
607
  script: c.scriptHex,
504
608
  address: c.script.address(deps.network.hrp, c.serverPubKey).encode()
505
609
  }));
@@ -514,12 +618,12 @@ function discoverDefaultRange(entries, deps) {
514
618
  }
515
619
  exports.DelegateVtxo = void 0;
516
620
  ((DelegateVtxo2) => {
517
- class Script3 extends chunkUJTYUYY4_cjs.VtxoScript {
621
+ class Script3 extends chunkASKOHVGX_cjs.VtxoScript {
518
622
  /** Create a delegated virtual output script with forfeit, exit, and delegate paths. */
519
623
  constructor(options) {
520
624
  const defaultVtxo = new exports.DefaultVtxo.Script(options);
521
625
  const { delegatePubKey, pubKey, serverPubKey } = options;
522
- const delegateScript = chunkUJTYUYY4_cjs.MultisigTapscript.encode({
626
+ const delegateScript = chunkASKOHVGX_cjs.MultisigTapscript.encode({
523
627
  pubkeys: [pubKey, delegatePubKey, serverPubKey]
524
628
  }).script;
525
629
  super([...defaultVtxo.scripts, delegateScript]);
@@ -558,7 +662,7 @@ var DelegateContractHandler = {
558
662
  pubKey: base.hex.encode(params.pubKey),
559
663
  serverPubKey: base.hex.encode(params.serverPubKey),
560
664
  delegatePubKey: base.hex.encode(params.delegatePubKey),
561
- csvTimelock: chunkUJTYUYY4_cjs.timelockToSequence(params.csvTimelock).toString()
665
+ csvTimelock: chunkASKOHVGX_cjs.timelockToSequence(params.csvTimelock).toString()
562
666
  };
563
667
  },
564
668
  deserializeParams(params) {
@@ -598,12 +702,7 @@ function delegateCandidatesAt(_index, descriptor, deps) {
598
702
  (opts) => new exports.DelegateVtxo.Script({ ...opts, delegatePubKey })
599
703
  ).map((c) => ({
600
704
  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: chunkUJTYUYY4_cjs.timelockToSequence(c.csvTimelock).toString()
606
- },
705
+ params: DelegateContractHandler.serializeParams({ ...c, delegatePubKey }),
607
706
  script: c.scriptHex,
608
707
  address: c.script.address(deps.network.hrp, c.serverPubKey).encode()
609
708
  }));
@@ -619,515 +718,10 @@ function discoverDelegateRange(entries, deps) {
619
718
  (c, index, descriptor) => ({ ...c, ...rotatedReceiveMetadata(index, descriptor) })
620
719
  );
621
720
  }
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
721
  var ARKADE_OP = {
1129
722
  // Merkle Branch Verification (0xb3 — repurposed NOP4 slot)
1130
723
  MERKLEBRANCHVERIFY: 179,
724
+ PUT: 187,
1131
725
  // Digest (0xc3)
1132
726
  DIGEST: 195,
1133
727
  // SHA256 Streaming (0xc4-0xc6)
@@ -1159,7 +753,10 @@ var ARKADE_OP = {
1159
753
  BIN2NUM: 216,
1160
754
  REVERSEBYTES: 217,
1161
755
  MODEXP: 218,
1162
- // 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)
1163
760
  // EC Operations (0xe0-0xe2)
1164
761
  ECADD: 224,
1165
762
  ECMUL: 225,
@@ -1188,7 +785,10 @@ var ARKADE_OP = {
1188
785
  INSPECTPACKET: 244,
1189
786
  INSPECTINPUTPACKET: 245,
1190
787
  // Signature Hash (0xf6)
1191
- SIGHASH: 246
788
+ SIGHASH: 246,
789
+ // Continuation & Intent Introspection (0xf7-0xf8)
790
+ TUNNEL: 247,
791
+ INSPECTINTENTMESSAGE: 248
1192
792
  };
1193
793
  var ARKADE_OPCODES = Object.values(ARKADE_OP);
1194
794
  var ARKADE_OPCODE_NAMES = Object.fromEntries(
@@ -1256,7 +856,7 @@ function getOpcodeValue(name) {
1256
856
 
1257
857
  // src/arkade/bignum.ts
1258
858
  var bignum_exports = {};
1259
- chunk5BLDMQED_cjs.__export(bignum_exports, {
859
+ chunkASKOHVGX_cjs.__export(bignum_exports, {
1260
860
  BIGNUM_MAX_BYTES: () => BIGNUM_MAX_BYTES,
1261
861
  decode: () => decode,
1262
862
  encode: () => encode
@@ -1284,7 +884,7 @@ var ArkadeOPNames = {};
1284
884
  for (const [k, v] of Object.entries(ARKADE_OPS)) {
1285
885
  if (typeof v === "number") ArkadeOPNames[v] = k;
1286
886
  }
1287
- var ArkadeScript = wrap({
887
+ var ArkadeScript = P__namespace.wrap({
1288
888
  encodeStream: (w, value) => {
1289
889
  for (let o of value) {
1290
890
  if (typeof o === "string") {
@@ -1310,10 +910,10 @@ var ArkadeScript = wrap({
1310
910
  w.byte(len);
1311
911
  } else if (len <= 65535) {
1312
912
  w.byte(btcSigner.OP.PUSHDATA2);
1313
- w.bytes(U16LE.encode(len));
913
+ w.bytes(P__namespace.U16LE.encode(len));
1314
914
  } else {
1315
915
  w.byte(btcSigner.OP.PUSHDATA4);
1316
- w.bytes(U32LE.encode(len));
916
+ w.bytes(P__namespace.U32LE.encode(len));
1317
917
  }
1318
918
  w.bytes(o);
1319
919
  }
@@ -1325,9 +925,9 @@ var ArkadeScript = wrap({
1325
925
  if (btcSigner.OP.OP_0 < cur && cur <= btcSigner.OP.PUSHDATA4) {
1326
926
  let len;
1327
927
  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);
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);
1331
931
  else throw new Error("Should be not possible");
1332
932
  out.push(r.bytes(len));
1333
933
  } else if (cur === 0) {
@@ -1445,7 +1045,7 @@ function computeArkadeScriptPublicKey(pubKey, script) {
1445
1045
  // src/script/vhtlc.ts
1446
1046
  exports.VHTLC = void 0;
1447
1047
  ((VHTLC2) => {
1448
- class BaseScript extends chunkUJTYUYY4_cjs.VtxoScript {
1048
+ class BaseScript extends chunkASKOHVGX_cjs.VtxoScript {
1449
1049
  options;
1450
1050
  claimScript;
1451
1051
  refundScript;
@@ -1472,27 +1072,27 @@ exports.VHTLC = void 0;
1472
1072
  unilateralRefundWithoutReceiverDelay
1473
1073
  } = options;
1474
1074
  const conditionScript = preimageCondition(preimageHash);
1475
- const claimScript = chunkUJTYUYY4_cjs.ConditionMultisigTapscript.encode({
1075
+ const claimScript = chunkASKOHVGX_cjs.ConditionMultisigTapscript.encode({
1476
1076
  conditionScript,
1477
1077
  pubkeys: [receiver, server]
1478
1078
  }).script;
1479
- const refundScript = chunkUJTYUYY4_cjs.MultisigTapscript.encode({
1079
+ const refundScript = chunkASKOHVGX_cjs.MultisigTapscript.encode({
1480
1080
  pubkeys: [sender, receiver, server]
1481
1081
  }).script;
1482
- const refundWithoutReceiverScript = chunkUJTYUYY4_cjs.CLTVMultisigTapscript.encode({
1082
+ const refundWithoutReceiverScript = chunkASKOHVGX_cjs.CLTVMultisigTapscript.encode({
1483
1083
  absoluteTimelock: refundLocktime,
1484
1084
  pubkeys: [sender, server]
1485
1085
  }).script;
1486
- const unilateralClaimScript = chunkUJTYUYY4_cjs.ConditionCSVMultisigTapscript.encode({
1086
+ const unilateralClaimScript = chunkASKOHVGX_cjs.ConditionCSVMultisigTapscript.encode({
1487
1087
  conditionScript,
1488
1088
  timelock: unilateralClaimDelay,
1489
1089
  pubkeys: [receiver]
1490
1090
  }).script;
1491
- const unilateralRefundScript = chunkUJTYUYY4_cjs.CSVMultisigTapscript.encode({
1091
+ const unilateralRefundScript = chunkASKOHVGX_cjs.CSVMultisigTapscript.encode({
1492
1092
  timelock: unilateralRefundDelay,
1493
1093
  pubkeys: [sender, receiver]
1494
1094
  }).script;
1495
- const unilateralRefundWithoutReceiverScript = chunkUJTYUYY4_cjs.CSVMultisigTapscript.encode({
1095
+ const unilateralRefundWithoutReceiverScript = chunkASKOHVGX_cjs.CSVMultisigTapscript.encode({
1496
1096
  timelock: unilateralRefundWithoutReceiverDelay,
1497
1097
  pubkeys: [sender]
1498
1098
  }).script;
@@ -1512,7 +1112,7 @@ exports.VHTLC = void 0;
1512
1112
  const covenants = options.nonInteractiveParameters;
1513
1113
  if (covenants) {
1514
1114
  arkadeScriptNic = enforcePayToMaybeAsset(covenants.receiverPkScript, options.asset);
1515
- nonInteractiveClaimScript = chunkUJTYUYY4_cjs.ConditionMultisigTapscript.encode({
1115
+ nonInteractiveClaimScript = chunkASKOHVGX_cjs.ConditionMultisigTapscript.encode({
1516
1116
  conditionScript,
1517
1117
  pubkeys: [
1518
1118
  server,
@@ -1525,12 +1125,12 @@ exports.VHTLC = void 0;
1525
1125
  covenants.emulatorPubkey,
1526
1126
  arkadeScriptNir
1527
1127
  );
1528
- nonInteractiveRefundScript = chunkUJTYUYY4_cjs.MultisigTapscript.encode({
1128
+ nonInteractiveRefundScript = chunkASKOHVGX_cjs.MultisigTapscript.encode({
1529
1129
  pubkeys: [server, receiver, nirCosigner]
1530
1130
  }).script;
1531
1131
  scripts.push(nonInteractiveRefundScript);
1532
1132
  if (covenants.legacy !== "preTimelockedRefund") {
1533
- nonInteractiveRefundWithoutReceiverScript = chunkUJTYUYY4_cjs.CLTVMultisigTapscript.encode({
1133
+ nonInteractiveRefundWithoutReceiverScript = chunkASKOHVGX_cjs.CLTVMultisigTapscript.encode({
1534
1134
  absoluteTimelock: refundLocktime,
1535
1135
  pubkeys: [server, nirCosigner]
1536
1136
  }).script;
@@ -1609,54 +1209,19 @@ exports.VHTLC = void 0;
1609
1209
  /**
1610
1210
  * Return the timelocked non-interactive refund tapleaf and its ArkadeScript.
1611
1211
  *
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`.
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.
1634
1220
  *
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.
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.
1660
1225
  */
1661
1226
  nonInteractiveRefundWithoutReceiver() {
1662
1227
  if (!this.nonInteractiveRefundWithoutReceiverScript || !this.nonInteractiveRefundWithoutReceiverArkadeScript) {
@@ -1799,10 +1364,7 @@ function enforcePayToAsset(destinationPkScript, asset) {
1799
1364
  }
1800
1365
  const inspectionTxid = Uint8Array.from(asset.txid).reverse();
1801
1366
  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.
1367
+ // The output at the input's index carries at least the input's amount of the asset.
1806
1368
  "PUSHCURRENTINPUTINDEX",
1807
1369
  inspectionTxid,
1808
1370
  asset.groupIndex,
@@ -1844,9 +1406,9 @@ var VHTLCContractHandler = {
1844
1406
  server: base.hex.encode(params.server),
1845
1407
  hash: base.hex.encode(params.preimageHash),
1846
1408
  refundLocktime: params.refundLocktime.toString(),
1847
- claimDelay: chunkUJTYUYY4_cjs.timelockToSequence(params.unilateralClaimDelay).toString(),
1848
- refundDelay: chunkUJTYUYY4_cjs.timelockToSequence(params.unilateralRefundDelay).toString(),
1849
- refundNoReceiverDelay: chunkUJTYUYY4_cjs.timelockToSequence(
1409
+ claimDelay: chunkASKOHVGX_cjs.timelockToSequence(params.unilateralClaimDelay).toString(),
1410
+ refundDelay: chunkASKOHVGX_cjs.timelockToSequence(params.unilateralRefundDelay).toString(),
1411
+ refundNoReceiverDelay: chunkASKOHVGX_cjs.timelockToSequence(
1850
1412
  params.unilateralRefundWithoutReceiverDelay
1851
1413
  ).toString()
1852
1414
  };
@@ -1858,147 +1420,26 @@ var VHTLCContractHandler = {
1858
1420
  server: base.hex.decode(params.server),
1859
1421
  preimageHash: base.hex.decode(params.hash),
1860
1422
  refundLocktime: BigInt(params.refundLocktime),
1861
- unilateralClaimDelay: chunkUJTYUYY4_cjs.sequenceToTimelock(Number(params.claimDelay)),
1862
- unilateralRefundDelay: chunkUJTYUYY4_cjs.sequenceToTimelock(Number(params.refundDelay)),
1863
- unilateralRefundWithoutReceiverDelay: chunkUJTYUYY4_cjs.sequenceToTimelock(
1423
+ unilateralClaimDelay: chunkASKOHVGX_cjs.sequenceToTimelock(Number(params.claimDelay)),
1424
+ unilateralRefundDelay: chunkASKOHVGX_cjs.sequenceToTimelock(Number(params.refundDelay)),
1425
+ unilateralRefundWithoutReceiverDelay: chunkASKOHVGX_cjs.sequenceToTimelock(
1864
1426
  Number(params.refundNoReceiverDelay)
1865
1427
  )
1866
1428
  };
1867
1429
  },
1868
1430
  /**
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.
1431
+ * Select spending path based on context. Role comes from `context.role` or from matching
1432
+ * `context.walletDescriptor` against sender/receiver.
1874
1433
  */
1875
1434
  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;
1435
+ return selectVhtlcPath(script, contract, context);
1914
1436
  },
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
- */
1437
+ /** All possible spending paths (no timelock checks); role as in {@link selectPath}. */
1922
1438
  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;
1439
+ return vhtlcAllSpendingPaths(script, contract, context);
1959
1440
  },
1960
1441
  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;
1442
+ return vhtlcSpendablePaths(script, contract, context);
2002
1443
  },
2003
1444
  /**
2004
1445
  * Refuse an explicit spend of a lockup whose refund path has not opened.
@@ -2009,70 +1450,38 @@ var VHTLCContractHandler = {
2009
1450
  assertVhtlcSpendableNow(contract, context);
2010
1451
  },
2011
1452
  /**
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.
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.
2016
1455
  *
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`.
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.
2027
1460
  *
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.
2032
- *
2033
- * Recovery is filtered on {@link assertSpendableNow}, not on this: the gate
2034
- * 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.
2035
1464
  */
2036
1465
  isGenericallySpendable: () => false,
2037
1466
  /**
2038
1467
  * The annotation leaf stamped onto every VTXO locked to this contract.
2039
1468
  *
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.
2049
- *
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.
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.
2057
1472
  *
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.
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.
2064
1477
  *
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.
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.
2068
1482
  */
2069
1483
  deriveTapscripts(script) {
2070
- const leaf = script.refundWithoutReceiver();
2071
- return {
2072
- forfeitTapLeafScript: leaf,
2073
- intentTapLeafScript: leaf,
2074
- tapTree: script.encode()
2075
- };
1484
+ return deriveVhtlcTapscripts(script);
2076
1485
  }
2077
1486
  };
2078
1487
  var parseGroupIndex = (raw) => {
@@ -2106,48 +1515,26 @@ var VHTLCV2ContractHandler = {
2106
1515
  server: base.hex.encode(params.server),
2107
1516
  hash: base.hex.encode(params.preimageHash),
2108
1517
  refundLocktime: params.refundLocktime.toString(),
2109
- claimDelay: chunkUJTYUYY4_cjs.timelockToSequence(params.unilateralClaimDelay).toString(),
2110
- refundDelay: chunkUJTYUYY4_cjs.timelockToSequence(params.unilateralRefundDelay).toString(),
2111
- refundNoReceiverDelay: chunkUJTYUYY4_cjs.timelockToSequence(
1518
+ claimDelay: chunkASKOHVGX_cjs.timelockToSequence(params.unilateralClaimDelay).toString(),
1519
+ refundDelay: chunkASKOHVGX_cjs.timelockToSequence(params.unilateralRefundDelay).toString(),
1520
+ refundNoReceiverDelay: chunkASKOHVGX_cjs.timelockToSequence(
2112
1521
  params.unilateralRefundWithoutReceiverDelay
2113
1522
  ).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".
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.
2125
1526
  ...covenants && {
2126
1527
  nonInteractiveClaimReceiverPkScript: base.hex.encode(covenants.receiverPkScript),
2127
1528
  nonInteractiveClaimEmulatorPubkey: base.hex.encode(covenants.emulatorPubkey),
2128
1529
  nonInteractiveRefundSenderPkScript: base.hex.encode(covenants.senderPkScript),
2129
1530
  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`.
1531
+ // The legacy (eight-leaf) marker is this key's ABSENCE, as older SDKs wrote it.
2138
1532
  ...covenants.legacy === void 0 && {
2139
1533
  nonInteractiveRefundWithoutReceiver: "1"
2140
1534
  }
2141
1535
  },
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.
1536
+ // Must round-trip: dropping the asset re-derives the sat-only script and registration
1537
+ // dies at `upsertContractRow` with an opaque `Script mismatch`.
2151
1538
  ...params.asset && {
2152
1539
  assetTxid: base.hex.encode(params.asset.txid),
2153
1540
  assetGroupIndex: params.asset.groupIndex.toString()
@@ -2208,9 +1595,9 @@ var VHTLCV2ContractHandler = {
2208
1595
  preimageHash: base.hex.decode(params.hash),
2209
1596
  refundLocktime: BigInt(params.refundLocktime),
2210
1597
  ...asset && { asset },
2211
- unilateralClaimDelay: chunkUJTYUYY4_cjs.sequenceToTimelock(Number(params.claimDelay)),
2212
- unilateralRefundDelay: chunkUJTYUYY4_cjs.sequenceToTimelock(Number(params.refundDelay)),
2213
- unilateralRefundWithoutReceiverDelay: chunkUJTYUYY4_cjs.sequenceToTimelock(
1598
+ unilateralClaimDelay: chunkASKOHVGX_cjs.sequenceToTimelock(Number(params.claimDelay)),
1599
+ unilateralRefundDelay: chunkASKOHVGX_cjs.sequenceToTimelock(Number(params.refundDelay)),
1600
+ unilateralRefundWithoutReceiverDelay: chunkASKOHVGX_cjs.sequenceToTimelock(
2214
1601
  Number(params.refundNoReceiverDelay)
2215
1602
  ),
2216
1603
  ...claim && refund && {
@@ -2218,8 +1605,6 @@ var VHTLCV2ContractHandler = {
2218
1605
  receiverPkScript: claim.destination,
2219
1606
  senderPkScript: refund.destination,
2220
1607
  emulatorPubkey: claim.emulatorPubkey,
2221
- // Absence of the flag IS the legacy marker — the same
2222
- // encoding older SDKs wrote for eight-leaf rows.
2223
1608
  ...params.nonInteractiveRefundWithoutReceiver !== "1" && {
2224
1609
  legacy: "preTimelockedRefund"
2225
1610
  }
@@ -2228,139 +1613,18 @@ var VHTLCV2ContractHandler = {
2228
1613
  };
2229
1614
  },
2230
1615
  /**
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.
1616
+ * Select spending path based on context. Role comes from `context.role` or by matching
1617
+ * `context.walletDescriptor` against sender/receiver.
2236
1618
  */
2237
1619
  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;
1620
+ return selectVhtlcPath(script, contract, context);
2276
1621
  },
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
- */
1622
+ /** Get all possible spending paths (no timelock checks); role resolved as in `selectPath`. */
2284
1623
  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;
1624
+ return vhtlcAllSpendingPaths(script, contract, context);
2321
1625
  },
2322
1626
  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;
1627
+ return vhtlcSpendablePaths(script, contract, context);
2364
1628
  },
2365
1629
  /**
2366
1630
  * Refuse an explicit spend of a lockup whose refund path has not opened.
@@ -2370,62 +1634,28 @@ var VHTLCV2ContractHandler = {
2370
1634
  assertVhtlcSpendableNow(contract, context);
2371
1635
  },
2372
1636
  /**
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.
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.
2385
1642
  */
2386
1643
  isGenericallySpendable: () => false,
2387
1644
  /**
2388
1645
  * The annotation leaf stamped onto every VTXO locked to this contract.
2389
1646
  *
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.
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`.
2410
1650
  *
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.
2417
- *
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.
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.
2421
1656
  */
2422
1657
  deriveTapscripts(script) {
2423
- const leaf = script.refundWithoutReceiver();
2424
- return {
2425
- forfeitTapLeafScript: leaf,
2426
- intentTapLeafScript: leaf,
2427
- tapTree: script.encode()
2428
- };
1658
+ return deriveVhtlcTapscripts(script);
2429
1659
  }
2430
1660
  };
2431
1661
  var BoardingContractHandler = {
@@ -2451,24 +1681,10 @@ var BoardingContractHandler = {
2451
1681
  /** Preserves today's settle/board behaviour. */
2452
1682
  isGenericallySpendable: () => true,
2453
1683
  /**
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.
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.
2472
1688
  */
2473
1689
  async discoverAt(index, descriptor, deps) {
2474
1690
  if (!deps.boardingTimelock || !deps.onchainNetwork) return [];
@@ -2482,38 +1698,49 @@ var BoardingContractHandler = {
2482
1698
  const coins = await deps.onchainProvider.getCoins(onchainAddress);
2483
1699
  if (coins.length === 0) return [];
2484
1700
  const scriptHex = base.hex.encode(script.pkScript);
2485
- const boardingSeq = chunkUJTYUYY4_cjs.timelockToSequence(deps.boardingTimelock);
2486
1701
  return [
2487
1702
  {
2488
1703
  type: "boarding",
2489
- params: {
2490
- pubKey: base.hex.encode(pubKey),
2491
- serverPubKey: base.hex.encode(deps.serverPubKey),
2492
- csvTimelock: boardingSeq.toString()
2493
- },
1704
+ params: BoardingContractHandler.serializeParams({
1705
+ pubKey,
1706
+ serverPubKey: deps.serverPubKey,
1707
+ csvTimelock: deps.boardingTimelock
1708
+ }),
2494
1709
  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.
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.
2500
1712
  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`.
1713
+ // Tag rotated rows (index > 0) for boot resolution and per-index signing.
2505
1714
  ...rotatedReceiveMetadata(index, descriptor)
2506
1715
  }
2507
1716
  ];
2508
1717
  }
2509
1718
  };
2510
1719
  var MinimalScriptNum = btcSigner.ScriptNum(void 0, true);
2511
- var SUPPORTED_PROGRAM_VERSION = 0;
2512
- function inputName(ref) {
2513
- return typeof ref === "string" ? ref : ref.name;
2514
- }
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
+ };
2515
1742
  function bindValue(bind, name) {
2516
- const v = bind[name];
1743
+ const v = Object.hasOwn(bind, name) ? bind[name] : void 0;
2517
1744
  if (v === void 0) throw new Error(`unbound parameter '${name}'`);
2518
1745
  return v;
2519
1746
  }
@@ -2528,6 +1755,17 @@ function resolveTimelockValue(value, args) {
2528
1755
  `invalid timelock value '${value}' \u2014 expected a bigint or a '$param' reference`
2529
1756
  );
2530
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 = chunkASKOHVGX_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
+ }
2531
1769
  function resolveAsm(asm, bind) {
2532
1770
  const tokens = asm.map((t) => {
2533
1771
  if (typeof t === "string" && t.startsWith("$")) {
@@ -2576,6 +1814,7 @@ function collectParamRefs(program) {
2576
1814
  const collect = (items) => {
2577
1815
  for (const t of items ?? []) {
2578
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));
2579
1818
  }
2580
1819
  };
2581
1820
  for (const fn of Object.values(program.functions)) {
@@ -2590,11 +1829,28 @@ function collectParamRefs(program) {
2590
1829
  }
2591
1830
  return refs;
2592
1831
  }
2593
- 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
+ };
2594
1839
  function validateParamValue(def, value) {
2595
- 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") {
2596
1844
  if (typeof value !== "bigint" && typeof value !== "number") {
2597
- 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`);
2598
1854
  }
2599
1855
  return;
2600
1856
  }
@@ -2611,11 +1867,10 @@ function validateParamValue(def, value) {
2611
1867
  }
2612
1868
  }
2613
1869
  function validateProgram(program, args) {
2614
- const params = program.params;
2615
- if (!params || !params.some((p) => typeof p !== "string")) return;
2616
- const declared = new Set(params.map(inputName));
1870
+ const params = program.params ?? [];
1871
+ const declared = new Set(params.map((p) => p.name));
2617
1872
  for (const name of declared) {
2618
- if (args[name] === void 0) {
1873
+ if (!Object.hasOwn(args, name) || args[name] === void 0) {
2619
1874
  throw new Error(`program parameter '${name}' is declared but not bound in args`);
2620
1875
  }
2621
1876
  }
@@ -2625,13 +1880,21 @@ function validateProgram(program, args) {
2625
1880
  }
2626
1881
  }
2627
1882
  for (const p of params) {
2628
- 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}'`);
2629
1887
  }
2630
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
+ }
2631
1894
  function resolveSigner(ref, args) {
2632
1895
  if (ref instanceof Uint8Array) return ref;
2633
- if (!ref.startsWith("$")) {
2634
- 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`);
2635
1898
  }
2636
1899
  const v = bindValue(args, ref.slice(1));
2637
1900
  if (!(v instanceof Uint8Array)) {
@@ -2641,35 +1904,33 @@ function resolveSigner(ref, args) {
2641
1904
  }
2642
1905
  function encodeTapscriptSegment(seg, pubkeys, args) {
2643
1906
  if (seg.csv) {
2644
- const timelock = { type: seg.csv.type, value: resolveTimelockValue(seg.csv.value, args) };
1907
+ const timelock = resolveCsvTimelock(seg.csv, args);
2645
1908
  if (seg.asm) {
2646
- return chunkUJTYUYY4_cjs.ConditionCSVMultisigTapscript.encode({
1909
+ return chunkASKOHVGX_cjs.ConditionCSVMultisigTapscript.encode({
2647
1910
  conditionScript: resolveAsm(seg.asm, args),
2648
1911
  timelock,
2649
1912
  pubkeys
2650
1913
  });
2651
1914
  }
2652
- return chunkUJTYUYY4_cjs.CSVMultisigTapscript.encode({ timelock, pubkeys });
1915
+ return chunkASKOHVGX_cjs.CSVMultisigTapscript.encode({ timelock, pubkeys });
2653
1916
  }
2654
1917
  if (seg.cltv !== void 0) {
2655
- return chunkUJTYUYY4_cjs.CLTVMultisigTapscript.encode({
1918
+ return chunkASKOHVGX_cjs.CLTVMultisigTapscript.encode({
2656
1919
  absoluteTimelock: resolveTimelockValue(seg.cltv, args),
2657
1920
  pubkeys
2658
1921
  });
2659
1922
  }
2660
1923
  if (seg.asm) {
2661
- return chunkUJTYUYY4_cjs.ConditionMultisigTapscript.encode({
1924
+ return chunkASKOHVGX_cjs.ConditionMultisigTapscript.encode({
2662
1925
  conditionScript: resolveAsm(seg.asm, args),
2663
1926
  pubkeys
2664
1927
  });
2665
1928
  }
2666
- return chunkUJTYUYY4_cjs.MultisigTapscript.encode({ pubkeys });
1929
+ return chunkASKOHVGX_cjs.MultisigTapscript.encode({ pubkeys });
2667
1930
  }
2668
1931
  function compileFunctions(program, args, keys) {
2669
1932
  if (program.version !== SUPPORTED_PROGRAM_VERSION) {
2670
- throw new Error(
2671
- `ArkadeContract: unsupported program version ${program.version} \u2014 this SDK supports version ${SUPPORTED_PROGRAM_VERSION}`
2672
- );
1933
+ throw new UnsupportedProgramVersionError(program.version, "ArkadeContract");
2673
1934
  }
2674
1935
  const functions = program.functions;
2675
1936
  const names = Object.keys(functions);
@@ -2677,23 +1938,74 @@ function compileFunctions(program, args, keys) {
2677
1938
  throw new Error("ArkadeContract: program has no functions");
2678
1939
  }
2679
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
+ }
2680
1946
  const defs = names.map((n) => functions[n]);
2681
- 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
+ );
2682
1962
  if (covenant && !keys.emulatorKey) {
2683
1963
  throw new Error(
2684
1964
  `ArkadeContract: function '${covenant}' has an arkadeScript but no emulator is configured \u2014 pass an \`emulator\` to Arkade.connect`
2685
1965
  );
2686
1966
  }
2687
1967
  return defs.map((def, i) => {
2688
- validateTapscript(def.tapscript);
2689
- const pubkeys = def.tapscript.signers.map((s) => resolveSigner(s, args));
2690
- const arkadeScript = def.arkadeScript ? resolveAsm(def.arkadeScript.asm, args) : void 0;
2691
- 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 });
2692
2004
  const leafScript = encodeTapscriptSegment(def.tapscript, leafPubkeys, args).script;
2693
2005
  return { name: names[i], def, leafScript, arkadeScript, signerKeys: pubkeys };
2694
2006
  });
2695
2007
  }
2696
- var ArkadeProgramScript = class extends chunkUJTYUYY4_cjs.VtxoScript {
2008
+ var ArkadeProgramScript = class extends chunkASKOHVGX_cjs.VtxoScript {
2697
2009
  constructor(program, args, keys) {
2698
2010
  const partial = compileFunctions(program, args, keys);
2699
2011
  super(partial.map((p) => p.leafScript));
@@ -2716,23 +2028,72 @@ var ArkadeProgramScript = class extends chunkUJTYUYY4_cjs.VtxoScript {
2716
2028
  }
2717
2029
  };
2718
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
+ }
2719
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
+ };
2720
2045
  const timelockValue = (v) => typeof v === "string" && v.startsWith("$") ? v : BigInt(v);
2721
- 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);
2722
2079
  for (const [name, fn] of Object.entries(artifact.functions)) {
2723
2080
  const tap = fn.tapscript ?? {};
2724
2081
  const tapscript = {
2725
- signers: (tap.signers ?? []).map(hexToken),
2082
+ signers: (tap.signers ?? []).map(signerRef),
2083
+ ...tap.signatures ? { signatures: tap.signatures } : {},
2726
2084
  ...tap.asm ? { asm: tap.asm.map(hexToken) } : {},
2727
2085
  ...tap.witness ? { witness: tap.witness.map(hexToken) } : {},
2728
2086
  ...tap.csv ? { csv: { type: tap.csv.type, value: timelockValue(tap.csv.value) } } : {},
2729
- ...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 } : {}
2730
2090
  };
2731
2091
  const arkadeScript = fn.arkadeScript ? {
2732
2092
  asm: fn.arkadeScript.asm.map(hexToken),
2733
2093
  ...fn.arkadeScript.witness ? { witness: fn.arkadeScript.witness.map(hexToken) } : {}
2734
2094
  } : void 0;
2735
2095
  functions[name] = {
2096
+ ...fn.group !== void 0 ? { group: fn.group } : {},
2736
2097
  ...fn.inputs ? { inputs: fn.inputs } : {},
2737
2098
  tapscript,
2738
2099
  ...arkadeScript ? { arkadeScript } : {}
@@ -2756,17 +2117,21 @@ function stringifyArtifact(program) {
2756
2117
  }
2757
2118
  return t;
2758
2119
  };
2759
- const functions = {};
2120
+ const functions = /* @__PURE__ */ Object.create(null);
2760
2121
  for (const [name, fn] of Object.entries(program.functions)) {
2761
2122
  const tap = fn.tapscript;
2762
2123
  functions[name] = {
2124
+ ...fn.group !== void 0 ? { group: fn.group } : {},
2763
2125
  ...fn.inputs ? { inputs: fn.inputs } : {},
2764
2126
  tapscript: {
2765
2127
  signers: tap.signers.map(token),
2128
+ ...tap.signatures ? { signatures: tap.signatures } : {},
2766
2129
  ...tap.asm ? { asm: tap.asm.map(token) } : {},
2767
2130
  ...tap.witness ? { witness: tap.witness.map(token) } : {},
2768
2131
  ...tap.csv ? { csv: { type: tap.csv.type, value: tap.csv.value.toString() } } : {},
2769
- ...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 } : {}
2770
2135
  },
2771
2136
  ...fn.arkadeScript ? {
2772
2137
  arkadeScript: {
@@ -2788,20 +2153,12 @@ function serializeArgValue(v) {
2788
2153
  if (typeof v === "bigint") return v.toString();
2789
2154
  return v;
2790
2155
  }
2791
- function parseArgValue(v) {
2792
- if (typeof v === "number") return v;
2793
- if (typeof v === "string") {
2794
- if (v.startsWith("0x")) return base.hex.decode(v.slice(2));
2795
- return BigInt(v);
2796
- }
2797
- throw new Error(`invalid arkade arg value: ${JSON.stringify(v)}`);
2798
- }
2799
2156
  function parseTypedArgValue(name, type, v) {
2800
- if (type === "int") {
2157
+ if (ARKADE_TYPE_ENCODINGS[type] === "scriptnum") {
2801
2158
  if (typeof v === "number") return v;
2802
2159
  if (typeof v === "string") return BigInt(v);
2803
2160
  throw new Error(
2804
- `arkade contract params: '${name}' expects an int, got ${JSON.stringify(v)}`
2161
+ `arkade contract params: '${name}' expects ${type}, got ${JSON.stringify(v)}`
2805
2162
  );
2806
2163
  }
2807
2164
  if (typeof v === "string" && v.startsWith("0x")) return base.hex.decode(v.slice(2));
@@ -2810,7 +2167,7 @@ function parseTypedArgValue(name, type, v) {
2810
2167
  );
2811
2168
  }
2812
2169
  function serializeArkadeContractParams(typed) {
2813
- const args = {};
2170
+ const args = /* @__PURE__ */ Object.create(null);
2814
2171
  for (const [k, v] of Object.entries(typed.args)) {
2815
2172
  args[k] = serializeArgValue(v);
2816
2173
  }
@@ -2830,15 +2187,13 @@ function deserializeArkadeContractParams(params) {
2830
2187
  throw new Error("arkade contract params: missing 'serverKey'");
2831
2188
  }
2832
2189
  const program = parseArtifact(JSON.parse(params.program));
2833
- const paramTypes = /* @__PURE__ */ new Map();
2834
- for (const p of program.params ?? []) {
2835
- if (typeof p !== "string") paramTypes.set(p.name, p.type);
2836
- }
2837
- const args = {};
2190
+ const paramTypes = new Map((program.params ?? []).map((p) => [p.name, p.type]));
2191
+ const args = /* @__PURE__ */ Object.create(null);
2838
2192
  if (params.args) {
2839
2193
  for (const [k, v] of Object.entries(JSON.parse(params.args))) {
2840
2194
  const type = paramTypes.get(k);
2841
- 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);
2842
2197
  }
2843
2198
  }
2844
2199
  return {
@@ -2852,22 +2207,12 @@ function deserializeArkadeContractParams(params) {
2852
2207
 
2853
2208
  // src/contracts/handlers/arkade.ts
2854
2209
  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);
2210
+ if (!context.walletDescriptor) return void 0;
2211
+ try {
2212
+ return extractPubKey(context.walletDescriptor).toLowerCase();
2213
+ } catch {
2214
+ return void 0;
2869
2215
  }
2870
- return void 0;
2871
2216
  }
2872
2217
  function staticWitness(fn, script) {
2873
2218
  const refs = fn.def.tapscript.witness ?? [];
@@ -2892,7 +2237,7 @@ function pathsFor(script, context, opts) {
2892
2237
  continue;
2893
2238
  }
2894
2239
  const csvDef = fn.def.tapscript.csv;
2895
- const csv = csvDef ? { type: csvDef.type, value: resolveTimelockValue(csvDef.value, script.args) } : void 0;
2240
+ const csv = csvDef ? resolveCsvTimelock(csvDef, script.args) : void 0;
2896
2241
  const cltv = fn.def.tapscript.cltv !== void 0 ? resolveTimelockValue(fn.def.tapscript.cltv, script.args) : void 0;
2897
2242
  if (context.collaborative) {
2898
2243
  if (csv) continue;
@@ -2906,7 +2251,7 @@ function pathsFor(script, context, opts) {
2906
2251
  continue;
2907
2252
  }
2908
2253
  if (requiresServer) continue;
2909
- const sequence = csv ? Number(chunkUJTYUYY4_cjs.timelockToSequence(csv)) : void 0;
2254
+ const sequence = csv ? Number(chunkASKOHVGX_cjs.timelockToSequence(csv)) : void 0;
2910
2255
  if (opts.checkTimelocks && csv && !isCsvSpendable(context, sequence)) continue;
2911
2256
  if (opts.checkTimelocks && cltv !== void 0 && !isCltvSatisfied(context, cltv)) {
2912
2257
  continue;
@@ -2993,6 +2338,7 @@ exports.ARKADE_OPCODES = ARKADE_OPCODES;
2993
2338
  exports.ARKADE_OPCODE_NAMES = ARKADE_OPCODE_NAMES;
2994
2339
  exports.ARKADE_OPCODE_VALUES = ARKADE_OPCODE_VALUES;
2995
2340
  exports.ARKADE_OPS = ARKADE_OPS;
2341
+ exports.ARKADE_TYPE_ENCODINGS = ARKADE_TYPE_ENCODINGS;
2996
2342
  exports.ArkadeContractHandler = ArkadeContractHandler;
2997
2343
  exports.ArkadeProgramScript = ArkadeProgramScript;
2998
2344
  exports.ArkadeScript = ArkadeScript;
@@ -3002,6 +2348,7 @@ exports.DelegateContractHandler = DelegateContractHandler;
3002
2348
  exports.OPCODE_NAMES = OPCODE_NAMES;
3003
2349
  exports.OPCODE_VALUES = OPCODE_VALUES;
3004
2350
  exports.SUPPORTED_PROGRAM_VERSION = SUPPORTED_PROGRAM_VERSION;
2351
+ exports.UnsupportedProgramVersionError = UnsupportedProgramVersionError;
3005
2352
  exports.VHTLCContractHandler = VHTLCContractHandler;
3006
2353
  exports.VHTLCV2ContractHandler = VHTLCV2ContractHandler;
3007
2354
  exports.WALLET_RECEIVE_SOURCE = WALLET_RECEIVE_SOURCE;
@@ -3016,11 +2363,11 @@ exports.deriveDescriptorLeafCompressedPubKey = deriveDescriptorLeafCompressedPub
3016
2363
  exports.deriveDescriptorLeafPubKey = deriveDescriptorLeafPubKey;
3017
2364
  exports.descriptorIsOurs = descriptorIsOurs;
3018
2365
  exports.deserializeArkadeContractParams = deserializeArkadeContractParams;
2366
+ exports.extractPubKey = extractPubKey;
3019
2367
  exports.fromASM = fromASM;
3020
2368
  exports.getOpcodeName = getOpcodeName;
3021
2369
  exports.getOpcodeValue = getOpcodeValue;
3022
2370
  exports.identityDescriptor = identityDescriptor;
3023
- exports.inputName = inputName;
3024
2371
  exports.isCltvSatisfied = isCltvSatisfied;
3025
2372
  exports.isCsvSpendable = isCsvSpendable;
3026
2373
  exports.isMainnetDescriptor = isMainnetDescriptor;
@@ -3033,7 +2380,8 @@ exports.speculativeReceiveMetadata = speculativeReceiveMetadata;
3033
2380
  exports.stringifyArtifact = stringifyArtifact;
3034
2381
  exports.toASM = toASM;
3035
2382
  exports.toXOnly = toXOnly;
2383
+ exports.validateParamValue = validateParamValue;
3036
2384
  exports.validateProgram = validateProgram;
3037
2385
  exports.witnessRefToBytes = witnessRefToBytes;
3038
- //# sourceMappingURL=chunk-UCSTNXB4.cjs.map
3039
- //# sourceMappingURL=chunk-UCSTNXB4.cjs.map
2386
+ //# sourceMappingURL=chunk-4MCQZYH6.cjs.map
2387
+ //# sourceMappingURL=chunk-4MCQZYH6.cjs.map