@arkade-os/sdk 0.4.66 → 0.4.68

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 (80) hide show
  1. package/README.md +71 -15
  2. package/dist/adapters/expo.cjs +5 -5
  3. package/dist/adapters/expo.d.cts +2 -2
  4. package/dist/adapters/expo.d.ts +2 -2
  5. package/dist/adapters/expo.js +3 -3
  6. package/dist/adapters/indexedDB.cjs +5 -5
  7. package/dist/adapters/indexedDB.js +4 -4
  8. package/dist/{asyncStorageTaskQueue-BZcIN7sA.d.cts → asyncStorageTaskQueue-B2CcXIHU.d.cts} +1 -1
  9. package/dist/{asyncStorageTaskQueue-B6SijMi3.d.ts → asyncStorageTaskQueue-DaZlVTbM.d.ts} +1 -1
  10. package/dist/{chunk-2JZGPXU4.js → chunk-33Q2RFET.js} +3 -3
  11. package/dist/{chunk-2JZGPXU4.js.map → chunk-33Q2RFET.js.map} +1 -1
  12. package/dist/{chunk-CYOI4PEA.js → chunk-45FKMOJH.js} +160 -114
  13. package/dist/chunk-45FKMOJH.js.map +1 -0
  14. package/dist/{chunk-J33ZEM3A.js → chunk-4CMXV5SF.js} +45 -14
  15. package/dist/chunk-4CMXV5SF.js.map +1 -0
  16. package/dist/{chunk-LL47QIHD.cjs → chunk-4KCVS4ZN.cjs} +10 -10
  17. package/dist/{chunk-LL47QIHD.cjs.map → chunk-4KCVS4ZN.cjs.map} +1 -1
  18. package/dist/{chunk-PXPPZF5K.cjs → chunk-6YUACVX4.cjs} +205 -159
  19. package/dist/chunk-6YUACVX4.cjs.map +1 -0
  20. package/dist/{chunk-ZIRFXBKL.cjs → chunk-EJOFL5WH.cjs} +47 -13
  21. package/dist/chunk-EJOFL5WH.cjs.map +1 -0
  22. package/dist/{chunk-R5POS3RS.js → chunk-G4I6PU5H.js} +4 -4
  23. package/dist/{chunk-R5POS3RS.js.map → chunk-G4I6PU5H.js.map} +1 -1
  24. package/dist/{chunk-55ZZ6RBL.js → chunk-GQ4NMQGR.js} +4 -4
  25. package/dist/{chunk-55ZZ6RBL.js.map → chunk-GQ4NMQGR.js.map} +1 -1
  26. package/dist/{chunk-IM6IKNSL.cjs → chunk-JGMSZIE4.cjs} +17 -17
  27. package/dist/{chunk-IM6IKNSL.cjs.map → chunk-JGMSZIE4.cjs.map} +1 -1
  28. package/dist/{chunk-3S3JZUEN.cjs → chunk-PJR63FTK.cjs} +17 -17
  29. package/dist/{chunk-3S3JZUEN.cjs.map → chunk-PJR63FTK.cjs.map} +1 -1
  30. package/dist/{chunk-DSC3G6QZ.js → chunk-VBHXBI7F.js} +1060 -185
  31. package/dist/chunk-VBHXBI7F.js.map +1 -0
  32. package/dist/{chunk-5E6IZNRG.cjs → chunk-WCJVKFAP.cjs} +1467 -581
  33. package/dist/chunk-WCJVKFAP.cjs.map +1 -0
  34. package/dist/contracts/handlers/index.cjs +9 -9
  35. package/dist/contracts/handlers/index.d.cts +3 -3
  36. package/dist/contracts/handlers/index.d.ts +3 -3
  37. package/dist/contracts/handlers/index.js +2 -2
  38. package/dist/{delegate-T-vgxMYZ.d.ts → delegate-AomVWxO_.d.ts} +1 -1
  39. package/dist/{delegate-YXupcWWJ.d.cts → delegate-Bffc5f54.d.cts} +1 -1
  40. package/dist/{wallet-CNibc3yJ.d.ts → hdWalletCapable-B5nRs3RH.d.cts} +318 -127
  41. package/dist/{wallet-DJN1QgFt.d.cts → hdWalletCapable-DZdIVa23.d.ts} +318 -127
  42. package/dist/{index-uUE_uQPn.d.ts → index-C7RZCfoY.d.cts} +222 -19
  43. package/dist/{index-uUE_uQPn.d.cts → index-C7RZCfoY.d.ts} +222 -19
  44. package/dist/{index-e7LYXk1d.d.cts → index-jouvy8FD.d.ts} +172 -99
  45. package/dist/{index-D_FgwLH9.d.ts → index-nfyQM33h.d.cts} +172 -99
  46. package/dist/index.cjs +326 -278
  47. package/dist/index.d.cts +295 -41
  48. package/dist/index.d.ts +295 -41
  49. package/dist/index.js +4 -4
  50. package/dist/repositories/realm/index.cjs +19 -19
  51. package/dist/repositories/realm/index.d.cts +2 -2
  52. package/dist/repositories/realm/index.d.ts +2 -2
  53. package/dist/repositories/realm/index.js +5 -5
  54. package/dist/repositories/sqlite/index.cjs +18 -18
  55. package/dist/repositories/sqlite/index.d.cts +2 -2
  56. package/dist/repositories/sqlite/index.d.ts +2 -2
  57. package/dist/repositories/sqlite/index.js +5 -5
  58. package/dist/{taskRunner-BOVcIH1N.d.cts → taskRunner-D2vnpPBT.d.cts} +1 -1
  59. package/dist/{taskRunner-DNyD1kXG.d.ts → taskRunner-DuwK9t8O.d.ts} +1 -1
  60. package/dist/wallet/expo/background.cjs +14 -14
  61. package/dist/wallet/expo/background.d.cts +3 -3
  62. package/dist/wallet/expo/background.d.ts +3 -3
  63. package/dist/wallet/expo/background.js +6 -6
  64. package/dist/wallet/expo/index.cjs +18 -14
  65. package/dist/wallet/expo/index.cjs.map +1 -1
  66. package/dist/wallet/expo/index.d.cts +7 -5
  67. package/dist/wallet/expo/index.d.ts +7 -5
  68. package/dist/wallet/expo/index.js +10 -6
  69. package/dist/wallet/expo/index.js.map +1 -1
  70. package/dist/worker/expo/index.cjs +9 -9
  71. package/dist/worker/expo/index.d.cts +4 -4
  72. package/dist/worker/expo/index.d.ts +4 -4
  73. package/dist/worker/expo/index.js +5 -5
  74. package/package.json +3 -3
  75. package/dist/chunk-5E6IZNRG.cjs.map +0 -1
  76. package/dist/chunk-CYOI4PEA.js.map +0 -1
  77. package/dist/chunk-DSC3G6QZ.js.map +0 -1
  78. package/dist/chunk-J33ZEM3A.js.map +0 -1
  79. package/dist/chunk-PXPPZF5K.cjs.map +0 -1
  80. package/dist/chunk-ZIRFXBKL.cjs.map +0 -1
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var chunk3S3JZUEN_cjs = require('./chunk-3S3JZUEN.cjs');
4
- var chunkPXPPZF5K_cjs = require('./chunk-PXPPZF5K.cjs');
5
- var chunkZIRFXBKL_cjs = require('./chunk-ZIRFXBKL.cjs');
3
+ var chunkPJR63FTK_cjs = require('./chunk-PJR63FTK.cjs');
4
+ var chunk6YUACVX4_cjs = require('./chunk-6YUACVX4.cjs');
5
+ var chunkEJOFL5WH_cjs = require('./chunk-EJOFL5WH.cjs');
6
6
  var chunk5BLDMQED_cjs = require('./chunk-5BLDMQED.cjs');
7
7
  var utils_js = require('@scure/btc-signer/utils.js');
8
8
  var btcSigner = require('@scure/btc-signer');
@@ -188,7 +188,7 @@ var TreeSignerSession = class _TreeSignerSession {
188
188
  noncesByPubkey.set(base.hex.encode(myPublicKey.subarray(1)), myNonce);
189
189
  const tx = this.graph.find(txid);
190
190
  if (!tx) throw new Error(`missing tx for txid ${txid}`);
191
- const cosigners = chunkZIRFXBKL_cjs.getArkPsbtFields(tx.root, 0, chunkZIRFXBKL_cjs.CosignerPublicKey).map(
191
+ const cosigners = chunkEJOFL5WH_cjs.getArkPsbtFields(tx.root, 0, chunkEJOFL5WH_cjs.CosignerPublicKey).map(
192
192
  (c) => base.hex.encode(c.key.subarray(1))
193
193
  // xonly pubkey
194
194
  );
@@ -240,7 +240,7 @@ var TreeSignerSession = class _TreeSignerSession {
240
240
  if (!aggNonce) throw new Error("missing aggregate nonce");
241
241
  const prevoutAmounts = [];
242
242
  const prevoutScripts = [];
243
- const cosigners = chunkZIRFXBKL_cjs.getArkPsbtFields(g.root, 0, chunkZIRFXBKL_cjs.CosignerPublicKey).map((c) => c.key);
243
+ const cosigners = chunkEJOFL5WH_cjs.getArkPsbtFields(g.root, 0, chunkEJOFL5WH_cjs.CosignerPublicKey).map((c) => c.key);
244
244
  const { finalKey } = aggregateKeys(cosigners, true, {
245
245
  taprootTweak: this.scriptRoot
246
246
  });
@@ -294,7 +294,7 @@ function getPrevOutput(finalKey, graph, sharedOutputAmount, tx) {
294
294
  script: pkScript
295
295
  };
296
296
  }
297
- var ALL_SIGHASH = Object.values(btcSigner.SigHash).filter((x) => typeof x === "number");
297
+ var ALLOWED_SIGHASH = [btcSigner.SigHash.DEFAULT, btcSigner.SigHash.ALL, btcSigner.SigHash.ALL_ANYONECANPAY];
298
298
  var SingleKey = class _SingleKey {
299
299
  key;
300
300
  constructor(key) {
@@ -323,8 +323,9 @@ var SingleKey = class _SingleKey {
323
323
  async sign(tx, inputIndexes) {
324
324
  const txCpy = tx.clone();
325
325
  if (!inputIndexes) {
326
+ chunkEJOFL5WH_cjs.assertAllowedSighashTypes(txCpy, ALLOWED_SIGHASH);
326
327
  try {
327
- if (!txCpy.sign(this.key, ALL_SIGHASH)) {
328
+ if (!txCpy.sign(this.key, ALLOWED_SIGHASH)) {
328
329
  throw new Error("Failed to sign transaction");
329
330
  }
330
331
  } catch (e) {
@@ -335,7 +336,7 @@ var SingleKey = class _SingleKey {
335
336
  return txCpy;
336
337
  }
337
338
  for (const inputIndex of inputIndexes) {
338
- if (!txCpy.signIdx(this.key, inputIndex, ALL_SIGHASH)) {
339
+ if (!txCpy.signIdx(this.key, inputIndex, ALLOWED_SIGHASH)) {
339
340
  throw new Error(`Failed to sign input #${inputIndex}`);
340
341
  }
341
342
  }
@@ -400,7 +401,7 @@ var ReadonlySingleKey = class _ReadonlySingleKey {
400
401
  return Promise.resolve(this.publicKey);
401
402
  }
402
403
  };
403
- var ALL_SIGHASH2 = Object.values(btcSigner.SigHash).filter((x) => typeof x === "number");
404
+ var ALLOWED_SIGHASH2 = [btcSigner.SigHash.DEFAULT, btcSigner.SigHash.ALL, btcSigner.SigHash.ALL_ANYONECANPAY];
404
405
  var seedBytes = /* @__PURE__ */ new WeakMap();
405
406
  var mnemonicMeta = /* @__PURE__ */ new WeakMap();
406
407
  var SeedIdentity = class _SeedIdentity {
@@ -431,7 +432,7 @@ var SeedIdentity = class _SeedIdentity {
431
432
  let network;
432
433
  if ("descriptor" in opts && typeof opts.descriptor === "string") {
433
434
  descriptor = opts.descriptor;
434
- network = chunkPXPPZF5K_cjs.isMainnetDescriptor(descriptor) ? descriptorsScure.networks.bitcoin : descriptorsScure.networks.testnet;
435
+ network = chunk6YUACVX4_cjs.isMainnetDescriptor(descriptor) ? descriptorsScure.networks.bitcoin : descriptorsScure.networks.testnet;
435
436
  } else {
436
437
  network = opts.isMainnet ?? true ? descriptorsScure.networks.bitcoin : descriptorsScure.networks.testnet;
437
438
  descriptor = descriptorsScure.scriptExpressions.trBIP32({
@@ -529,7 +530,7 @@ var SeedIdentity = class _SeedIdentity {
529
530
  * `StaticDescriptorProvider` for legacy single-key wallets.
530
531
  */
531
532
  isOurs(descriptor) {
532
- return chunkPXPPZF5K_cjs.descriptorIsOurs(descriptor, this.descriptor, utils_js.pubSchnorr(this.derivedKey));
533
+ return chunk6YUACVX4_cjs.descriptorIsOurs(descriptor, this.descriptor, utils_js.pubSchnorr(this.derivedKey));
533
534
  }
534
535
  /**
535
536
  * Signs each request with the key derived from its descriptor.
@@ -578,7 +579,7 @@ var SeedIdentity = class _SeedIdentity {
578
579
  }
579
580
  // ── internal helpers ─────────────────────────────────────────────
580
581
  derivePrivateKeyForDescriptor(descriptor) {
581
- const network = chunkPXPPZF5K_cjs.isMainnetDescriptor(descriptor) ? descriptorsScure.networks.bitcoin : descriptorsScure.networks.testnet;
582
+ const network = chunk6YUACVX4_cjs.isMainnetDescriptor(descriptor) ? descriptorsScure.networks.bitcoin : descriptorsScure.networks.testnet;
582
583
  const expansion = descriptorsScure.expand({ descriptor, network });
583
584
  if (expansion.isRanged) {
584
585
  throw new Error(
@@ -603,8 +604,9 @@ var SeedIdentity = class _SeedIdentity {
603
604
  signTxWithKey(tx, key, inputIndexes) {
604
605
  const txCpy = tx.clone();
605
606
  if (!inputIndexes) {
607
+ chunkEJOFL5WH_cjs.assertAllowedSighashTypes(txCpy, ALLOWED_SIGHASH2);
606
608
  try {
607
- if (!txCpy.sign(key, ALL_SIGHASH2)) {
609
+ if (!txCpy.sign(key, ALLOWED_SIGHASH2)) {
608
610
  throw new Error("Failed to sign transaction");
609
611
  }
610
612
  } catch (e) {
@@ -614,7 +616,7 @@ var SeedIdentity = class _SeedIdentity {
614
616
  }
615
617
  } else {
616
618
  for (const idx of inputIndexes) {
617
- if (!txCpy.signIdx(key, idx, ALL_SIGHASH2)) {
619
+ if (!txCpy.signIdx(key, idx, ALLOWED_SIGHASH2)) {
618
620
  throw new Error(`Failed to sign input #${idx}`);
619
621
  }
620
622
  }
@@ -664,7 +666,7 @@ var ReadonlyDescriptorIdentity = class _ReadonlyDescriptorIdentity {
664
666
  */
665
667
  descriptor;
666
668
  constructor(descriptor) {
667
- const network = chunkPXPPZF5K_cjs.isMainnetDescriptor(descriptor) ? descriptorsScure.networks.bitcoin : descriptorsScure.networks.testnet;
669
+ const network = chunk6YUACVX4_cjs.isMainnetDescriptor(descriptor) ? descriptorsScure.networks.bitcoin : descriptorsScure.networks.testnet;
668
670
  let expansion;
669
671
  try {
670
672
  expansion = descriptorsScure.expand({ descriptor, network, index: 0 });
@@ -714,7 +716,7 @@ var ReadonlyDescriptorIdentity = class _ReadonlyDescriptorIdentity {
714
716
  * `StaticDescriptorProvider` for legacy single-key wallets.
715
717
  */
716
718
  isOurs(descriptor) {
717
- return chunkPXPPZF5K_cjs.descriptorIsOurs(descriptor, this.descriptor, this.indexZero.pubkey);
719
+ return chunk6YUACVX4_cjs.descriptorIsOurs(descriptor, this.descriptor, this.indexZero.pubkey);
718
720
  }
719
721
  };
720
722
  function serializeSeedOwnedSigningIdentity(identity) {
@@ -876,10 +878,10 @@ var DescriptorIdentity = class {
876
878
  this.base = base;
877
879
  }
878
880
  async xOnlyPublicKey() {
879
- return chunkPXPPZF5K_cjs.deriveDescriptorLeafPubKey(this.descriptor);
881
+ return chunk6YUACVX4_cjs.deriveDescriptorLeafPubKey(this.descriptor);
880
882
  }
881
883
  async compressedPublicKey() {
882
- return chunkPXPPZF5K_cjs.deriveDescriptorLeafCompressedPubKey(this.descriptor);
884
+ return chunk6YUACVX4_cjs.deriveDescriptorLeafCompressedPubKey(this.descriptor);
883
885
  }
884
886
  async sign(tx, inputIndexes) {
885
887
  const [signed] = await this.signer.signWithDescriptor([
@@ -939,14 +941,20 @@ var ForeignDescriptorError = class extends Error {
939
941
  descriptor;
940
942
  name = "ForeignDescriptorError";
941
943
  };
944
+ var WalletCannotAllocateAddressError = class extends Error {
945
+ name = "WalletCannotAllocateAddressError";
946
+ constructor(reason, options) {
947
+ super(`cannot allocate a fresh address: ${reason}`, options);
948
+ }
949
+ };
942
950
  async function resolveDescriptorSigner(descriptor, identity, provider) {
943
951
  const owner = provider?.isOurs(descriptor) ? provider : isHDCapableIdentity(identity) && identity.isOurs(descriptor) ? identity : void 0;
944
- if (owner && chunkPXPPZF5K_cjs.parseHDDescriptor(descriptor)) {
952
+ if (owner && chunk6YUACVX4_cjs.parseHDDescriptor(descriptor)) {
945
953
  return new DescriptorIdentity({ descriptor, signer: owner, base: identity });
946
954
  }
947
955
  let key;
948
956
  try {
949
- key = chunkPXPPZF5K_cjs.deriveDescriptorLeafPubKey(descriptor);
957
+ key = chunk6YUACVX4_cjs.deriveDescriptorLeafPubKey(descriptor);
950
958
  } catch {
951
959
  throw new ForeignDescriptorError(descriptor);
952
960
  }
@@ -963,6 +971,10 @@ function isHDAllocationCapable(value) {
963
971
  const v = value;
964
972
  return typeof v.getNextSigningDescriptor === "function" && typeof v.advanceSigningDescriptorWatermark === "function";
965
973
  }
974
+ function isAddressAllocationCapable(value) {
975
+ if (typeof value !== "object" || value === null) return false;
976
+ return typeof value.getNewAddresses === "function";
977
+ }
966
978
 
967
979
  // ../../node_modules/@noble/hashes/utils.js
968
980
  function isBytes(a) {
@@ -1317,22 +1329,33 @@ function buildSaltedPreimageMessage(xonly, salt) {
1317
1329
  }
1318
1330
  var PREIMAGE_INDEX = 0;
1319
1331
  function isPerArtifactDescriptor(descriptor) {
1320
- return chunkPXPPZF5K_cjs.parseHDDescriptor(descriptor) !== null;
1332
+ return chunk6YUACVX4_cjs.parseHDDescriptor(descriptor) !== null;
1321
1333
  }
1322
1334
  async function provisionDescriptor(wallet) {
1323
1335
  const allocated = isHDAllocationCapable(wallet) ? await wallet.getNextSigningDescriptor() : void 0;
1324
- return allocated ?? await chunkPXPPZF5K_cjs.identityDescriptor(wallet.identity);
1336
+ return allocated ?? await chunk6YUACVX4_cjs.identityDescriptor(wallet.identity);
1325
1337
  }
1326
1338
  async function provisionRefundKey(wallet) {
1327
- const descriptor = await provisionDescriptor(wallet);
1339
+ const descriptor = await chunk6YUACVX4_cjs.identityDescriptor(wallet.identity);
1328
1340
  const signer = await contractSigner(wallet, descriptor);
1329
- return { descriptor, pubkey: await signer.xOnlyPublicKey() };
1341
+ const pubkey = await signer.xOnlyPublicKey();
1342
+ const identityPubkey = await wallet.identity.xOnlyPublicKey();
1343
+ if (!utils_js.equalBytes(pubkey, identityPubkey)) {
1344
+ throw new Error(
1345
+ "provisionRefundKey: descriptor pubkey does not match wallet identity \u2014 the refund key and the refund address would be on different keys"
1346
+ );
1347
+ }
1348
+ const address = await wallet.getAddress();
1349
+ const { pkScript } = chunkEJOFL5WH_cjs.ArkAddress.decode(address);
1350
+ return { descriptor, pubkey, pkScript, address };
1330
1351
  }
1331
1352
  async function provisionClaimSecret(wallet, opts = {}) {
1332
1353
  if (opts.preimage && opts.preimage.length !== 32) {
1333
1354
  throw new Error(`preimage must be 32 bytes, got ${opts.preimage.length}`);
1334
1355
  }
1335
- const { descriptor, pubkey } = await provisionRefundKey(wallet);
1356
+ const descriptor = await provisionDescriptor(wallet);
1357
+ const signer = await contractSigner(wallet, descriptor);
1358
+ const pubkey = await signer.xOnlyPublicKey();
1336
1359
  const claim = async () => {
1337
1360
  if (opts.preimage) return { preimage: opts.preimage, mustPersistPreimage: true };
1338
1361
  if (isPerArtifactDescriptor(descriptor)) {
@@ -1369,7 +1392,7 @@ async function contractSigner(wallet, descriptor) {
1369
1392
  const signer = isHDWalletCapable(wallet) ? await wallet.signerForDescriptor(descriptor) : wallet.identity;
1370
1393
  let expected;
1371
1394
  try {
1372
- expected = chunkPXPPZF5K_cjs.deriveDescriptorLeafPubKey(descriptor);
1395
+ expected = chunk6YUACVX4_cjs.deriveDescriptorLeafPubKey(descriptor);
1373
1396
  } catch (cause) {
1374
1397
  throw new ForeignDescriptorError(descriptor, { cause });
1375
1398
  }
@@ -1588,14 +1611,14 @@ var RestDelegateProvider = class {
1588
1611
  */
1589
1612
  async delegate(intent, forfeitTxs, options) {
1590
1613
  const url = `${this.url}/v1/delegate`;
1591
- const response = await chunkZIRFXBKL_cjs.baseFetch(url, {
1614
+ const response = await chunkEJOFL5WH_cjs.baseFetch(url, {
1592
1615
  method: "POST",
1593
1616
  headers: {
1594
1617
  "Content-Type": "application/json"
1595
1618
  },
1596
1619
  body: JSON.stringify({
1597
1620
  intent: {
1598
- message: chunkZIRFXBKL_cjs.Intent.encodeMessage(intent.message),
1621
+ message: chunkEJOFL5WH_cjs.Intent.encodeMessage(intent.message),
1599
1622
  proof: intent.proof
1600
1623
  },
1601
1624
  forfeit_txs: forfeitTxs,
@@ -1615,7 +1638,7 @@ var RestDelegateProvider = class {
1615
1638
  */
1616
1639
  async getDelegateInfo() {
1617
1640
  const url = `${this.url}/v1/delegator/info`;
1618
- const response = await chunkZIRFXBKL_cjs.rateGate.runHttp(url, () => chunkZIRFXBKL_cjs.baseFetch(url));
1641
+ const response = await chunkEJOFL5WH_cjs.rateGate.runHttp(url, () => chunkEJOFL5WH_cjs.baseFetch(url));
1619
1642
  if (!response.ok) {
1620
1643
  const errorText2 = await response.text();
1621
1644
  throw new Error(`Failed to get delegate info: ${errorText2}`);
@@ -1632,8 +1655,6 @@ var RestDelegatorProvider = RestDelegateProvider;
1632
1655
  function isDelegateInfo(data) {
1633
1656
  return !!data && typeof data === "object" && "pubkey" in data && "fee" in data && typeof data.pubkey === "string" && typeof data.fee === "string" && data.pubkey !== "" && data.fee !== "" && (typeof data.delegateAddress === "string" && data.delegateAddress !== "" || typeof data.delegatorAddress === "string" && data.delegatorAddress !== "");
1634
1657
  }
1635
-
1636
- // src/providers/onchain.ts
1637
1658
  var ESPLORA_URL = {
1638
1659
  bitcoin: "https://mempool.arkade.sh/api",
1639
1660
  testnet: "https://mempool.space/testnet/api",
@@ -1642,7 +1663,7 @@ var ESPLORA_URL = {
1642
1663
  regtest: "http://localhost:3000/api"
1643
1664
  };
1644
1665
  var EsploraProvider = class {
1645
- constructor(baseUrl = ESPLORA_URL[chunkZIRFXBKL_cjs.DEFAULT_NETWORK_NAME], opts) {
1666
+ constructor(baseUrl = ESPLORA_URL[chunkEJOFL5WH_cjs.DEFAULT_NETWORK_NAME], opts) {
1646
1667
  this.baseUrl = baseUrl;
1647
1668
  this.pollingInterval = opts?.pollingInterval ?? 15e3;
1648
1669
  this.forcePolling = opts?.forcePolling ?? false;
@@ -1651,14 +1672,14 @@ var EsploraProvider = class {
1651
1672
  pollingInterval;
1652
1673
  forcePolling;
1653
1674
  async getCoins(address) {
1654
- const response = await chunkZIRFXBKL_cjs.baseFetch(`${this.baseUrl}/address/${address}/utxo`);
1675
+ const response = await chunkEJOFL5WH_cjs.baseFetch(`${this.baseUrl}/address/${address}/utxo`);
1655
1676
  if (!response.ok) {
1656
1677
  throw new Error(`Failed to fetch UTXOs: ${response.statusText}`);
1657
1678
  }
1658
1679
  return response.json();
1659
1680
  }
1660
1681
  async getFeeRate() {
1661
- const response = await chunkZIRFXBKL_cjs.baseFetch(`${this.baseUrl}/fee-estimates`);
1682
+ const response = await chunkEJOFL5WH_cjs.baseFetch(`${this.baseUrl}/fee-estimates`);
1662
1683
  if (response.status === 404) {
1663
1684
  return void 0;
1664
1685
  }
@@ -1679,7 +1700,7 @@ var EsploraProvider = class {
1679
1700
  }
1680
1701
  }
1681
1702
  async getTxOutspends(txid) {
1682
- const response = await chunkZIRFXBKL_cjs.baseFetch(`${this.baseUrl}/tx/${txid}/outspends`);
1703
+ const response = await chunkEJOFL5WH_cjs.baseFetch(`${this.baseUrl}/tx/${txid}/outspends`);
1683
1704
  if (!response.ok) {
1684
1705
  const error = await response.text();
1685
1706
  throw new Error(`Failed to get transaction outspends: ${error}`);
@@ -1687,15 +1708,23 @@ var EsploraProvider = class {
1687
1708
  return response.json();
1688
1709
  }
1689
1710
  async getTransactions(address) {
1690
- const response = await chunkZIRFXBKL_cjs.baseFetch(`${this.baseUrl}/address/${address}/txs`);
1711
+ const response = await chunkEJOFL5WH_cjs.baseFetch(`${this.baseUrl}/address/${address}/txs`);
1691
1712
  if (!response.ok) {
1692
1713
  const error = await response.text();
1693
1714
  throw new Error(`Failed to get transactions: ${error}`);
1694
1715
  }
1695
1716
  return response.json();
1696
1717
  }
1718
+ async getRawTransaction(txid) {
1719
+ const response = await chunkEJOFL5WH_cjs.baseFetch(`${this.baseUrl}/tx/${txid}/hex`);
1720
+ if (!response.ok) {
1721
+ const error = await response.text();
1722
+ throw new Error(`Failed to get raw transaction ${txid}: ${error}`);
1723
+ }
1724
+ return base.hex.decode((await response.text()).trim());
1725
+ }
1697
1726
  async getTxStatus(txid) {
1698
- const txresponse = await chunkZIRFXBKL_cjs.baseFetch(`${this.baseUrl}/tx/${txid}`);
1727
+ const txresponse = await chunkEJOFL5WH_cjs.baseFetch(`${this.baseUrl}/tx/${txid}`);
1699
1728
  if (!txresponse.ok) {
1700
1729
  throw new Error(txresponse.statusText);
1701
1730
  }
@@ -1703,7 +1732,7 @@ var EsploraProvider = class {
1703
1732
  if (!tx.status.confirmed) {
1704
1733
  return { confirmed: false };
1705
1734
  }
1706
- const response = await chunkZIRFXBKL_cjs.baseFetch(`${this.baseUrl}/tx/${txid}/status`);
1735
+ const response = await chunkEJOFL5WH_cjs.baseFetch(`${this.baseUrl}/tx/${txid}/status`);
1707
1736
  if (!response.ok) {
1708
1737
  throw new Error(`Failed to get transaction status: ${response.statusText}`);
1709
1738
  }
@@ -1787,7 +1816,7 @@ var EsploraProvider = class {
1787
1816
  return stopFunc;
1788
1817
  }
1789
1818
  async getChainTip() {
1790
- const tipBlocks = await chunkZIRFXBKL_cjs.baseFetch(`${this.baseUrl}/blocks`);
1819
+ const tipBlocks = await chunkEJOFL5WH_cjs.baseFetch(`${this.baseUrl}/blocks`);
1791
1820
  if (!tipBlocks.ok) {
1792
1821
  throw new Error(`Failed to get chain tip: ${tipBlocks.statusText}`);
1793
1822
  }
@@ -1806,7 +1835,7 @@ var EsploraProvider = class {
1806
1835
  };
1807
1836
  }
1808
1837
  async broadcastPackage(parent, child) {
1809
- const response = await chunkZIRFXBKL_cjs.baseFetch(`${this.baseUrl}/txs/package`, {
1838
+ const response = await chunkEJOFL5WH_cjs.baseFetch(`${this.baseUrl}/txs/package`, {
1810
1839
  method: "POST",
1811
1840
  headers: {
1812
1841
  "Content-Type": "application/json"
@@ -1817,10 +1846,12 @@ var EsploraProvider = class {
1817
1846
  const error = await response.text();
1818
1847
  throw new Error(`Failed to broadcast package: ${error}`);
1819
1848
  }
1820
- return response.json();
1849
+ const result = await response.json();
1850
+ assertPackageAccepted(result);
1851
+ return result;
1821
1852
  }
1822
1853
  async broadcastTx(tx) {
1823
- const response = await chunkZIRFXBKL_cjs.baseFetch(`${this.baseUrl}/tx`, {
1854
+ const response = await chunkEJOFL5WH_cjs.baseFetch(`${this.baseUrl}/tx`, {
1824
1855
  method: "POST",
1825
1856
  headers: {
1826
1857
  "Content-Type": "text/plain"
@@ -1834,6 +1865,24 @@ var EsploraProvider = class {
1834
1865
  return response.text();
1835
1866
  }
1836
1867
  };
1868
+ function assertPackageAccepted(result) {
1869
+ if (!result || typeof result !== "object") return;
1870
+ const r = result;
1871
+ const msg = typeof r.package_msg === "string" ? r.package_msg : void 0;
1872
+ if (msg === void 0 || msg === "success") return;
1873
+ const reasons = [];
1874
+ const results = r["tx-results"];
1875
+ if (results && typeof results === "object") {
1876
+ for (const entry of Object.values(results)) {
1877
+ if (!entry || typeof entry !== "object" || entry.error === void 0) continue;
1878
+ const txid = typeof entry.txid === "string" ? entry.txid : "unknown tx";
1879
+ reasons.push(`${txid}: ${String(entry.error)}`);
1880
+ }
1881
+ }
1882
+ throw new Error(
1883
+ reasons.length > 0 ? `Package rejected (${msg}) \u2014 ${reasons.join("; ")}` : `Package rejected (${msg})`
1884
+ );
1885
+ }
1837
1886
  function isValidBlocksTip(tip) {
1838
1887
  return Array.isArray(tip) && tip.every((t) => {
1839
1888
  return t && typeof t === "object" && typeof t.id === "string" && t.id.length > 0 && typeof t.height === "number" && t.height >= 0 && typeof t.mediantime === "number" && t.mediantime > 0;
@@ -1982,7 +2031,7 @@ function findP2AOutput(tx) {
1982
2031
  var CHILD_DUST_AMOUNT = 546;
1983
2032
  function buildAnchorChild(params) {
1984
2033
  const { parent, feeRate, fundingCoins, changeAddress, tapInternalKey, network } = params;
1985
- const child = new chunkZIRFXBKL_cjs.Transaction({ version: 3, allowLegacyWitnessUtxo: true });
2034
+ const child = new chunkEJOFL5WH_cjs.Transaction({ version: 3, allowLegacyWitnessUtxo: true });
1986
2035
  child.addInput(findP2AOutput(parent));
1987
2036
  const estimator = TxWeightEstimator.create().addP2AInput();
1988
2037
  for (const _ of fundingCoins) {
@@ -2030,7 +2079,7 @@ function buildForfeitTx(inputs, forfeitPkScript, txLocktime) {
2030
2079
  );
2031
2080
  }
2032
2081
  function buildForfeitTxWithOutput(inputs, output, txLocktime) {
2033
- const tx = new chunkZIRFXBKL_cjs.Transaction({
2082
+ const tx = new chunkEJOFL5WH_cjs.Transaction({
2034
2083
  version: 3,
2035
2084
  lockTime: txLocktime
2036
2085
  });
@@ -2106,7 +2155,7 @@ function validateVtxoTxGraph(graph, roundTransaction, sweepTapTreeRoot) {
2106
2155
  if (previousScriptKey.length !== 32) {
2107
2156
  throw new Error(`parent output ${childIndex} has invalid script`);
2108
2157
  }
2109
- const cosigners = chunkZIRFXBKL_cjs.getArkPsbtFields(child.root, 0, chunkZIRFXBKL_cjs.CosignerPublicKey);
2158
+ const cosigners = chunkEJOFL5WH_cjs.getArkPsbtFields(child.root, 0, chunkEJOFL5WH_cjs.CosignerPublicKey);
2110
2159
  if (cosigners.length === 0) {
2111
2160
  throw ErrMissingCosignersPublicKeys;
2112
2161
  }
@@ -2164,7 +2213,7 @@ var EmulatorPacket = class _EmulatorPacket {
2164
2213
  return new _EmulatorPacket(entries);
2165
2214
  }
2166
2215
  static fromBytes(data) {
2167
- const reader = new chunk3S3JZUEN_cjs.BufferReader(data);
2216
+ const reader = new chunkPJR63FTK_cjs.BufferReader(data);
2168
2217
  const entryCount = reader.readCompactSize();
2169
2218
  const entries = [];
2170
2219
  for (let i = 0; i < entryCount; i++) {
@@ -2182,7 +2231,7 @@ var EmulatorPacket = class _EmulatorPacket {
2182
2231
  return _EmulatorPacket.PACKET_TYPE;
2183
2232
  }
2184
2233
  serialize() {
2185
- const writer = new chunk3S3JZUEN_cjs.BufferWriter();
2234
+ const writer = new chunkPJR63FTK_cjs.BufferWriter();
2186
2235
  writer.writeCompactSize(this.entries.length);
2187
2236
  for (const entry of this.entries) {
2188
2237
  writer.writeUint16LE(entry.vin);
@@ -2269,7 +2318,7 @@ var Extension = class _Extension {
2269
2318
  `expected magic prefix ${base.hex.encode(ARKADE_MAGIC)}, got ${base.hex.encode(payload.slice(0, Math.min(payload.length, ARKADE_MAGIC.length)))}`
2270
2319
  );
2271
2320
  }
2272
- const reader = new chunk3S3JZUEN_cjs.BufferReader(payload.slice(ARKADE_MAGIC.length));
2321
+ const reader = new chunkPJR63FTK_cjs.BufferReader(payload.slice(ARKADE_MAGIC.length));
2273
2322
  const packets = [];
2274
2323
  while (reader.remaining() > 0) {
2275
2324
  const packetType = reader.readByte();
@@ -2343,7 +2392,7 @@ var Extension = class _Extension {
2343
2392
  */
2344
2393
  getAssetPacket() {
2345
2394
  for (const p of this.packets) {
2346
- if (p instanceof chunk3S3JZUEN_cjs.Packet) {
2395
+ if (p instanceof chunkPJR63FTK_cjs.Packet) {
2347
2396
  return p;
2348
2397
  }
2349
2398
  }
@@ -2381,8 +2430,8 @@ var Extension = class _Extension {
2381
2430
  };
2382
2431
  function parsePacket(packetType, data) {
2383
2432
  switch (packetType) {
2384
- case chunk3S3JZUEN_cjs.Packet.PACKET_TYPE:
2385
- return chunk3S3JZUEN_cjs.Packet.fromBytes(data);
2433
+ case chunkPJR63FTK_cjs.Packet.PACKET_TYPE:
2434
+ return chunkPJR63FTK_cjs.Packet.fromBytes(data);
2386
2435
  case EmulatorPacket.PACKET_TYPE:
2387
2436
  return EmulatorPacket.fromBytes(data);
2388
2437
  default:
@@ -2429,16 +2478,16 @@ function buildOpReturnScript(data) {
2429
2478
  }
2430
2479
  return script;
2431
2480
  }
2432
- var ErrOffchainOutputNotFound = (address) => new chunkZIRFXBKL_cjs.ServerResponseMismatchError(`offchain send output not found: ${address}`);
2433
- var ErrInvalidAssetOutputAmount = (got, want, assetId) => new chunkZIRFXBKL_cjs.ServerResponseMismatchError(
2481
+ var ErrOffchainOutputNotFound = (address) => new chunkEJOFL5WH_cjs.ServerResponseMismatchError(`offchain send output not found: ${address}`);
2482
+ var ErrInvalidAssetOutputAmount = (got, want, assetId) => new chunkEJOFL5WH_cjs.ServerResponseMismatchError(
2434
2483
  `invalid asset output amount for ${assetId}: got ${got}, want ${want}`
2435
2484
  );
2436
- var ErrAssetGroupNotFound = (assetId) => new chunkZIRFXBKL_cjs.ServerResponseMismatchError(`asset group not found in batch leaf: ${assetId}`);
2437
- var ErrAssetOutputNotFound = (assetId, outputIndex) => new chunkZIRFXBKL_cjs.ServerResponseMismatchError(
2485
+ var ErrAssetGroupNotFound = (assetId) => new chunkEJOFL5WH_cjs.ServerResponseMismatchError(`asset group not found in batch leaf: ${assetId}`);
2486
+ var ErrAssetOutputNotFound = (assetId, outputIndex) => new chunkEJOFL5WH_cjs.ServerResponseMismatchError(
2438
2487
  `asset output not found in asset group ${assetId} at index ${outputIndex}`
2439
2488
  );
2440
- var ErrOnchainOutputNotFound = (address) => new chunkZIRFXBKL_cjs.ServerResponseMismatchError(`onchain output not found: ${address}`);
2441
- var ErrUnvalidatedOffchainOutput = (address) => new chunkZIRFXBKL_cjs.ServerResponseMismatchError(
2489
+ var ErrOnchainOutputNotFound = (address) => new chunkEJOFL5WH_cjs.ServerResponseMismatchError(`onchain output not found: ${address}`);
2490
+ var ErrUnvalidatedOffchainOutput = (address) => new chunkEJOFL5WH_cjs.ServerResponseMismatchError(
2442
2491
  `offchain output ${address} cannot be validated: virtual output tree signing did not run`
2443
2492
  );
2444
2493
  var ErrInvalidOnchainOutputAmount = (address) => new Error(`invalid onchain output amount: ${address}`);
@@ -2447,7 +2496,7 @@ var ErrInvalidOffchainOutputAmount = (address) => new Error(`invalid offchain ou
2447
2496
  function assertFinalCommitmentMatchesValidated(finalCommitmentTx, validatedCommitmentTxid, context) {
2448
2497
  if (!validatedCommitmentTxid) return;
2449
2498
  if (finalCommitmentTx.id === validatedCommitmentTxid) return;
2450
- throw new chunkZIRFXBKL_cjs.ServerResponseMismatchError(
2499
+ throw new chunkEJOFL5WH_cjs.ServerResponseMismatchError(
2451
2500
  `${context}: finalization commitment tx ${finalCommitmentTx.id} differs from the validated commitment tx ${validatedCommitmentTxid}`
2452
2501
  );
2453
2502
  }
@@ -2457,7 +2506,7 @@ function validateBatchRecipients(commitmentTx, vtxoTreeLeaves, recipients, netwo
2457
2506
  for (const recipient of recipients) {
2458
2507
  let arkAddress;
2459
2508
  try {
2460
- arkAddress = chunkZIRFXBKL_cjs.ArkAddress.decode(recipient.address);
2509
+ arkAddress = chunkEJOFL5WH_cjs.ArkAddress.decode(recipient.address);
2461
2510
  } catch {
2462
2511
  validateOnchainRecipient(commitmentTx, recipient, network, usedOnchainOutputs);
2463
2512
  continue;
@@ -2469,7 +2518,7 @@ function validateBatchRecipientsWithoutTree(commitmentTx, recipients, network) {
2469
2518
  const usedOnchainOutputs = /* @__PURE__ */ new Set();
2470
2519
  for (const recipient of recipients) {
2471
2520
  try {
2472
- chunkZIRFXBKL_cjs.ArkAddress.decode(recipient.address);
2521
+ chunkEJOFL5WH_cjs.ArkAddress.decode(recipient.address);
2473
2522
  } catch {
2474
2523
  validateOnchainRecipient(commitmentTx, recipient, network, usedOnchainOutputs);
2475
2524
  continue;
@@ -2702,7 +2751,7 @@ function assetMintResolver() {
2702
2751
  if (!tx.assets?.length || !tx.key.arkTxid) return void 0;
2703
2752
  const minted = tx.assets.filter((a) => {
2704
2753
  try {
2705
- return base.hex.encode(chunk3S3JZUEN_cjs.AssetId.fromString(a.assetId).txid) === tx.key.arkTxid;
2754
+ return base.hex.encode(chunkPJR63FTK_cjs.AssetId.fromString(a.assetId).txid) === tx.key.arkTxid;
2706
2755
  } catch {
2707
2756
  return false;
2708
2757
  }
@@ -2745,7 +2794,7 @@ function createAssetPacket(assetInputs, receivers, changeReceiver) {
2745
2794
  const existing = inputsByAssetId.get(asset.assetId);
2746
2795
  inputsByAssetId.set(asset.assetId, [
2747
2796
  ...existing ?? [],
2748
- chunk3S3JZUEN_cjs.AssetInput.create(inputIndex, asset.amount)
2797
+ chunkPJR63FTK_cjs.AssetInput.create(inputIndex, asset.amount)
2749
2798
  ]);
2750
2799
  }
2751
2800
  }
@@ -2757,7 +2806,7 @@ function createAssetPacket(assetInputs, receivers, changeReceiver) {
2757
2806
  const existing = outputsByAssetId.get(asset.assetId);
2758
2807
  outputsByAssetId.set(asset.assetId, [
2759
2808
  ...existing ?? [],
2760
- chunk3S3JZUEN_cjs.AssetOutput.create(outputIndex, asset.amount)
2809
+ chunkPJR63FTK_cjs.AssetOutput.create(outputIndex, asset.amount)
2761
2810
  ]);
2762
2811
  }
2763
2812
  }
@@ -2768,7 +2817,7 @@ function createAssetPacket(assetInputs, receivers, changeReceiver) {
2768
2817
  const existing = outputsByAssetId.get(asset.assetId);
2769
2818
  outputsByAssetId.set(asset.assetId, [
2770
2819
  ...existing ?? [],
2771
- chunk3S3JZUEN_cjs.AssetOutput.create(outputIndex, asset.amount)
2820
+ chunkPJR63FTK_cjs.AssetOutput.create(outputIndex, asset.amount)
2772
2821
  ]);
2773
2822
  }
2774
2823
  }
@@ -2777,11 +2826,11 @@ function createAssetPacket(assetInputs, receivers, changeReceiver) {
2777
2826
  for (const assetIdStr of allAssetIds) {
2778
2827
  const inputs = inputsByAssetId.get(assetIdStr);
2779
2828
  const outputs = outputsByAssetId.get(assetIdStr);
2780
- const assetId = chunk3S3JZUEN_cjs.AssetId.fromString(assetIdStr);
2781
- const group = chunk3S3JZUEN_cjs.AssetGroup.create(assetId, null, inputs ?? [], outputs ?? [], []);
2829
+ const assetId = chunkPJR63FTK_cjs.AssetId.fromString(assetIdStr);
2830
+ const group = chunkPJR63FTK_cjs.AssetGroup.create(assetId, null, inputs ?? [], outputs ?? [], []);
2782
2831
  groups.push(group);
2783
2832
  }
2784
- return chunk3S3JZUEN_cjs.Packet.create(groups);
2833
+ return chunkPJR63FTK_cjs.Packet.create(groups);
2785
2834
  }
2786
2835
  function selectCoinsWithAsset(coins, assetId, requiredAmount) {
2787
2836
  const coinsWithAsset = coins.filter((coin) => coin.assets?.some((a) => a.assetId === assetId));
@@ -2818,7 +2867,7 @@ function selectedCoinsToAssetInputs(selectedCoins) {
2818
2867
  }
2819
2868
  function toXOnlySignerHex(pubkeyHex) {
2820
2869
  const bytes = base.hex.decode(pubkeyHex);
2821
- if (bytes.length === 32 || bytes.length === 33) return base.hex.encode(chunkPXPPZF5K_cjs.toXOnly(bytes, "signer key"));
2870
+ if (bytes.length === 32 || bytes.length === 33) return base.hex.encode(chunk6YUACVX4_cjs.toXOnly(bytes, "signer key"));
2822
2871
  throw new Error(`invalid signer pubkey length: expected 32 or 33 bytes, got ${bytes.length}`);
2823
2872
  }
2824
2873
  function signerSetFromInfo(info) {
@@ -2865,13 +2914,13 @@ var toTimelock = (value) => ({
2865
2914
  var toSeconds = (t) => t.type === "seconds" ? t.value : t.value * NOMINAL_BLOCK_SECONDS;
2866
2915
  function assertTimelockInPolicy(timelock, policy, label, overrideOption) {
2867
2916
  if (policy.requireSeconds && timelock.type === "blocks") {
2868
- throw new chunkZIRFXBKL_cjs.ServerResponseMismatchError(
2917
+ throw new chunkEJOFL5WH_cjs.ServerResponseMismatchError(
2869
2918
  `${label} rejected: block-typed timelocks are not accepted (got ${timelock.value})`
2870
2919
  );
2871
2920
  }
2872
2921
  const seconds = toSeconds(timelock);
2873
2922
  if (seconds < policy.minSeconds) {
2874
- throw new chunkZIRFXBKL_cjs.ServerResponseMismatchError(
2923
+ throw new chunkEJOFL5WH_cjs.ServerResponseMismatchError(
2875
2924
  `${label} rejected: ${timelock.value} ${timelock.type} is below the ${policy.minSeconds}s floor; pass ${overrideOption}: ${seconds}n to Wallet.create to lower it`
2876
2925
  );
2877
2926
  }
@@ -2892,7 +2941,7 @@ function resolveBatchExpiryPolicy(network, overrides) {
2892
2941
  }
2893
2942
  function assertValidBatchExpiry(batchExpiry, policy) {
2894
2943
  if (policy.advertisedVtxoTreeExpiry !== void 0 && batchExpiry !== policy.advertisedVtxoTreeExpiry) {
2895
- throw new chunkZIRFXBKL_cjs.ServerResponseMismatchError(
2944
+ throw new chunkEJOFL5WH_cjs.ServerResponseMismatchError(
2896
2945
  `batch expiry rejected: ${batchExpiry} does not match the advertised vtxoTreeExpiry ${policy.advertisedVtxoTreeExpiry}`
2897
2946
  );
2898
2947
  }
@@ -2922,21 +2971,21 @@ function resolveCheckpointExitDelayPolicy(network, overrides) {
2922
2971
  function assertValidServerUnrollScript(checkpointTapscript, policy) {
2923
2972
  let script;
2924
2973
  try {
2925
- script = chunkZIRFXBKL_cjs.CSVMultisigTapscript.decode(base.hex.decode(checkpointTapscript));
2974
+ script = chunkEJOFL5WH_cjs.CSVMultisigTapscript.decode(base.hex.decode(checkpointTapscript));
2926
2975
  } catch (e) {
2927
- throw new chunkZIRFXBKL_cjs.ServerResponseMismatchError(
2976
+ throw new chunkEJOFL5WH_cjs.ServerResponseMismatchError(
2928
2977
  `checkpoint exit delay rejected: invalid checkpointTapscript from server (${e instanceof Error ? e.message : String(e)})`
2929
2978
  );
2930
2979
  }
2931
2980
  if (policy.advertisedForfeitPubkey !== void 0) {
2932
2981
  const { pubkeys } = script.params;
2933
2982
  if (pubkeys.length !== 1) {
2934
- throw new chunkZIRFXBKL_cjs.ServerResponseMismatchError(
2983
+ throw new chunkEJOFL5WH_cjs.ServerResponseMismatchError(
2935
2984
  `checkpoint exit delay rejected: checkpointTapscript must commit to exactly one pubkey, got ${pubkeys.length} [${pubkeys.map(base.hex.encode).join(", ")}]`
2936
2985
  );
2937
2986
  }
2938
2987
  if (!utils_js.equalBytes(pubkeys[0], policy.advertisedForfeitPubkey)) {
2939
- throw new chunkZIRFXBKL_cjs.ServerResponseMismatchError(
2988
+ throw new chunkEJOFL5WH_cjs.ServerResponseMismatchError(
2940
2989
  `checkpoint exit delay rejected: checkpointTapscript pubkey ${base.hex.encode(pubkeys[0])} does not match the advertised forfeitPubkey ${base.hex.encode(policy.advertisedForfeitPubkey)}`
2941
2990
  );
2942
2991
  }
@@ -2980,8 +3029,8 @@ function buildOffchainTx(inputs, outputs, serverUnrollScript) {
2980
3029
  function buildVirtualTx(inputs, outputs) {
2981
3030
  let lockTime = 0n;
2982
3031
  for (const input of inputs) {
2983
- const tapscript = chunkZIRFXBKL_cjs.decodeTapscript(chunkZIRFXBKL_cjs.scriptFromTapLeafScript(input.tapLeafScript));
2984
- if (chunkZIRFXBKL_cjs.CLTVMultisigTapscript.is(tapscript)) {
3032
+ const tapscript = chunkEJOFL5WH_cjs.decodeTapscript(chunkEJOFL5WH_cjs.scriptFromTapLeafScript(input.tapLeafScript));
3033
+ if (chunkEJOFL5WH_cjs.CLTVMultisigTapscript.is(tapscript)) {
2985
3034
  if (lockTime !== 0n) {
2986
3035
  if (isSeconds(lockTime) !== isSeconds(tapscript.params.absoluteTimelock)) {
2987
3036
  throw new Error("cannot mix seconds and blocks locktime");
@@ -2992,7 +3041,7 @@ function buildVirtualTx(inputs, outputs) {
2992
3041
  }
2993
3042
  }
2994
3043
  }
2995
- const tx = new chunkZIRFXBKL_cjs.Transaction({
3044
+ const tx = new chunkEJOFL5WH_cjs.Transaction({
2996
3045
  version: 3,
2997
3046
  lockTime: Number(lockTime)
2998
3047
  });
@@ -3002,12 +3051,12 @@ function buildVirtualTx(inputs, outputs) {
3002
3051
  index: input.vout,
3003
3052
  sequence: lockTime ? btcSigner.DEFAULT_SEQUENCE - 1 : void 0,
3004
3053
  witnessUtxo: {
3005
- script: chunkZIRFXBKL_cjs.VtxoScript.decode(input.tapTree).pkScript,
3054
+ script: chunkEJOFL5WH_cjs.VtxoScript.decode(input.tapTree).pkScript,
3006
3055
  amount: BigInt(input.value)
3007
3056
  },
3008
3057
  tapLeafScript: [input.tapLeafScript]
3009
3058
  });
3010
- chunkZIRFXBKL_cjs.setArkPsbtField(tx, i, chunkZIRFXBKL_cjs.VtxoTaprootTree, input.tapTree);
3059
+ chunkEJOFL5WH_cjs.setArkPsbtField(tx, i, chunkEJOFL5WH_cjs.VtxoTaprootTree, input.tapTree);
3011
3060
  }
3012
3061
  for (const output of outputs) {
3013
3062
  tx.addOutput(output);
@@ -3016,8 +3065,8 @@ function buildVirtualTx(inputs, outputs) {
3016
3065
  return tx;
3017
3066
  }
3018
3067
  function buildCheckpointTx(vtxo, serverUnrollScript) {
3019
- const collaborativeClosure = chunkZIRFXBKL_cjs.decodeTapscript(chunkZIRFXBKL_cjs.scriptFromTapLeafScript(vtxo.tapLeafScript));
3020
- const checkpointVtxoScript = new chunkZIRFXBKL_cjs.VtxoScript([
3068
+ const collaborativeClosure = chunkEJOFL5WH_cjs.decodeTapscript(chunkEJOFL5WH_cjs.scriptFromTapLeafScript(vtxo.tapLeafScript));
3069
+ const checkpointVtxoScript = new chunkEJOFL5WH_cjs.VtxoScript([
3021
3070
  serverUnrollScript.script,
3022
3071
  collaborativeClosure.script
3023
3072
  ]);
@@ -3060,9 +3109,6 @@ function hasBoardingTxExpired(coin, boardingTimelock, chainTipHeight) {
3060
3109
  const blockTime = BigInt(Math.floor(coin.status.block_time));
3061
3110
  return blockTime + boardingTimelock.value <= now;
3062
3111
  }
3063
- function formatSighash(type) {
3064
- return `0x${type.toString(16).padStart(2, "0")}`;
3065
- }
3066
3112
  function verifyTapscriptSignatures(tx, inputIndex, requiredSigners, excludePubkeys = [], allowedSighashTypes = [btcSigner.SigHash.DEFAULT], expectedLeafHash) {
3067
3113
  const input = tx.getInput(inputIndex);
3068
3114
  const prevoutScripts = [];
@@ -3096,7 +3142,7 @@ function verifyTapscriptSignatures(tx, inputIndex, requiredSigners, excludePubke
3096
3142
  const sighashType = signature.length === 65 ? signature[64] : btcSigner.SigHash.DEFAULT;
3097
3143
  const sig = signature.subarray(0, 64);
3098
3144
  if (!allowedSighashTypes.includes(sighashType)) {
3099
- const sighashName = formatSighash(sighashType);
3145
+ const sighashName = chunkEJOFL5WH_cjs.formatSighash(sighashType);
3100
3146
  throw new Error(
3101
3147
  `Unallowed sighash type ${sighashName} for input ${inputIndex}, pubkey ${pubKeyHex}.`
3102
3148
  );
@@ -3170,7 +3216,7 @@ function combineTapscriptSigs(signedTx, originalTx) {
3170
3216
  }
3171
3217
  function isValidArkAddress(address) {
3172
3218
  try {
3173
- chunkZIRFXBKL_cjs.ArkAddress.decode(address);
3219
+ chunkEJOFL5WH_cjs.ArkAddress.decode(address);
3174
3220
  return true;
3175
3221
  } catch (e) {
3176
3222
  return false;
@@ -3178,16 +3224,16 @@ function isValidArkAddress(address) {
3178
3224
  }
3179
3225
  function matchServerCheckpoints(serverCheckpointTxs, expectedCheckpoints, context) {
3180
3226
  if (serverCheckpointTxs.length !== expectedCheckpoints.length) {
3181
- throw new chunkZIRFXBKL_cjs.ServerResponseMismatchError(
3227
+ throw new chunkEJOFL5WH_cjs.ServerResponseMismatchError(
3182
3228
  `${context} returned ${serverCheckpointTxs.length} checkpoints, expected ${expectedCheckpoints.length}`
3183
3229
  );
3184
3230
  }
3185
3231
  const byTxid = new Map(expectedCheckpoints.map((c) => [c.id, c]));
3186
3232
  return serverCheckpointTxs.map((encoded, index) => {
3187
- const server = chunkZIRFXBKL_cjs.Transaction.fromPSBT(base.base64.decode(encoded));
3233
+ const server = chunkEJOFL5WH_cjs.Transaction.fromPSBT(base.base64.decode(encoded));
3188
3234
  const local = byTxid.get(server.id);
3189
3235
  if (!local) {
3190
- throw new chunkZIRFXBKL_cjs.ServerResponseMismatchError(
3236
+ throw new chunkEJOFL5WH_cjs.ServerResponseMismatchError(
3191
3237
  `${context} checkpoint ${index} txid ${server.id} does not match any submitted checkpoint`
3192
3238
  );
3193
3239
  }
@@ -3197,14 +3243,14 @@ function matchServerCheckpoints(serverCheckpointTxs, expectedCheckpoints, contex
3197
3243
  }
3198
3244
  function assertSubmittedArkTxid(response, signedArkTx, context) {
3199
3245
  if (response.arkTxid !== signedArkTx.id) {
3200
- throw new chunkZIRFXBKL_cjs.ServerResponseMismatchError(
3246
+ throw new chunkEJOFL5WH_cjs.ServerResponseMismatchError(
3201
3247
  `${context} returned ark txid ${response.arkTxid}, expected ${signedArkTx.id}`
3202
3248
  );
3203
3249
  }
3204
3250
  if (response.finalArkTx === void 0) return;
3205
- const finalTxid = chunkZIRFXBKL_cjs.Transaction.fromPSBT(base.base64.decode(response.finalArkTx)).id;
3251
+ const finalTxid = chunkEJOFL5WH_cjs.Transaction.fromPSBT(base.base64.decode(response.finalArkTx)).id;
3206
3252
  if (finalTxid !== signedArkTx.id) {
3207
- throw new chunkZIRFXBKL_cjs.ServerResponseMismatchError(
3253
+ throw new chunkEJOFL5WH_cjs.ServerResponseMismatchError(
3208
3254
  `${context} returned final ark tx ${finalTxid}, expected ${signedArkTx.id}`
3209
3255
  );
3210
3256
  }
@@ -3223,10 +3269,10 @@ function assertServerSignedLeaf(serverTx, localTx, inputIndex, serverPubkeyHex,
3223
3269
  [serverPubkeyHex],
3224
3270
  void 0,
3225
3271
  void 0,
3226
- payment_js.tapLeafHash(chunkZIRFXBKL_cjs.scriptFromTapLeafScript(leaf))
3272
+ payment_js.tapLeafHash(chunkEJOFL5WH_cjs.scriptFromTapLeafScript(leaf))
3227
3273
  );
3228
3274
  } catch (error) {
3229
- throw new chunkZIRFXBKL_cjs.ServerResponseMismatchError(
3275
+ throw new chunkEJOFL5WH_cjs.ServerResponseMismatchError(
3230
3276
  `${context}: input ${inputIndex} is not signed by the server on the leaf being spent (${error instanceof Error ? error.message : String(error)})`
3231
3277
  );
3232
3278
  }
@@ -3235,20 +3281,20 @@ function assertCheckpointsMatchInputs(checkpoints, inputs, unrollCandidates, con
3235
3281
  const byOutpoint = new Map(inputs.map((input) => [`${input.txid}:${input.vout}`, input]));
3236
3282
  for (const [index, checkpoint] of checkpoints.entries()) {
3237
3283
  if (checkpoint.inputsLength !== 1) {
3238
- throw new chunkZIRFXBKL_cjs.ServerResponseMismatchError(
3284
+ throw new chunkEJOFL5WH_cjs.ServerResponseMismatchError(
3239
3285
  `${context}: checkpoint ${index} spends ${checkpoint.inputsLength} inputs, expected 1`
3240
3286
  );
3241
3287
  }
3242
3288
  const spent = checkpoint.getInput(0);
3243
3289
  if (!spent.txid || spent.index === void 0) {
3244
- throw new chunkZIRFXBKL_cjs.ServerResponseMismatchError(
3290
+ throw new chunkEJOFL5WH_cjs.ServerResponseMismatchError(
3245
3291
  `${context}: checkpoint ${index} has no input outpoint`
3246
3292
  );
3247
3293
  }
3248
3294
  const outpoint = `${base.hex.encode(spent.txid)}:${spent.index}`;
3249
3295
  const input = byOutpoint.get(outpoint);
3250
3296
  if (!input) {
3251
- throw new chunkZIRFXBKL_cjs.ServerResponseMismatchError(
3297
+ throw new chunkEJOFL5WH_cjs.ServerResponseMismatchError(
3252
3298
  `${context}: checkpoint ${index} spends ${outpoint}, which is not one of the requested virtual outputs`
3253
3299
  );
3254
3300
  }
@@ -3256,7 +3302,7 @@ function assertCheckpointsMatchInputs(checkpoints, inputs, unrollCandidates, con
3256
3302
  (unroll) => buildCheckpointTx(input, unroll).tx.id === checkpoint.id
3257
3303
  );
3258
3304
  if (!rebuilt) {
3259
- throw new chunkZIRFXBKL_cjs.ServerResponseMismatchError(
3305
+ throw new chunkEJOFL5WH_cjs.ServerResponseMismatchError(
3260
3306
  `${context}: checkpoint ${index} txid ${checkpoint.id} differs from the checkpoint built locally for ${outpoint}`
3261
3307
  );
3262
3308
  }
@@ -3280,15 +3326,24 @@ async function submitOffchainTx(provider, offchainTx, signer, hooks, options) {
3280
3326
  assertSubmittedArkTxid(response, signedArkTx, "submitTx");
3281
3327
  const { arkTxid, signedCheckpointTxs } = response;
3282
3328
  const matched = matchServerCheckpoints(signedCheckpointTxs, offchainTx.checkpoints, "submitTx");
3329
+ matched.forEach(({ server }, index) => {
3330
+ try {
3331
+ chunkEJOFL5WH_cjs.assertAllowedSighashTypes(server);
3332
+ } catch (error) {
3333
+ throw new chunkEJOFL5WH_cjs.ServerResponseMismatchError(
3334
+ `submitTx checkpoint ${index}: ${error instanceof Error ? error.message : String(error)}`
3335
+ );
3336
+ }
3337
+ });
3283
3338
  const verify = options?.verifyServerSignatures;
3284
3339
  if (verify) {
3285
3340
  if (response.finalArkTx === void 0) {
3286
- throw new chunkZIRFXBKL_cjs.ServerResponseMismatchError(
3341
+ throw new chunkEJOFL5WH_cjs.ServerResponseMismatchError(
3287
3342
  "submitTx: server returned no final ark tx to verify its signatures against"
3288
3343
  );
3289
3344
  }
3290
- const finalArkTx = chunkZIRFXBKL_cjs.Transaction.fromPSBT(base.base64.decode(response.finalArkTx));
3291
- const serverPubkeyHex = base.hex.encode(chunkPXPPZF5K_cjs.toXOnly(verify.serverPubkey, "server key"));
3345
+ const finalArkTx = chunkEJOFL5WH_cjs.Transaction.fromPSBT(base.base64.decode(response.finalArkTx));
3346
+ const serverPubkeyHex = base.hex.encode(chunk6YUACVX4_cjs.toXOnly(verify.serverPubkey, "server key"));
3292
3347
  for (let i = 0; i < offchainTx.arkTx.inputsLength; i++) {
3293
3348
  assertServerSignedLeaf(
3294
3349
  finalArkTx,
@@ -3344,12 +3399,12 @@ function claimWithPreimageIdentity(identity, preimage) {
3344
3399
  return {
3345
3400
  ...identity,
3346
3401
  sign: async (tx, inputIndexes) => {
3347
- const signed = chunkZIRFXBKL_cjs.Transaction.fromPSBT(
3402
+ const signed = chunkEJOFL5WH_cjs.Transaction.fromPSBT(
3348
3403
  (await identity.sign(tx.clone(), inputIndexes)).toPSBT()
3349
3404
  );
3350
3405
  const indexes = inputIndexes ?? Array.from({ length: signed.inputsLength }, (_, i) => i);
3351
3406
  for (const index of indexes) {
3352
- chunkZIRFXBKL_cjs.setArkPsbtField(signed, index, chunkZIRFXBKL_cjs.ConditionWitness, [preimage]);
3407
+ chunkEJOFL5WH_cjs.setArkPsbtField(signed, index, chunkEJOFL5WH_cjs.ConditionWitness, [preimage]);
3353
3408
  }
3354
3409
  return signed;
3355
3410
  }
@@ -3541,7 +3596,7 @@ function extendCoinWithTapscript(boardingTapscript, utxo) {
3541
3596
  };
3542
3597
  }
3543
3598
  function deriveContractTapscripts(contract) {
3544
- const handler = chunkPXPPZF5K_cjs.contractHandlers.get(contract.type);
3599
+ const handler = chunk6YUACVX4_cjs.contractHandlers.get(contract.type);
3545
3600
  if (!handler) {
3546
3601
  throw new Error(`No handler for contract type '${contract.type}'`);
3547
3602
  }
@@ -3612,7 +3667,7 @@ function getRandomId() {
3612
3667
  }
3613
3668
  function isValidArkAddress2(address) {
3614
3669
  try {
3615
- chunkZIRFXBKL_cjs.ArkAddress.decode(address);
3670
+ chunkEJOFL5WH_cjs.ArkAddress.decode(address);
3616
3671
  return true;
3617
3672
  } catch (e) {
3618
3673
  return false;
@@ -3640,7 +3695,7 @@ function assertRecipientArkAddress(encoded, address, context) {
3640
3695
  function assertTapTreeDerivesAddress(encoded, tapTree, address) {
3641
3696
  let derived;
3642
3697
  try {
3643
- derived = chunkZIRFXBKL_cjs.VtxoScript.decode(tapTree).pkScript;
3698
+ derived = chunkEJOFL5WH_cjs.VtxoScript.decode(tapTree).pkScript;
3644
3699
  } catch (e) {
3645
3700
  throw new Error(
3646
3701
  `Invalid tapTree for ${encoded}: ${e instanceof Error ? e.message : String(e)}`
@@ -3657,7 +3712,7 @@ function validateRecipients(recipients, dustAmount, context) {
3657
3712
  for (const recipient of recipients) {
3658
3713
  let address;
3659
3714
  try {
3660
- address = chunkZIRFXBKL_cjs.ArkAddress.decode(recipient.address);
3715
+ address = chunkEJOFL5WH_cjs.ArkAddress.decode(recipient.address);
3661
3716
  } catch (e) {
3662
3717
  throw new Error(`Invalid Arkade address: ${recipient.address}`);
3663
3718
  }
@@ -3682,7 +3737,7 @@ function validateRecipients(recipients, dustAmount, context) {
3682
3737
 
3683
3738
  // src/contracts/spendability.ts
3684
3739
  function isContractGenericallySpendable(contract) {
3685
- return chunkPXPPZF5K_cjs.contractHandlers.get(contract.type)?.isGenericallySpendable?.(contract) === true;
3740
+ return chunk6YUACVX4_cjs.contractHandlers.get(contract.type)?.isGenericallySpendable?.(contract) === true;
3686
3741
  }
3687
3742
  function gatedContracts(contracts) {
3688
3743
  const gated = /* @__PURE__ */ new Map();
@@ -3695,7 +3750,7 @@ function gateExclusion(gated) {
3695
3750
  return (vtxo) => {
3696
3751
  const type = vtxo.script === void 0 ? void 0 : gated.get(vtxo.script);
3697
3752
  if (type === void 0) return void 0;
3698
- if (!chunkPXPPZF5K_cjs.contractHandlers.has(type)) {
3753
+ if (!chunk6YUACVX4_cjs.contractHandlers.has(type)) {
3699
3754
  return `at ${vtxo.script} (contract type '${type}') has no handler registered in this build`;
3700
3755
  }
3701
3756
  return `at ${vtxo.script} (contract type '${type}') is not generically spendable`;
@@ -3731,7 +3786,9 @@ function selectPendingRecoveryOutpoints(contractsWithVtxos, signerSet, nowSecond
3731
3786
  continue;
3732
3787
  }
3733
3788
  for (const v of vtxos) {
3734
- if (!chunkZIRFXBKL_cjs.hasTerminalSpend(v) && !v.isSwept) out.add(`${v.txid}:${v.vout}`);
3789
+ if (!chunkEJOFL5WH_cjs.hasTerminalSpend(v) && !v.isSwept && !v.isUnrolled) {
3790
+ out.add(`${v.txid}:${v.vout}`);
3791
+ }
3735
3792
  }
3736
3793
  }
3737
3794
  return out;
@@ -3764,10 +3821,10 @@ function byValueDescending(vtxos) {
3764
3821
  return [...vtxos].sort((a, b) => b.value - a.value);
3765
3822
  }
3766
3823
  async function fetchTimeHeight(wallet) {
3767
- return chunkZIRFXBKL_cjs.resolveTimeHeight(wallet.onchainProvider);
3824
+ return chunkEJOFL5WH_cjs.resolveTimeHeight(wallet.onchainProvider);
3768
3825
  }
3769
3826
  function canMigrateBySend(vtxo, now) {
3770
- if (!chunkZIRFXBKL_cjs.canSpendOffchain(vtxo, now)) return false;
3827
+ if (!chunkEJOFL5WH_cjs.canSpendOffchain(vtxo, now)) return false;
3771
3828
  return vtxo.expiresAt !== void 0 || vtxo.expiresAtHeight !== void 0;
3772
3829
  }
3773
3830
  function byExpiryAscending(vtxos, now) {
@@ -3775,7 +3832,7 @@ function byExpiryAscending(vtxos, now) {
3775
3832
  if (vtxo.isSwept) return -Infinity;
3776
3833
  if (vtxo.expiresAt !== void 0) return vtxo.expiresAt.getTime();
3777
3834
  if (vtxo.expiresAtHeight !== void 0) {
3778
- return chunkZIRFXBKL_cjs.isPastExpiry(vtxo, now) ? -Infinity : Infinity;
3835
+ return chunkEJOFL5WH_cjs.isPastExpiry(vtxo, now) ? -Infinity : Infinity;
3779
3836
  }
3780
3837
  return Infinity;
3781
3838
  };
@@ -3802,7 +3859,7 @@ function priceSettlementInputs(vtxos, estimator) {
3802
3859
  const payable = [];
3803
3860
  const net = /* @__PURE__ */ new Map();
3804
3861
  for (const vtxo of vtxos) {
3805
- const inputFee = estimator.evalOffchainInput(chunkZIRFXBKL_cjs.toOffchainInputFeeParams(vtxo));
3862
+ const inputFee = estimator.evalOffchainInput(chunkEJOFL5WH_cjs.toOffchainInputFeeParams(vtxo));
3806
3863
  if (inputFee.satoshis >= vtxo.value) {
3807
3864
  continue;
3808
3865
  }
@@ -3828,7 +3885,7 @@ function deductOffchainOutputFee(subtotal, estimator, arkAddress) {
3828
3885
  }
3829
3886
  const outputFee = estimator.evalOffchainOutput({
3830
3887
  amount: subtotal,
3831
- script: base.hex.encode(chunkZIRFXBKL_cjs.ArkAddress.decode(arkAddress).pkScript)
3888
+ script: base.hex.encode(chunkEJOFL5WH_cjs.ArkAddress.decode(arkAddress).pkScript)
3832
3889
  });
3833
3890
  return subtotal - BigInt(outputFee.satoshis);
3834
3891
  }
@@ -3846,10 +3903,10 @@ var DEFAULT_SETTLEMENT_CONFIG = {
3846
3903
  };
3847
3904
  function getRecoverableVtxos(vtxos, dustAmount, now) {
3848
3905
  return vtxos.filter((vtxo) => {
3849
- if (chunkZIRFXBKL_cjs.canRecoverOnchain(vtxo, now)) {
3906
+ if (chunkEJOFL5WH_cjs.canRecoverOnchain(vtxo, now)) {
3850
3907
  return true;
3851
3908
  }
3852
- if (chunkZIRFXBKL_cjs.canSpendOffchain(vtxo, now) && vtxo.isPreconfirmed && isSubdust(vtxo, dustAmount)) {
3909
+ if (chunkEJOFL5WH_cjs.canSpendOffchain(vtxo, now) && vtxo.isPreconfirmed && isSubdust(vtxo, dustAmount)) {
3853
3910
  return true;
3854
3911
  }
3855
3912
  return false;
@@ -3879,8 +3936,9 @@ function getRecoverableWithSubdust(vtxos, dustAmount, now) {
3879
3936
  };
3880
3937
  }
3881
3938
  function isVtxoExpiringSoon(vtxo, thresholdMs) {
3939
+ if (vtxo.isUnrolled) return false;
3882
3940
  const realThresholdMs = thresholdMs <= 100 ? DEFAULT_THRESHOLD_MS : thresholdMs;
3883
- const expiresAt = chunkZIRFXBKL_cjs.normalizeVtxo(vtxo).expiresAt;
3941
+ const expiresAt = chunkEJOFL5WH_cjs.normalizeVtxo(vtxo).expiresAt;
3884
3942
  if (expiresAt === void 0) return false;
3885
3943
  const now = Date.now();
3886
3944
  const batchExpiry = expiresAt.getTime();
@@ -3889,7 +3947,9 @@ function isVtxoExpiringSoon(vtxo, thresholdMs) {
3889
3947
  }
3890
3948
  function getExpiringAndRecoverableVtxos(vtxos, thresholdMs, dustAmount, now) {
3891
3949
  return vtxos.filter(
3892
- (vtxo) => isVtxoExpiringSoon(vtxo, thresholdMs) || chunkZIRFXBKL_cjs.canRecoverOnchain(vtxo, now) || isSubdust(vtxo, dustAmount)
3950
+ // The leading exclusion covers the `isSubdust` arm too, which is a value
3951
+ // property and would otherwise re-admit an exited coin on its own.
3952
+ (vtxo) => !vtxo.isUnrolled && (isVtxoExpiringSoon(vtxo, thresholdMs) || chunkEJOFL5WH_cjs.canRecoverOnchain(vtxo, now) || isSubdust(vtxo, dustAmount))
3893
3953
  );
3894
3954
  }
3895
3955
  function isMigrationCapable(wallet) {
@@ -4488,11 +4548,11 @@ var VtxoManager = class _VtxoManager {
4488
4548
  `Sweep not economical: output ${outputAmount} sats after ${fee} sats fee is below dust (${dustAmount} sats)`
4489
4549
  );
4490
4550
  }
4491
- const tx = new chunkZIRFXBKL_cjs.Transaction();
4551
+ const tx = new chunkEJOFL5WH_cjs.Transaction();
4492
4552
  for (const utxo of expiredUtxos) {
4493
- const utxoScript = chunkZIRFXBKL_cjs.VtxoScript.decode(utxo.tapTree);
4553
+ const utxoScript = chunkEJOFL5WH_cjs.VtxoScript.decode(utxo.tapTree);
4494
4554
  const utxoExitLeaf = utxoScript.leaves.find(
4495
- (leaf) => chunkZIRFXBKL_cjs.CSVMultisigTapscript.isScriptValid(chunkZIRFXBKL_cjs.scriptFromTapLeafScript(leaf)) === true
4555
+ (leaf) => chunkEJOFL5WH_cjs.CSVMultisigTapscript.isScriptValid(chunkEJOFL5WH_cjs.scriptFromTapLeafScript(leaf)) === true
4496
4556
  );
4497
4557
  if (!utxoExitLeaf) {
4498
4558
  throw new Error(
@@ -4507,7 +4567,7 @@ var VtxoManager = class _VtxoManager {
4507
4567
  amount: BigInt(utxo.value)
4508
4568
  },
4509
4569
  tapLeafScript: [utxoExitLeaf],
4510
- sequence: chunkZIRFXBKL_cjs.getSequence(utxoExitLeaf)
4570
+ sequence: chunkEJOFL5WH_cjs.getSequence(utxoExitLeaf)
4511
4571
  });
4512
4572
  }
4513
4573
  tx.addOutputAddress(boardingAddress, outputAmount, this.getNetwork());
@@ -4540,6 +4600,7 @@ var VtxoManager = class _VtxoManager {
4540
4600
  async getDeprecatedSignerStatus() {
4541
4601
  const wallet = this.requireMigrationCapableWallet();
4542
4602
  const info = await wallet.arkProvider.getInfo();
4603
+ await wallet.settleServerInfoChanges?.();
4543
4604
  const { reports: vtxoReports } = await this.classifyDeprecatedSignerContracts(info);
4544
4605
  const { reports: boardingReports } = await this.classifyDeprecatedSignerBoarding(info);
4545
4606
  return mergeSignerReports(vtxoReports, boardingReports);
@@ -4553,26 +4614,33 @@ var VtxoManager = class _VtxoManager {
4553
4614
  */
4554
4615
  async migrateCore(options) {
4555
4616
  const wallet = this.requireMigrationCapableWallet();
4617
+ const signerBeforeRefresh = base.hex.encode(wallet.arkServerPublicKey);
4556
4618
  const info = await wallet.arkProvider.getInfo();
4619
+ await wallet.settleServerInfoChanges?.();
4620
+ const rotatedOnRefresh = signerBeforeRefresh !== base.hex.encode(wallet.arkServerPublicKey);
4557
4621
  wallet.refreshDeprecatedSigners(info);
4558
4622
  const signerSet = signerSetFromInfo(info);
4559
4623
  const nowSeconds = Math.floor(Date.now() / 1e3);
4560
4624
  const walletSignerHex = base.hex.encode(wallet.arkServerPublicKey);
4561
4625
  const walletClass = classifyAgainstSignerSet(walletSignerHex, signerSet, nowSeconds);
4562
4626
  if (signerSet.deprecated.size === 0 && walletClass.status === "CURRENT") {
4563
- return { rotated: false, expired: [], signers: [] };
4627
+ return { rotated: rotatedOnRefresh, expired: [], signers: [] };
4564
4628
  }
4565
4629
  if (walletClass.status === "UNKNOWN_SIGNER") {
4566
4630
  const { reports: vtxoReports2 } = await this.classifyDeprecatedSignerContracts(info);
4567
4631
  const { reports: boardingReports2 } = await this.classifyDeprecatedSignerBoarding(info);
4568
4632
  return {
4569
- rotated: false,
4633
+ // Normally false here — a drained rotation targets the active
4634
+ // signer, which classifies CURRENT, not UNKNOWN. It is true only
4635
+ // when a second rotation landed inside the drain, leaving us on a
4636
+ // signer newer than `info`: still a rotation this pass applied.
4637
+ rotated: rotatedOnRefresh,
4570
4638
  expired: [],
4571
4639
  signers: mergeSignerReports(vtxoReports2, boardingReports2),
4572
4640
  skipped: "unknown-wallet-signer"
4573
4641
  };
4574
4642
  }
4575
- const rotated = await this.ensureReceiveOnActiveSigner(info);
4643
+ const rotated = await this.ensureReceiveOnActiveSigner(info) || rotatedOnRefresh;
4576
4644
  const {
4577
4645
  reports: vtxoReports,
4578
4646
  migratable: vtxoMigratable,
@@ -4741,8 +4809,9 @@ var VtxoManager = class _VtxoManager {
4741
4809
  if (!serverPubKey) continue;
4742
4810
  const cls = classifyAgainstSignerSet(serverPubKey, signerSet, nowSeconds);
4743
4811
  if (cls.status === "CURRENT") continue;
4744
- const recoverable = vtxos.filter((v) => v.isSwept && !chunkZIRFXBKL_cjs.hasTerminalSpend(v));
4745
- const spendable = vtxos.filter((v) => !chunkZIRFXBKL_cjs.hasTerminalSpend(v) && !v.isSwept);
4812
+ const live = vtxos.filter((v) => !v.isUnrolled);
4813
+ const recoverable = live.filter((v) => v.isSwept && !chunkEJOFL5WH_cjs.hasTerminalSpend(v));
4814
+ const spendable = live.filter((v) => !chunkEJOFL5WH_cjs.hasTerminalSpend(v) && !v.isSwept);
4746
4815
  const value = spendable.reduce((sum, v) => sum + v.value, 0);
4747
4816
  let recoverableCount = 0;
4748
4817
  let recoverableValue = 0;
@@ -4755,7 +4824,7 @@ var VtxoManager = class _VtxoManager {
4755
4824
  awaitingSweepCount = spendable.length;
4756
4825
  awaitingSweepValue = value;
4757
4826
  for (const v of spendable) {
4758
- const exp = chunkZIRFXBKL_cjs.toBatchExpiry(v);
4827
+ const exp = chunkEJOFL5WH_cjs.toBatchExpiry(v);
4759
4828
  if (exp !== void 0 && (nextSweepEta === void 0 || exp < nextSweepEta)) {
4760
4829
  nextSweepEta = exp;
4761
4830
  }
@@ -5016,7 +5085,7 @@ var VtxoManager = class _VtxoManager {
5016
5085
  /** Decodes the boarding tapscript exit path to extract the CSV timelock. */
5017
5086
  getBoardingTimelock() {
5018
5087
  const wallet = this.getSweepWallet();
5019
- const exitScript = chunkZIRFXBKL_cjs.CSVMultisigTapscript.decode(
5088
+ const exitScript = chunkEJOFL5WH_cjs.CSVMultisigTapscript.decode(
5020
5089
  base.hex.decode(wallet.boardingTapscript.exitScript)
5021
5090
  );
5022
5091
  return exitScript.params.timelock;
@@ -5147,8 +5216,8 @@ var VtxoManager = class _VtxoManager {
5147
5216
  * or doesn't carry the metadata.
5148
5217
  */
5149
5218
  extractSpentOutpoint(error) {
5150
- const ark = chunkZIRFXBKL_cjs.maybeArkError(error);
5151
- if (!chunkZIRFXBKL_cjs.isArkError(ark, chunkZIRFXBKL_cjs.ArkErrorName.VTXO_ALREADY_SPENT)) return void 0;
5219
+ const ark = chunkEJOFL5WH_cjs.maybeArkError(error);
5220
+ if (!chunkEJOFL5WH_cjs.isArkError(ark, chunkEJOFL5WH_cjs.ArkErrorName.VTXO_ALREADY_SPENT)) return void 0;
5152
5221
  const raw = ark.metadata?.vtxo_outpoint;
5153
5222
  if (typeof raw !== "string") return void 0;
5154
5223
  const [txid, voutStr] = raw.split(":");
@@ -5338,7 +5407,7 @@ var VtxoManager = class _VtxoManager {
5338
5407
  if (filteredVtxos.length >= MAX_VTXOS_PER_SETTLEMENT) {
5339
5408
  break;
5340
5409
  }
5341
- const inputFee = estimator.evalOffchainInput(chunkZIRFXBKL_cjs.toOffchainInputFeeParams(v));
5410
+ const inputFee = estimator.evalOffchainInput(chunkEJOFL5WH_cjs.toOffchainInputFeeParams(v));
5342
5411
  if (inputFee.satoshis >= v.value) {
5343
5412
  continue;
5344
5413
  }
@@ -5358,7 +5427,7 @@ var VtxoManager = class _VtxoManager {
5358
5427
  const arkAddress = await this.wallet.getAddress();
5359
5428
  const outputFee = estimator.evalOffchainOutput({
5360
5429
  amount: totalAmount,
5361
- script: base.hex.encode(chunkZIRFXBKL_cjs.ArkAddress.decode(arkAddress).pkScript)
5430
+ script: base.hex.encode(chunkEJOFL5WH_cjs.ArkAddress.decode(arkAddress).pkScript)
5362
5431
  });
5363
5432
  totalAmount -= BigInt(outputFee.satoshis);
5364
5433
  if (totalAmount < dustAmount) return;
@@ -5438,7 +5507,7 @@ var ArkNote = class _ArkNote {
5438
5507
  this.value = value;
5439
5508
  this.HRP = HRP;
5440
5509
  const preimageHash = utils_js.sha256(this.preimage);
5441
- this.vtxoScript = new chunkZIRFXBKL_cjs.VtxoScript([noteTapscript(preimageHash)]);
5510
+ this.vtxoScript = new chunkEJOFL5WH_cjs.VtxoScript([noteTapscript(preimageHash)]);
5442
5511
  const leaf = this.vtxoScript.leaves[0];
5443
5512
  this.txid = base.hex.encode(new Uint8Array(preimageHash).reverse());
5444
5513
  this.tapTree = this.vtxoScript.encode();
@@ -5605,7 +5674,7 @@ var ArkadeCash = class _ArkadeCash {
5605
5674
  const privateKey = data.slice(1, 33);
5606
5675
  const serverPubKey = data.slice(33, 65);
5607
5676
  const sequence = new DataView(data.buffer, data.byteOffset + 65, 4).getUint32(0, false);
5608
- const csvTimelock = chunkZIRFXBKL_cjs.sequenceToTimelock(sequence);
5677
+ const csvTimelock = chunkEJOFL5WH_cjs.sequenceToTimelock(sequence);
5609
5678
  return new _ArkadeCash(privateKey, serverPubKey, csvTimelock, decoded.prefix);
5610
5679
  }
5611
5680
  toString() {
@@ -5613,7 +5682,7 @@ var ArkadeCash = class _ArkadeCash {
5613
5682
  data[0] = _ArkadeCash.Version;
5614
5683
  data.set(this._privateKey, 1);
5615
5684
  data.set(this._serverPubKey, 33);
5616
- const sequence = chunkZIRFXBKL_cjs.timelockToSequence(this.csvTimelock);
5685
+ const sequence = chunkEJOFL5WH_cjs.timelockToSequence(this.csvTimelock);
5617
5686
  new DataView(data.buffer, data.byteOffset + 65, 4).setUint32(0, sequence, false);
5618
5687
  const words = base.bech32m.toWords(data);
5619
5688
  return base.bech32m.encode(this.hrp, words, 1023);
@@ -5622,7 +5691,7 @@ var ArkadeCash = class _ArkadeCash {
5622
5691
  return SingleKey.fromPrivateKey(this._privateKey);
5623
5692
  }
5624
5693
  get vtxoScript() {
5625
- return new chunkPXPPZF5K_cjs.DefaultVtxo.Script({
5694
+ return new chunk6YUACVX4_cjs.DefaultVtxo.Script({
5626
5695
  pubKey: this._publicKey,
5627
5696
  serverPubKey: this._serverPubKey,
5628
5697
  csvTimelock: this.csvTimelock
@@ -5883,7 +5952,7 @@ async function captureExitBranch(params) {
5883
5952
  const nonCommitment = ordered.filter((c) => chainTxTypeToChainedExit(c.type) !== 1 /* Commitment */).map((c) => c.txid);
5884
5953
  if (nonCommitment.length > 0) {
5885
5954
  for (const psbt of await resolver.getVirtualTxs(nonCommitment)) {
5886
- psbtByTxid.set(chunkZIRFXBKL_cjs.Transaction.fromPSBT(base.base64.decode(psbt)).id, psbt);
5955
+ psbtByTxid.set(chunkEJOFL5WH_cjs.Transaction.fromPSBT(base.base64.decode(psbt)).id, psbt);
5887
5956
  }
5888
5957
  }
5889
5958
  }
@@ -5926,10 +5995,10 @@ var IndexerExitDataSource = class {
5926
5995
  while (hasMore) {
5927
5996
  const { chain: page, page: meta } = await this.indexer.getVtxoChain(
5928
5997
  { txid: vtxo.txid, vout: vtxo.vout },
5929
- { pageIndex, pageSize: chunkZIRFXBKL_cjs.DEFAULT_PAGE_SIZE }
5998
+ { pageIndex, pageSize: chunkEJOFL5WH_cjs.DEFAULT_PAGE_SIZE }
5930
5999
  );
5931
6000
  chain.push(...page);
5932
- hasMore = meta ? page.length === chunkZIRFXBKL_cjs.DEFAULT_PAGE_SIZE : false;
6001
+ hasMore = meta ? page.length === chunkEJOFL5WH_cjs.DEFAULT_PAGE_SIZE : false;
5933
6002
  pageIndex++;
5934
6003
  }
5935
6004
  return chain;
@@ -5941,12 +6010,12 @@ var IndexerExitDataSource = class {
5941
6010
  while (hasMore) {
5942
6011
  const { txs, page } = await this.indexer.getVirtualTxs(txids, {
5943
6012
  pageIndex,
5944
- pageSize: chunkZIRFXBKL_cjs.DEFAULT_PAGE_SIZE
6013
+ pageSize: chunkEJOFL5WH_cjs.DEFAULT_PAGE_SIZE
5945
6014
  });
5946
6015
  for (const psbt of txs) {
5947
- out.set(chunkZIRFXBKL_cjs.Transaction.fromPSBT(base.base64.decode(psbt)).id, psbt);
6016
+ out.set(chunkEJOFL5WH_cjs.Transaction.fromPSBT(base.base64.decode(psbt)).id, psbt);
5948
6017
  }
5949
- hasMore = page ? txs.length === chunkZIRFXBKL_cjs.DEFAULT_PAGE_SIZE : false;
6018
+ hasMore = page ? txs.length === chunkEJOFL5WH_cjs.DEFAULT_PAGE_SIZE : false;
5950
6019
  pageIndex++;
5951
6020
  }
5952
6021
  return out;
@@ -5967,7 +6036,7 @@ function chainedTxTypeToChainTxType(t) {
5967
6036
  }
5968
6037
  }
5969
6038
  function psbtInputTxids(psbtBase64) {
5970
- const tx = chunkZIRFXBKL_cjs.Transaction.fromPSBT(base.base64.decode(psbtBase64));
6039
+ const tx = chunkEJOFL5WH_cjs.Transaction.fromPSBT(base.base64.decode(psbtBase64));
5971
6040
  const ids = [];
5972
6041
  for (let i = 0; i < tx.inputsLength; i++) {
5973
6042
  const txid = tx.getInput(i).txid;
@@ -6326,10 +6395,10 @@ async function resolveArkInfo(arkProvider, walletRepository) {
6326
6395
  try {
6327
6396
  info = await arkProvider.getInfo();
6328
6397
  } catch (err) {
6329
- if (!chunkZIRFXBKL_cjs.isRetryableProviderError(err)) throw err;
6398
+ if (!chunkEJOFL5WH_cjs.isRetryableProviderError(err)) throw err;
6330
6399
  const snapshot = await loadArkInfoSnapshot(walletRepository);
6331
6400
  if (!snapshot) {
6332
- throw new chunkZIRFXBKL_cjs.ProviderUnavailableError(
6401
+ throw new chunkEJOFL5WH_cjs.ProviderUnavailableError(
6333
6402
  "Arkade server info is unavailable and no cached snapshot exists",
6334
6403
  { cause: err }
6335
6404
  );
@@ -6412,6 +6481,13 @@ var TxTree = class {
6412
6481
  if (nbOfInputs !== 1) {
6413
6482
  throw new Error(`unexpected number of inputs: ${nbOfInputs}, expected 1`);
6414
6483
  }
6484
+ if (this.root.lockTime !== 0) {
6485
+ throw new Error(`unexpected locktime: ${this.root.lockTime}, expected 0`);
6486
+ }
6487
+ const sequence = this.root.getInput(0).sequence;
6488
+ if (sequence !== void 0 && sequence !== btcSigner.DEFAULT_SEQUENCE) {
6489
+ throw new Error(`unexpected sequence: ${sequence}, expected ${btcSigner.DEFAULT_SEQUENCE}`);
6490
+ }
6415
6491
  if (this.children.size > nbOfOutputs - 1) {
6416
6492
  throw new Error(
6417
6493
  `unexpected number of children: ${this.children.size}, expected maximum ${nbOfOutputs - 1}`
@@ -6712,7 +6788,7 @@ function collectArkTxidsNeedingCreatedAt(vtxos) {
6712
6788
  return [...txids];
6713
6789
  }
6714
6790
  async function buildTransactionHistory(vtxos, allBoardingTxs, commitmentsToIgnore, resolveTxCreatedAt) {
6715
- const fromOldestVtxo = vtxos.map(chunkZIRFXBKL_cjs.normalizeVtxo).sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
6791
+ const fromOldestVtxo = vtxos.map(chunkEJOFL5WH_cjs.normalizeVtxo).sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
6716
6792
  const txidsNeedingCreatedAt = resolveTxCreatedAt ? collectArkTxidsNeedingCreatedAt(fromOldestVtxo) : [];
6717
6793
  const resolvedCreatedAt = resolveTxCreatedAt && txidsNeedingCreatedAt.length > 0 ? await resolveTxCreatedAt(txidsNeedingCreatedAt) : /* @__PURE__ */ new Map();
6718
6794
  const unmatchedSettledBoardingTxs = allBoardingTxs.filter(isSettledBoardingReceive).sort((a, b) => a.createdAt - b.createdAt);
@@ -6876,7 +6952,7 @@ var AssetManager = class extends ReadonlyAssetManager {
6876
6952
  const virtualCoins = await this.wallet.getSpendableVtxos({
6877
6953
  withRecoverable: false
6878
6954
  });
6879
- const controlAssetRef = params.controlAssetId ? chunk3S3JZUEN_cjs.AssetRef.fromId(chunk3S3JZUEN_cjs.AssetId.fromString(params.controlAssetId)) : null;
6955
+ const controlAssetRef = params.controlAssetId ? chunkPJR63FTK_cjs.AssetRef.fromId(chunkPJR63FTK_cjs.AssetId.fromString(params.controlAssetId)) : null;
6880
6956
  const coinSelection = selectVirtualCoins(virtualCoins, Number(this.wallet.dustAmount));
6881
6957
  let totalBtcSelected = 0n;
6882
6958
  const assetChanges = /* @__PURE__ */ new Map();
@@ -6889,8 +6965,8 @@ var AssetManager = class extends ReadonlyAssetManager {
6889
6965
  }
6890
6966
  }
6891
6967
  const groups = [];
6892
- const issuedAssetOutput = chunk3S3JZUEN_cjs.AssetOutput.create(0, params.amount);
6893
- const issuedAssetGroup = chunk3S3JZUEN_cjs.AssetGroup.create(
6968
+ const issuedAssetOutput = chunkPJR63FTK_cjs.AssetOutput.create(0, params.amount);
6969
+ const issuedAssetGroup = chunkPJR63FTK_cjs.AssetGroup.create(
6894
6970
  null,
6895
6971
  controlAssetRef,
6896
6972
  [],
@@ -6905,28 +6981,28 @@ var AssetManager = class extends ReadonlyAssetManager {
6905
6981
  for (const [inputIndex, assets] of assetInputs) {
6906
6982
  for (const asset of assets) {
6907
6983
  if (asset.assetId !== assetId) continue;
6908
- changeInputs.push(chunk3S3JZUEN_cjs.AssetInput.create(inputIndex, asset.amount));
6984
+ changeInputs.push(chunkPJR63FTK_cjs.AssetInput.create(inputIndex, asset.amount));
6909
6985
  }
6910
6986
  }
6911
6987
  groups.push(
6912
- chunk3S3JZUEN_cjs.AssetGroup.create(
6913
- chunk3S3JZUEN_cjs.AssetId.fromString(assetId),
6988
+ chunkPJR63FTK_cjs.AssetGroup.create(
6989
+ chunkPJR63FTK_cjs.AssetId.fromString(assetId),
6914
6990
  null,
6915
6991
  changeInputs,
6916
- [chunk3S3JZUEN_cjs.AssetOutput.create(0, amount)],
6992
+ [chunkPJR63FTK_cjs.AssetOutput.create(0, amount)],
6917
6993
  []
6918
6994
  )
6919
6995
  );
6920
6996
  }
6921
6997
  }
6922
6998
  const address = await this.wallet.getAddress();
6923
- const outputAddress = chunkZIRFXBKL_cjs.ArkAddress.decode(address);
6999
+ const outputAddress = chunkEJOFL5WH_cjs.ArkAddress.decode(address);
6924
7000
  const outputs = [
6925
7001
  {
6926
7002
  script: outputAddress.pkScript,
6927
7003
  amount: BigInt(totalBtcSelected)
6928
7004
  },
6929
- Extension.create([chunk3S3JZUEN_cjs.Packet.create(groups)]).txOut()
7005
+ Extension.create([chunkPJR63FTK_cjs.Packet.create(groups)]).txOut()
6930
7006
  ];
6931
7007
  const { arkTxid } = await this.wallet.buildAndSubmitOffchainTx(
6932
7008
  coinSelection.inputs,
@@ -6934,7 +7010,7 @@ var AssetManager = class extends ReadonlyAssetManager {
6934
7010
  );
6935
7011
  return {
6936
7012
  arkTxId: arkTxid,
6937
- assetId: chunk3S3JZUEN_cjs.AssetId.create(arkTxid, 0).toString()
7013
+ assetId: chunkPJR63FTK_cjs.AssetId.create(arkTxid, 0).toString()
6938
7014
  };
6939
7015
  }
6940
7016
  /**
@@ -7006,16 +7082,16 @@ var AssetManager = class extends ReadonlyAssetManager {
7006
7082
  for (const [inputIndex, assets] of assetInputs) {
7007
7083
  for (const asset of assets) {
7008
7084
  if (asset.assetId !== params.assetId) continue;
7009
- reissueInputs.push(chunk3S3JZUEN_cjs.AssetInput.create(inputIndex, asset.amount));
7085
+ reissueInputs.push(chunkPJR63FTK_cjs.AssetInput.create(inputIndex, asset.amount));
7010
7086
  }
7011
7087
  }
7012
7088
  const totalAssetAmount = assetToReissueAmount + params.amount;
7013
- const reissueAssetIdObj = chunk3S3JZUEN_cjs.AssetId.fromString(params.assetId);
7014
- const reissueAssetGroup = chunk3S3JZUEN_cjs.AssetGroup.create(
7089
+ const reissueAssetIdObj = chunkPJR63FTK_cjs.AssetId.fromString(params.assetId);
7090
+ const reissueAssetGroup = chunkPJR63FTK_cjs.AssetGroup.create(
7015
7091
  reissueAssetIdObj,
7016
7092
  null,
7017
7093
  reissueInputs,
7018
- [chunk3S3JZUEN_cjs.AssetOutput.create(0, totalAssetAmount)],
7094
+ [chunkPJR63FTK_cjs.AssetOutput.create(0, totalAssetAmount)],
7019
7095
  []
7020
7096
  );
7021
7097
  const groups = [reissueAssetGroup];
@@ -7024,27 +7100,27 @@ var AssetManager = class extends ReadonlyAssetManager {
7024
7100
  for (const [inputIndex, assets] of assetInputs) {
7025
7101
  for (const asset of assets) {
7026
7102
  if (asset.assetId !== assetId) continue;
7027
- changeInputs.push(chunk3S3JZUEN_cjs.AssetInput.create(inputIndex, asset.amount));
7103
+ changeInputs.push(chunkPJR63FTK_cjs.AssetInput.create(inputIndex, asset.amount));
7028
7104
  }
7029
7105
  }
7030
7106
  groups.push(
7031
- chunk3S3JZUEN_cjs.AssetGroup.create(
7032
- chunk3S3JZUEN_cjs.AssetId.fromString(assetId),
7107
+ chunkPJR63FTK_cjs.AssetGroup.create(
7108
+ chunkPJR63FTK_cjs.AssetId.fromString(assetId),
7033
7109
  null,
7034
7110
  changeInputs,
7035
- [chunk3S3JZUEN_cjs.AssetOutput.create(0, amount)],
7111
+ [chunkPJR63FTK_cjs.AssetOutput.create(0, amount)],
7036
7112
  []
7037
7113
  )
7038
7114
  );
7039
7115
  }
7040
7116
  const address = await this.wallet.getAddress();
7041
- const outputAddress = chunkZIRFXBKL_cjs.ArkAddress.decode(address);
7117
+ const outputAddress = chunkEJOFL5WH_cjs.ArkAddress.decode(address);
7042
7118
  const outputs = [
7043
7119
  {
7044
7120
  script: outputAddress.pkScript,
7045
7121
  amount: BigInt(totalBtcSelected)
7046
7122
  },
7047
- Extension.create([chunk3S3JZUEN_cjs.Packet.create(groups)]).txOut()
7123
+ Extension.create([chunkPJR63FTK_cjs.Packet.create(groups)]).txOut()
7048
7124
  ];
7049
7125
  const { arkTxid } = await this.wallet.buildAndSubmitOffchainTx(selectedCoins, outputs);
7050
7126
  return arkTxid;
@@ -7111,27 +7187,27 @@ var AssetManager = class extends ReadonlyAssetManager {
7111
7187
  for (const [inputIndex, assets] of assetInputs) {
7112
7188
  for (const asset of assets) {
7113
7189
  if (asset.assetId !== assetId) continue;
7114
- changeInputs.push(chunk3S3JZUEN_cjs.AssetInput.create(inputIndex, asset.amount));
7190
+ changeInputs.push(chunkPJR63FTK_cjs.AssetInput.create(inputIndex, asset.amount));
7115
7191
  }
7116
7192
  }
7117
7193
  groups.push(
7118
- chunk3S3JZUEN_cjs.AssetGroup.create(
7119
- chunk3S3JZUEN_cjs.AssetId.fromString(assetId),
7194
+ chunkPJR63FTK_cjs.AssetGroup.create(
7195
+ chunkPJR63FTK_cjs.AssetId.fromString(assetId),
7120
7196
  null,
7121
7197
  changeInputs,
7122
- amount > 0n ? [chunk3S3JZUEN_cjs.AssetOutput.create(0, amount)] : [],
7198
+ amount > 0n ? [chunkPJR63FTK_cjs.AssetOutput.create(0, amount)] : [],
7123
7199
  []
7124
7200
  )
7125
7201
  );
7126
7202
  }
7127
7203
  const address = await this.wallet.getAddress();
7128
- const outputAddress = chunkZIRFXBKL_cjs.ArkAddress.decode(address);
7204
+ const outputAddress = chunkEJOFL5WH_cjs.ArkAddress.decode(address);
7129
7205
  const outputs = [
7130
7206
  {
7131
7207
  script: outputAddress.pkScript,
7132
7208
  amount: BigInt(totalBtcSelected)
7133
7209
  },
7134
- Extension.create([chunk3S3JZUEN_cjs.Packet.create(groups)]).txOut()
7210
+ Extension.create([chunkPJR63FTK_cjs.Packet.create(groups)]).txOut()
7135
7211
  ];
7136
7212
  const { arkTxid } = await this.wallet.buildAndSubmitOffchainTx(selectedCoins, outputs);
7137
7213
  return arkTxid;
@@ -7156,7 +7232,7 @@ function castMetadata(metadata) {
7156
7232
  } else {
7157
7233
  throw new Error("Invalid metadata value type");
7158
7234
  }
7159
- md.push(chunk3S3JZUEN_cjs.Metadata.create(textEncoder.encode(key), valueBytes));
7235
+ md.push(chunkPJR63FTK_cjs.Metadata.create(textEncoder.encode(key), valueBytes));
7160
7236
  }
7161
7237
  return md;
7162
7238
  }
@@ -7177,10 +7253,10 @@ var DelegateManagerImpl = class {
7177
7253
  if (vtxos.length === 0) {
7178
7254
  return { delegated: [], failed: [] };
7179
7255
  }
7180
- const destinationScript = chunkZIRFXBKL_cjs.ArkAddress.decode(destination).pkScript;
7256
+ const destinationScript = chunkEJOFL5WH_cjs.ArkAddress.decode(destination).pkScript;
7181
7257
  const arkInfo = await this.arkInfoProvider.getInfo();
7182
7258
  const delegateInfo = await this.delegateProvider.getDelegateInfo();
7183
- const eligible = vtxos.map(chunkZIRFXBKL_cjs.normalizeVtxo).filter(
7259
+ const eligible = vtxos.map(chunkEJOFL5WH_cjs.normalizeVtxo).filter(
7184
7260
  (v) => isAnnotated(v) && findDelegateTapLeaf(v, delegateInfo.pubkey) !== void 0
7185
7261
  );
7186
7262
  if (eligible.length === 0) {
@@ -7209,11 +7285,11 @@ var DelegateManagerImpl = class {
7209
7285
  const groupByExpiry = /* @__PURE__ */ new Map();
7210
7286
  let recoverableVtxos = [];
7211
7287
  for (const vtxo of eligible) {
7212
- if (chunkZIRFXBKL_cjs.canRecoverOnchain(vtxo, now)) {
7288
+ if (chunkEJOFL5WH_cjs.canRecoverOnchain(vtxo, now)) {
7213
7289
  recoverableVtxos.push(vtxo);
7214
7290
  continue;
7215
7291
  }
7216
- const expiry = chunkZIRFXBKL_cjs.toBatchExpiry(vtxo);
7292
+ const expiry = chunkEJOFL5WH_cjs.toBatchExpiry(vtxo);
7217
7293
  if (!expiry) continue;
7218
7294
  const dayKey = getDayTimestamp(expiry);
7219
7295
  groupByExpiry.set(dayKey, [...groupByExpiry.get(dayKey) ?? [], vtxo]);
@@ -7278,7 +7354,7 @@ async function delegate(identity, delegateProvider, arkInfo, delegateInfo, vtxos
7278
7354
  }
7279
7355
  if (!delegateAt) {
7280
7356
  const now = { timestamp: /* @__PURE__ */ new Date() };
7281
- const expiryTimestamp = vtxos.filter((coin) => !chunkZIRFXBKL_cjs.canRecoverOnchain(coin, now) && chunkZIRFXBKL_cjs.toBatchExpiry(coin)).reduce((min, coin) => Math.min(min, chunkZIRFXBKL_cjs.toBatchExpiry(coin)), Number.MAX_SAFE_INTEGER);
7357
+ const expiryTimestamp = vtxos.filter((coin) => !chunkEJOFL5WH_cjs.canRecoverOnchain(coin, now) && chunkEJOFL5WH_cjs.toBatchExpiry(coin)).reduce((min, coin) => Math.min(min, chunkEJOFL5WH_cjs.toBatchExpiry(coin)), Number.MAX_SAFE_INTEGER);
7282
7358
  if (!expiryTimestamp || expiryTimestamp === Number.MAX_SAFE_INTEGER) {
7283
7359
  delegateAt = new Date(Date.now() + 1 * 60 * 1e3);
7284
7360
  } else {
@@ -7307,7 +7383,7 @@ async function delegate(identity, delegateProvider, arkInfo, delegateInfo, vtxos
7307
7383
  let amount = 0n;
7308
7384
  for (const coin of vtxos) {
7309
7385
  const inputFee = estimator.evalOffchainInput({
7310
- ...chunkZIRFXBKL_cjs.toOffchainInputFeeParams(coin),
7386
+ ...chunkEJOFL5WH_cjs.toOffchainInputFeeParams(coin),
7311
7387
  type: "vtxo"
7312
7388
  });
7313
7389
  if (inputFee.value >= coin.value) {
@@ -7321,7 +7397,7 @@ async function delegate(identity, delegateProvider, arkInfo, delegateInfo, vtxos
7321
7397
  const delegateFee = BigInt(Number(fee));
7322
7398
  if (delegateFee > 0n) {
7323
7399
  outputs.push({
7324
- script: chunkZIRFXBKL_cjs.ArkAddress.decode(delegateAddress).pkScript,
7400
+ script: chunkEJOFL5WH_cjs.ArkAddress.decode(delegateAddress).pkScript,
7325
7401
  amount: delegateFee
7326
7402
  });
7327
7403
  }
@@ -7354,10 +7430,10 @@ async function delegate(identity, delegateProvider, arkInfo, delegateInfo, vtxos
7354
7430
  destinationScript
7355
7431
  );
7356
7432
  const forfeitOutputScript = btcSigner.OutScript.encode(
7357
- btcSigner.Address(chunkZIRFXBKL_cjs.getNetwork(network)).decode(forfeitAddress)
7433
+ btcSigner.Address(chunkEJOFL5WH_cjs.getNetwork(network)).decode(forfeitAddress)
7358
7434
  );
7359
7435
  const forfeits = await Promise.all(
7360
- vtxos.filter((v) => !chunkZIRFXBKL_cjs.canRecoverOnchain(v, { timestamp: /* @__PURE__ */ new Date() })).map(async (coin) => {
7436
+ vtxos.filter((v) => !chunkEJOFL5WH_cjs.canRecoverOnchain(v, { timestamp: /* @__PURE__ */ new Date() })).map(async (coin) => {
7361
7437
  const forfeit = await makeDelegateForfeitTx(
7362
7438
  coin,
7363
7439
  dust,
@@ -7382,7 +7458,7 @@ async function makeDelegateForfeitTx(input, connectorAmount, delegatePubkey, for
7382
7458
  index: input.vout,
7383
7459
  witnessUtxo: {
7384
7460
  amount: BigInt(input.value),
7385
- script: chunkZIRFXBKL_cjs.VtxoScript.decode(input.tapTree).pkScript
7461
+ script: chunkEJOFL5WH_cjs.VtxoScript.decode(input.tapTree).pkScript
7386
7462
  },
7387
7463
  sighashType: btcSigner.SigHash.ALL_ANYONECANPAY,
7388
7464
  tapLeafScript: [delegateTapLeaf]
@@ -7440,7 +7516,7 @@ async function makeSignedDelegateIntent(identity, coins, outputs, onchainOutputs
7440
7516
  expire_at: 0,
7441
7517
  cosigners_public_keys: cosignerPubKeys
7442
7518
  };
7443
- const proof = chunkZIRFXBKL_cjs.Intent.create(message, coins, outputs);
7519
+ const proof = chunkEJOFL5WH_cjs.Intent.create(message, coins, outputs);
7444
7520
  const signedProof = await identity.sign(proof);
7445
7521
  return {
7446
7522
  proof: base.base64.encode(signedProof.toPSBT()),
@@ -7458,10 +7534,10 @@ function getDayTimestamp(timestamp) {
7458
7534
  function findDelegateTapLeaf(vtxo, delegatePubkey) {
7459
7535
  if (!vtxo.tapTree) return void 0;
7460
7536
  const pk = delegatePubkey.length === 66 ? delegatePubkey.slice(2) : delegatePubkey;
7461
- const vtxoScript = chunkZIRFXBKL_cjs.VtxoScript.decode(vtxo.tapTree);
7537
+ const vtxoScript = chunkEJOFL5WH_cjs.VtxoScript.decode(vtxo.tapTree);
7462
7538
  return vtxoScript.leaves.find((tapLeaf) => {
7463
- const arkTapscript = chunkZIRFXBKL_cjs.decodeTapscript(chunkZIRFXBKL_cjs.scriptFromTapLeafScript(tapLeaf));
7464
- if (!chunkZIRFXBKL_cjs.MultisigTapscript.is(arkTapscript)) return false;
7539
+ const arkTapscript = chunkEJOFL5WH_cjs.decodeTapscript(chunkEJOFL5WH_cjs.scriptFromTapLeafScript(tapLeaf));
7540
+ if (!chunkEJOFL5WH_cjs.MultisigTapscript.is(arkTapscript)) return false;
7465
7541
  return arkTapscript.params.pubkeys.map(base.hex.encode).includes(pk);
7466
7542
  });
7467
7543
  }
@@ -7742,7 +7818,7 @@ function createManagedConnection(dbName, version, initDatabase2) {
7742
7818
  };
7743
7819
  }
7744
7820
  function scriptFromArkAddress(address) {
7745
- return base.hex.encode(chunkZIRFXBKL_cjs.ArkAddress.decode(address).pkScript);
7821
+ return base.hex.encode(chunkEJOFL5WH_cjs.ArkAddress.decode(address).pkScript);
7746
7822
  }
7747
7823
 
7748
7824
  // src/repositories/indexedDB/schema.ts
@@ -8237,7 +8313,7 @@ function validateVtxosForScript(vtxos, script, context) {
8237
8313
  }
8238
8314
  async function getVtxosForContract(repo, contract) {
8239
8315
  const vtxos = repo.getVtxosForScript ? await repo.getVtxosForScript(contract.script) : filterVtxosForScript(await repo.getVtxos(contract.address), contract.script);
8240
- return vtxos.map(chunkZIRFXBKL_cjs.normalizeVtxo);
8316
+ return vtxos.map(chunkEJOFL5WH_cjs.normalizeVtxo);
8241
8317
  }
8242
8318
  async function saveVtxosForContract(repo, contract, vtxos) {
8243
8319
  if (repo.saveVtxosForScript) {
@@ -8379,7 +8455,7 @@ function decodeArkContract(encoded) {
8379
8455
  }
8380
8456
  function contractFromArkContract(encoded, options = {}) {
8381
8457
  const parsed = decodeArkContract(encoded);
8382
- const handler = chunkPXPPZF5K_cjs.contractHandlers.get(parsed.type);
8458
+ const handler = chunk6YUACVX4_cjs.contractHandlers.get(parsed.type);
8383
8459
  if (!handler) {
8384
8460
  throw new Error(`No handler registered for contract type '${parsed.type}'`);
8385
8461
  }
@@ -8393,9 +8469,9 @@ function contractFromArkContract(encoded, options = {}) {
8393
8469
  metadata: options.metadata
8394
8470
  };
8395
8471
  }
8396
- function contractFromArkContractWithAddress(encoded, serverPubKey, addressPrefix = chunkZIRFXBKL_cjs.DEFAULT_NETWORK.hrp, options = {}) {
8472
+ function contractFromArkContractWithAddress(encoded, serverPubKey, addressPrefix = chunkEJOFL5WH_cjs.DEFAULT_NETWORK.hrp, options = {}) {
8397
8473
  const parsed = decodeArkContract(encoded);
8398
- const handler = chunkPXPPZF5K_cjs.contractHandlers.getOrThrow(parsed.type);
8474
+ const handler = chunk6YUACVX4_cjs.contractHandlers.getOrThrow(parsed.type);
8399
8475
  const params = parsed.data;
8400
8476
  const vtxoScript = handler.createScript(params);
8401
8477
  return {
@@ -8649,9 +8725,9 @@ var ContractWatcher = class {
8649
8725
  this.connectionState = "connected";
8650
8726
  this.reconnectAttempts = 0;
8651
8727
  this.listenLoop().catch((e) => {
8652
- if (chunkZIRFXBKL_cjs.isEventSourceError(e)) {
8728
+ if (chunkEJOFL5WH_cjs.isEventSourceError(e)) {
8653
8729
  console.debug("ContractWatcher subscription disconnected; reconnecting");
8654
- } else if (!chunkZIRFXBKL_cjs.isEventSourceUnavailableError(e)) {
8730
+ } else if (!chunkEJOFL5WH_cjs.isEventSourceUnavailableError(e)) {
8655
8731
  console.error(e);
8656
8732
  }
8657
8733
  this.connectionState = "disconnected";
@@ -8663,7 +8739,7 @@ var ContractWatcher = class {
8663
8739
  this.scheduleReconnect();
8664
8740
  });
8665
8741
  } catch (error) {
8666
- if (!chunkZIRFXBKL_cjs.isEventSourceUnavailableError(error)) {
8742
+ if (!chunkEJOFL5WH_cjs.isEventSourceUnavailableError(error)) {
8667
8743
  console.error("ContractWatcher connection failed:", error);
8668
8744
  }
8669
8745
  this.connectionState = "disconnected";
@@ -8689,7 +8765,7 @@ var ContractWatcher = class {
8689
8765
  * slower; what it loses is push latency.
8690
8766
  */
8691
8767
  reportEventSourceUnavailable(error) {
8692
- if (!chunkZIRFXBKL_cjs.isEventSourceUnavailableError(error)) return false;
8768
+ if (!chunkEJOFL5WH_cjs.isEventSourceUnavailableError(error)) return false;
8693
8769
  if (!this.eventSourceReported) {
8694
8770
  this.eventSourceReported = true;
8695
8771
  console.warn(
@@ -8905,14 +8981,14 @@ var ContractWatcher = class {
8905
8981
  const timestamp = Date.now();
8906
8982
  if (update.newVtxos?.length) {
8907
8983
  this.processSubscriptionVtxos(
8908
- update.newVtxos.map(chunkZIRFXBKL_cjs.normalizeVtxo),
8984
+ update.newVtxos.map(chunkEJOFL5WH_cjs.normalizeVtxo),
8909
8985
  "vtxo_received",
8910
8986
  timestamp
8911
8987
  );
8912
8988
  }
8913
8989
  if (update.spentVtxos?.length) {
8914
8990
  this.processSubscriptionVtxos(
8915
- update.spentVtxos.map(chunkZIRFXBKL_cjs.normalizeVtxo),
8991
+ update.spentVtxos.map(chunkEJOFL5WH_cjs.normalizeVtxo),
8916
8992
  "vtxo_spent",
8917
8993
  timestamp
8918
8994
  );
@@ -9007,7 +9083,7 @@ var NON_TERMINAL_INTENT_STATES = ALL_INTENT_STATES.filter(
9007
9083
  (s) => !isTerminalIntentState(s)
9008
9084
  );
9009
9085
  function isConsumed(vtxo) {
9010
- return vtxo !== void 0 && (vtxo.isSpent === true || vtxo.settledBy !== void 0);
9086
+ return vtxo !== void 0 && chunkEJOFL5WH_cjs.hasTerminalSpend(vtxo);
9011
9087
  }
9012
9088
  async function classifyIntent(intent, vtxosByOutpoint, now) {
9013
9089
  if (isTerminalIntentState(intent.state)) return void 0;
@@ -9017,6 +9093,11 @@ async function classifyIntent(intent, vtxosByOutpoint, now) {
9017
9093
  const commitmentTransactionId = intent.commitmentTransactionId ?? consumed.map((v) => v?.settledBy).find((s) => !!s);
9018
9094
  return terminal(intent, "batch_succeeded", now, { commitmentTransactionId });
9019
9095
  }
9096
+ if (consumed.some((vtxo) => vtxo?.isUnrolled)) {
9097
+ return terminal(intent, "cancelled", now, {
9098
+ cancellationReason: "reconciliation: an input was unilaterally exited"
9099
+ });
9100
+ }
9020
9101
  if (intent.state === "waiting_to_submit") {
9021
9102
  return terminal(intent, "cancelled", now, {
9022
9103
  cancellationReason: "reconciliation: intent was never submitted before restart"
@@ -9045,7 +9126,7 @@ async function reconcileIntents(deps) {
9045
9126
  let vtxosByOutpoint = /* @__PURE__ */ new Map();
9046
9127
  if (outpoints.length > 0) {
9047
9128
  try {
9048
- const { vtxos } = await chunkZIRFXBKL_cjs.getNormalizedVtxos(deps.indexerProvider, { outpoints });
9129
+ const { vtxos } = await chunkEJOFL5WH_cjs.getNormalizedVtxos(deps.indexerProvider, { outpoints });
9049
9130
  vtxosByOutpoint = new Map(vtxos.map((v) => [outpointKey(v), v]));
9050
9131
  } catch (e) {
9051
9132
  console.error("reconcileIntents: failed to fetch input VTXO state", e);
@@ -9219,7 +9300,7 @@ var ContractManager = class _ContractManager {
9219
9300
  await this.reconcileWatched();
9220
9301
  this.markSyncOnline();
9221
9302
  } catch (err) {
9222
- if (!chunkZIRFXBKL_cjs.isRetryableProviderError(err)) throw err;
9303
+ if (!chunkEJOFL5WH_cjs.isRetryableProviderError(err)) throw err;
9223
9304
  this.markSyncDegraded(err);
9224
9305
  }
9225
9306
  this.initialized = true;
@@ -9351,7 +9432,7 @@ var ContractManager = class _ContractManager {
9351
9432
  const from = Math.max(0, watermark - lookAhead.size);
9352
9433
  const to = watermark + lookAhead.size;
9353
9434
  const deps = lookAhead.candidateDeps();
9354
- const handlers = chunkPXPPZF5K_cjs.contractHandlers.getRegisteredTypes().map((t) => chunkPXPPZF5K_cjs.contractHandlers.get(t)).filter(hasCandidates);
9435
+ const handlers = chunk6YUACVX4_cjs.contractHandlers.getRegisteredTypes().map((t) => chunk6YUACVX4_cjs.contractHandlers.get(t)).filter(hasCandidates);
9355
9436
  const band = /* @__PURE__ */ new Map();
9356
9437
  for (let index = from; index <= to; index++) {
9357
9438
  const descriptor = lookAhead.materialize(index);
@@ -9362,7 +9443,7 @@ var ContractManager = class _ContractManager {
9362
9443
  index,
9363
9444
  params: {
9364
9445
  ...candidate,
9365
- ...chunkPXPPZF5K_cjs.speculativeReceiveMetadata(descriptor)
9446
+ ...chunk6YUACVX4_cjs.speculativeReceiveMetadata(descriptor)
9366
9447
  }
9367
9448
  });
9368
9449
  }
@@ -9424,7 +9505,7 @@ var ContractManager = class _ContractManager {
9424
9505
  });
9425
9506
  for (const entry of pending) entry.catchUpPending = false;
9426
9507
  } catch (err) {
9427
- if (!chunkZIRFXBKL_cjs.isRetryableProviderError(err)) throw err;
9508
+ if (!chunkEJOFL5WH_cjs.isRetryableProviderError(err)) throw err;
9428
9509
  this.markSyncDegraded(err);
9429
9510
  }
9430
9511
  }
@@ -9474,7 +9555,7 @@ var ContractManager = class _ContractManager {
9474
9555
  await this.fetchContractVxosFromIndexer([contract]);
9475
9556
  this.markSyncOnline();
9476
9557
  } catch (err) {
9477
- if (!chunkZIRFXBKL_cjs.isRetryableProviderError(err)) throw err;
9558
+ if (!chunkEJOFL5WH_cjs.isRetryableProviderError(err)) throw err;
9478
9559
  this.markSyncDegraded(err);
9479
9560
  }
9480
9561
  await this.watcher.addContract(contract);
@@ -9511,7 +9592,7 @@ var ContractManager = class _ContractManager {
9511
9592
  return result;
9512
9593
  }
9513
9594
  async upsertContractRow(params) {
9514
- const handler = chunkPXPPZF5K_cjs.contractHandlers.get(params.type);
9595
+ const handler = chunk6YUACVX4_cjs.contractHandlers.get(params.type);
9515
9596
  if (!handler) {
9516
9597
  throw new Error(`No handler registered for contract type '${params.type}'`);
9517
9598
  }
@@ -9611,7 +9692,7 @@ var ContractManager = class _ContractManager {
9611
9692
  `scanContracts: batchSize must be a positive integer (got ${String(opts.batchSize)})`
9612
9693
  );
9613
9694
  }
9614
- const registered = chunkPXPPZF5K_cjs.contractHandlers.getRegisteredTypes().map((t) => chunkPXPPZF5K_cjs.contractHandlers.get(t)).filter(isDiscoverable);
9695
+ const registered = chunk6YUACVX4_cjs.contractHandlers.getRegisteredTypes().map((t) => chunk6YUACVX4_cjs.contractHandlers.get(t)).filter(isDiscoverable);
9615
9696
  const discoverables = [
9616
9697
  ...registered.filter((h) => h.type === "boarding"),
9617
9698
  ...registered.filter((h) => h.type !== "boarding")
@@ -9746,7 +9827,7 @@ var ContractManager = class _ContractManager {
9746
9827
  await this.syncContracts({ contracts, pageSize });
9747
9828
  this.markSyncOnline();
9748
9829
  } catch (err) {
9749
- if (!chunkZIRFXBKL_cjs.isRetryableProviderError(err)) throw err;
9830
+ if (!chunkEJOFL5WH_cjs.isRetryableProviderError(err)) throw err;
9750
9831
  this.markSyncDegraded(err);
9751
9832
  }
9752
9833
  const vtxos = await this.getVtxosForContracts(contracts);
@@ -9767,7 +9848,7 @@ var ContractManager = class _ContractManager {
9767
9848
  }
9768
9849
  const tapscriptCache = tapscripts ?? /* @__PURE__ */ new Map();
9769
9850
  return vtxos.map(
9770
- (vtxo) => extendVirtualCoinForContract(chunkZIRFXBKL_cjs.normalizeVtxo(vtxo), byScript, tapscriptCache)
9851
+ (vtxo) => extendVirtualCoinForContract(chunkEJOFL5WH_cjs.normalizeVtxo(vtxo), byScript, tapscriptCache)
9771
9852
  );
9772
9853
  }
9773
9854
  /** @inheritdoc */
@@ -9811,14 +9892,14 @@ var ContractManager = class _ContractManager {
9811
9892
  const byScript = new Map(contracts.map((contract) => [contract.script, contract]));
9812
9893
  const asking = vtxos.filter((vtxo) => {
9813
9894
  const contract = byScript.get(vtxo.script);
9814
- return contract !== void 0 && chunkPXPPZF5K_cjs.contractHandlers.get(contract.type)?.assertSpendableNow !== void 0;
9895
+ return contract !== void 0 && chunk6YUACVX4_cjs.contractHandlers.get(contract.type)?.assertSpendableNow !== void 0;
9815
9896
  });
9816
9897
  if (asking.length === 0) return refused;
9817
9898
  const tip = await this.currentChainTip();
9818
9899
  const walletKey = await walletPubKey?.();
9819
9900
  for (const vtxo of asking) {
9820
9901
  const contract = byScript.get(vtxo.script);
9821
- const handler = chunkPXPPZF5K_cjs.contractHandlers.get(contract.type);
9902
+ const handler = chunk6YUACVX4_cjs.contractHandlers.get(contract.type);
9822
9903
  if (!handler?.assertSpendableNow) continue;
9823
9904
  const context = {
9824
9905
  collaborative: true,
@@ -9833,7 +9914,7 @@ var ContractManager = class _ContractManager {
9833
9914
  // the next handler to answer a CSV question would meet a
9834
9915
  // TypeError instead of a `false`. Carry the coin only when it
9835
9916
  // really is one.
9836
- vtxo: chunkZIRFXBKL_cjs.isVirtualCoin(vtxo) && "status" in vtxo ? vtxo : void 0
9917
+ vtxo: chunkEJOFL5WH_cjs.isVirtualCoin(vtxo) && "status" in vtxo ? vtxo : void 0
9837
9918
  };
9838
9919
  try {
9839
9920
  await handler.assertSpendableNow(
@@ -9989,7 +10070,7 @@ var ContractManager = class _ContractManager {
9989
10070
  const { contractScript, collaborative = true, walletPubKey, vtxo } = options;
9990
10071
  const [contract] = await this.getContracts({ script: contractScript });
9991
10072
  if (!contract) return [];
9992
- const handler = chunkPXPPZF5K_cjs.contractHandlers.get(contract.type);
10073
+ const handler = chunk6YUACVX4_cjs.contractHandlers.get(contract.type);
9993
10074
  if (!handler) return [];
9994
10075
  const script = handler.createScript(contract.params);
9995
10076
  const tip = await this.currentChainTip();
@@ -10017,7 +10098,7 @@ var ContractManager = class _ContractManager {
10017
10098
  const { contractScript, collaborative = true, walletPubKey } = options;
10018
10099
  const [contract] = await this.getContracts({ script: contractScript });
10019
10100
  if (!contract) return [];
10020
- const handler = chunkPXPPZF5K_cjs.contractHandlers.get(contract.type);
10101
+ const handler = chunk6YUACVX4_cjs.contractHandlers.get(contract.type);
10021
10102
  if (!handler) return [];
10022
10103
  const script = handler.createScript(contract.params);
10023
10104
  const context = {
@@ -10073,7 +10154,7 @@ var ContractManager = class _ContractManager {
10073
10154
  }
10074
10155
  async refreshOutpoints(outpoints) {
10075
10156
  if (outpoints.length === 0) return;
10076
- const { vtxos } = await chunkZIRFXBKL_cjs.getNormalizedVtxos(this.config.indexerProvider, {
10157
+ const { vtxos } = await chunkEJOFL5WH_cjs.getNormalizedVtxos(this.config.indexerProvider, {
10077
10158
  outpoints
10078
10159
  });
10079
10160
  if (vtxos.length === 0) return;
@@ -10152,7 +10233,7 @@ var ContractManager = class _ContractManager {
10152
10233
  break;
10153
10234
  }
10154
10235
  } catch (err) {
10155
- if (!chunkZIRFXBKL_cjs.isRetryableProviderError(err)) throw err;
10236
+ if (!chunkEJOFL5WH_cjs.isRetryableProviderError(err)) throw err;
10156
10237
  this.markSyncDegraded(err);
10157
10238
  }
10158
10239
  this.emitEvent(event);
@@ -10231,7 +10312,7 @@ var ContractManager = class _ContractManager {
10231
10312
  */
10232
10313
  async reconcilePendingFrontier(contracts) {
10233
10314
  const scriptToContract = new Map(contracts.map((c) => [c.script, c]));
10234
- const vtxos = await chunkZIRFXBKL_cjs.getAllNormalizedVtxos(
10315
+ const vtxos = await chunkEJOFL5WH_cjs.getAllNormalizedVtxos(
10235
10316
  this.config.indexerProvider,
10236
10317
  contracts.map((c) => c.script),
10237
10318
  { pendingOnly: true }
@@ -10314,7 +10395,7 @@ var ContractManager = class _ContractManager {
10314
10395
  }
10315
10396
  return result;
10316
10397
  }
10317
- async fetchContractVtxosBulk(contracts, pageSize = chunkZIRFXBKL_cjs.DEFAULT_PAGE_SIZE, syncWindow) {
10398
+ async fetchContractVtxosBulk(contracts, pageSize = chunkEJOFL5WH_cjs.DEFAULT_PAGE_SIZE, syncWindow) {
10318
10399
  if (contracts.length === 0) {
10319
10400
  return { vtxosByScript: /* @__PURE__ */ new Map(), promoted: /* @__PURE__ */ new Map() };
10320
10401
  }
@@ -10330,7 +10411,7 @@ var ContractManager = class _ContractManager {
10330
10411
  before: syncWindow.before
10331
10412
  }
10332
10413
  } : {};
10333
- const vtxos = await chunkZIRFXBKL_cjs.getAllNormalizedVtxos(
10414
+ const vtxos = await chunkEJOFL5WH_cjs.getAllNormalizedVtxos(
10334
10415
  this.config.indexerProvider,
10335
10416
  contracts.map((c) => c.script),
10336
10417
  { ...windowOpts, pageSize }
@@ -10475,7 +10556,7 @@ var deserializeTapLeaf = (t) => {
10475
10556
  const s = base.hex.decode(t.s);
10476
10557
  return [cb, s];
10477
10558
  };
10478
- var deserializeVtxo = (o) => chunkZIRFXBKL_cjs.normalizeVtxo({
10559
+ var deserializeVtxo = (o) => chunkEJOFL5WH_cjs.normalizeVtxo({
10479
10560
  ...o,
10480
10561
  createdAt: new Date(o.createdAt),
10481
10562
  tapTree: base.hex.decode(o.tapTree),
@@ -11298,7 +11379,7 @@ var HDDescriptorProvider = class _HDDescriptorProvider {
11298
11379
  */
11299
11380
  materializeDescriptorAt(index) {
11300
11381
  const descriptor = this.identity.descriptor;
11301
- const network = chunkPXPPZF5K_cjs.isMainnetDescriptor(descriptor) ? descriptorsScure.networks.bitcoin : descriptorsScure.networks.testnet;
11382
+ const network = chunk6YUACVX4_cjs.isMainnetDescriptor(descriptor) ? descriptorsScure.networks.bitcoin : descriptorsScure.networks.testnet;
11302
11383
  const expansion = descriptorsScure.expand({ descriptor, network, index });
11303
11384
  const keyInfo = expansion.expansionMap?.["@0"];
11304
11385
  if (!keyInfo?.keyExpression) {
@@ -11446,7 +11527,7 @@ var WalletReceiveRotator = class _WalletReceiveRotator {
11446
11527
  const provider = await resolveDescriptorProvider(config, setup.walletRepository);
11447
11528
  if (!provider) return void 0;
11448
11529
  const allowSilentFallback = (config.walletMode ?? "auto") === "auto";
11449
- const expectedContractType = setup.offchainTapscript instanceof chunkPXPPZF5K_cjs.DelegateVtxo.Script ? "delegate" : "default";
11530
+ const expectedContractType = setup.offchainTapscript instanceof chunk6YUACVX4_cjs.DelegateVtxo.Script ? "delegate" : "default";
11450
11531
  const factoryOpts = {
11451
11532
  walletRepository: setup.walletRepository,
11452
11533
  contractRepository: setup.contractRepository,
@@ -11626,7 +11707,9 @@ var WalletReceiveRotator = class _WalletReceiveRotator {
11626
11707
  const { tapscript: newTapscript, params } = buildReceiveContract(
11627
11708
  wallet.offchainTapscript,
11628
11709
  descriptor,
11629
- wallet.network.hrp);
11710
+ wallet.network.hrp,
11711
+ true
11712
+ );
11630
11713
  const newScript = params.script;
11631
11714
  const manager = await wallet.getContractManager();
11632
11715
  await manager.createContract(params);
@@ -11645,7 +11728,7 @@ var WalletReceiveRotator = class _WalletReceiveRotator {
11645
11728
  };
11646
11729
  function deriveLeafPubkey(descriptor) {
11647
11730
  try {
11648
- return chunkPXPPZF5K_cjs.deriveDescriptorLeafPubKey(descriptor);
11731
+ return chunk6YUACVX4_cjs.deriveDescriptorLeafPubKey(descriptor);
11649
11732
  } catch (e) {
11650
11733
  throw new NonRangeableDescriptorError(
11651
11734
  "Cannot derive leaf pubkey: descriptor is not a materialized, parsable tr(...) shape.",
@@ -11657,7 +11740,7 @@ function buildReceiveContract(current, descriptor, hrp, tagSource) {
11657
11740
  const pubKey = deriveLeafPubkey(descriptor);
11658
11741
  const tapscript = rebuildTapscript(current, pubKey);
11659
11742
  const serverPubKey = tapscript.options.serverPubKey;
11660
- const csvTimelock = chunkZIRFXBKL_cjs.timelockToSequence(tapscript.options.csvTimelock).toString();
11743
+ const csvTimelock = chunkEJOFL5WH_cjs.timelockToSequence(tapscript.options.csvTimelock).toString();
11661
11744
  const base$1 = {
11662
11745
  script: base.hex.encode(tapscript.pkScript),
11663
11746
  address: tapscript.address(hrp, serverPubKey).encode(),
@@ -11668,11 +11751,11 @@ function buildReceiveContract(current, descriptor, hrp, tagSource) {
11668
11751
  // index-0 key. Without it, spends produce unsigned PSBTs that the
11669
11752
  // server rejects with `INVALID_PSBT_INPUT (5): missing tapscript spend sig`.
11670
11753
  metadata: {
11671
- ...{ source: chunkPXPPZF5K_cjs.WALLET_RECEIVE_SOURCE },
11754
+ ...tagSource && { source: chunk6YUACVX4_cjs.WALLET_RECEIVE_SOURCE },
11672
11755
  signingDescriptor: descriptor
11673
11756
  }
11674
11757
  };
11675
- const params = tapscript instanceof chunkPXPPZF5K_cjs.DelegateVtxo.Script ? {
11758
+ const params = tapscript instanceof chunk6YUACVX4_cjs.DelegateVtxo.Script ? {
11676
11759
  ...base$1,
11677
11760
  type: "delegate",
11678
11761
  params: {
@@ -11693,10 +11776,10 @@ function buildReceiveContract(current, descriptor, hrp, tagSource) {
11693
11776
  return { tapscript, params };
11694
11777
  }
11695
11778
  function rebuildTapscript(current, pubKey) {
11696
- if (current instanceof chunkPXPPZF5K_cjs.DelegateVtxo.Script) {
11697
- return new chunkPXPPZF5K_cjs.DelegateVtxo.Script({ ...current.options, pubKey });
11779
+ if (current instanceof chunk6YUACVX4_cjs.DelegateVtxo.Script) {
11780
+ return new chunk6YUACVX4_cjs.DelegateVtxo.Script({ ...current.options, pubKey });
11698
11781
  }
11699
- return new chunkPXPPZF5K_cjs.DefaultVtxo.Script({ ...current.options, pubKey });
11782
+ return new chunk6YUACVX4_cjs.DefaultVtxo.Script({ ...current.options, pubKey });
11700
11783
  }
11701
11784
  async function pickActiveReceive(contractRepository, serverPubKey, expectedType) {
11702
11785
  const candidates = await contractRepository.getContracts({
@@ -11705,7 +11788,7 @@ async function pickActiveReceive(contractRepository, serverPubKey, expectedType)
11705
11788
  });
11706
11789
  const serverPubKeyHex = base.hex.encode(serverPubKey);
11707
11790
  const matching = candidates.filter(
11708
- (c) => c.params.serverPubKey === serverPubKeyHex && c.metadata?.source === chunkPXPPZF5K_cjs.WALLET_RECEIVE_SOURCE
11791
+ (c) => c.params.serverPubKey === serverPubKeyHex && c.metadata?.source === chunk6YUACVX4_cjs.WALLET_RECEIVE_SOURCE
11709
11792
  ).sort((a, b) => {
11710
11793
  if (b.createdAt !== a.createdAt) return b.createdAt - a.createdAt;
11711
11794
  return signingDescriptorIndex(b.metadata?.signingDescriptor) - signingDescriptorIndex(a.metadata?.signingDescriptor);
@@ -11752,6 +11835,7 @@ function computeOffchainBalance(vtxos, caps) {
11752
11835
  let intentLocked = 0;
11753
11836
  let recoverable = 0;
11754
11837
  let pendingRecovery = 0;
11838
+ let unrolled = 0;
11755
11839
  const owned = /* @__PURE__ */ new Map();
11756
11840
  const spendable = /* @__PURE__ */ new Map();
11757
11841
  const addAssets = (into, vtxo) => {
@@ -11760,17 +11844,21 @@ function computeOffchainBalance(vtxos, caps) {
11760
11844
  }
11761
11845
  };
11762
11846
  for (const vtxo of vtxos) {
11763
- if (chunkZIRFXBKL_cjs.hasTerminalSpend(vtxo)) continue;
11847
+ if (chunkEJOFL5WH_cjs.hasTerminalSpend(vtxo)) continue;
11764
11848
  addAssets(owned, vtxo);
11849
+ if (vtxo.isUnrolled) {
11850
+ unrolled += vtxo.value;
11851
+ continue;
11852
+ }
11765
11853
  if (isPendingRecovery(vtxo)) {
11766
11854
  pendingRecovery += vtxo.value;
11767
11855
  continue;
11768
11856
  }
11769
- if (chunkZIRFXBKL_cjs.canRecoverOnchain(vtxo, now)) {
11857
+ if (chunkEJOFL5WH_cjs.canRecoverOnchain(vtxo, now)) {
11770
11858
  recoverable += vtxo.value;
11771
11859
  continue;
11772
11860
  }
11773
- if (!chunkZIRFXBKL_cjs.canSpendOffchain(vtxo, now)) continue;
11861
+ if (!chunkEJOFL5WH_cjs.canSpendOffchain(vtxo, now)) continue;
11774
11862
  if (vtxo.isPreconfirmed) {
11775
11863
  preconfirmed += vtxo.value;
11776
11864
  } else {
@@ -11794,7 +11882,8 @@ function computeOffchainBalance(vtxos, caps) {
11794
11882
  intentLocked,
11795
11883
  recoverable,
11796
11884
  pendingRecovery,
11797
- total: settled + preconfirmed + recoverable + pendingRecovery,
11885
+ unrolled,
11886
+ total: settled + preconfirmed + recoverable + pendingRecovery + unrolled,
11798
11887
  assets: toAssets(owned),
11799
11888
  availableAssets: toAssets(spendable)
11800
11889
  };
@@ -11939,12 +12028,12 @@ var InputSignerRouter = class {
11939
12028
  };
11940
12029
 
11941
12030
  // src/wallet/wallet.ts
11942
- var getArkadeServerUrl = ({ arkServerUrl }) => arkServerUrl || chunkZIRFXBKL_cjs.DEFAULT_ARKADE_SERVER_URL;
12031
+ var getArkadeServerUrl = ({ arkServerUrl }) => arkServerUrl || chunkEJOFL5WH_cjs.DEFAULT_ARKADE_SERVER_URL;
11943
12032
  function intentProofJobs(coins) {
11944
12033
  if (coins.length === 0) return [];
11945
12034
  const coinJobs = coins.map((coin, i) => ({
11946
12035
  index: i + 1,
11947
- lookupScript: chunkZIRFXBKL_cjs.VtxoScript.decode(coin.tapTree).pkScript
12036
+ lookupScript: chunkEJOFL5WH_cjs.VtxoScript.decode(coin.tapTree).pkScript
11948
12037
  }));
11949
12038
  return [{ index: 0, lookupScript: coinJobs[0].lookupScript }, ...coinJobs];
11950
12039
  }
@@ -11976,7 +12065,7 @@ function dedupeTimelocks(timelocks) {
11976
12065
  const seen = /* @__PURE__ */ new Set();
11977
12066
  const deduped = [];
11978
12067
  for (const timelock of timelocks) {
11979
- const sequence = chunkZIRFXBKL_cjs.timelockToSequence(timelock).toString();
12068
+ const sequence = chunkEJOFL5WH_cjs.timelockToSequence(timelock).toString();
11980
12069
  if (seen.has(sequence)) continue;
11981
12070
  seen.add(sequence);
11982
12071
  deduped.push(timelock);
@@ -11993,7 +12082,7 @@ async function resolveBoardingBootTapscript(contractRepository, serverPubKey, ba
11993
12082
  state: "active"
11994
12083
  });
11995
12084
  const newest = candidates.filter(
11996
- (c) => c.params.serverPubKey === serverPubKeyHex && c.metadata?.source === chunkPXPPZF5K_cjs.WALLET_RECEIVE_SOURCE
12085
+ (c) => c.params.serverPubKey === serverPubKeyHex && c.metadata?.source === chunk6YUACVX4_cjs.WALLET_RECEIVE_SOURCE
11997
12086
  ).sort((a, b) => {
11998
12087
  if (b.createdAt !== a.createdAt) return b.createdAt - a.createdAt;
11999
12088
  return signingDescriptorIndex(b.metadata?.signingDescriptor) - signingDescriptorIndex(a.metadata?.signingDescriptor);
@@ -12001,7 +12090,7 @@ async function resolveBoardingBootTapscript(contractRepository, serverPubKey, ba
12001
12090
  if (!newest?.params.pubKey) return baseline;
12002
12091
  try {
12003
12092
  const pubKey = base.hex.decode(newest.params.pubKey);
12004
- return new chunkPXPPZF5K_cjs.DefaultVtxo.Script({ ...baseline.options, pubKey });
12093
+ return new chunk6YUACVX4_cjs.DefaultVtxo.Script({ ...baseline.options, pubKey });
12005
12094
  } catch (e) {
12006
12095
  console.warn("Skipping malformed boarding contract at boot", newest.script, e);
12007
12096
  return baseline;
@@ -12017,16 +12106,20 @@ function filterSnapshotVtxos(snapshot, filter, pendingSpendOutpoints) {
12017
12106
  if (pendingSpendOutpoints.has(`${vtxo.txid}:${vtxo.vout}`)) {
12018
12107
  return false;
12019
12108
  }
12020
- if (!chunkZIRFXBKL_cjs.hasTerminalSpend(vtxo)) {
12021
- if (!f.withRecoverable && chunkZIRFXBKL_cjs.canRecoverOnchain(vtxo, now)) {
12022
- return false;
12023
- }
12024
- return true;
12109
+ if (vtxo.isUnrolled) {
12110
+ return !!f.withUnrolled;
12111
+ }
12112
+ if (chunkEJOFL5WH_cjs.hasTerminalSpend(vtxo)) {
12113
+ return false;
12114
+ }
12115
+ if (!f.withRecoverable && chunkEJOFL5WH_cjs.canRecoverOnchain(vtxo, now)) {
12116
+ return false;
12025
12117
  }
12026
- return !!(f.withUnrolled && vtxo.isUnrolled);
12118
+ return true;
12027
12119
  });
12028
12120
  }
12029
12121
  var PENDING_RECOVERY_REASON = "is past its operator signer's rotation cutoff \u2014 the operator will not co-sign it until it recovers";
12122
+ var UNROLLED_REASON = "was unilaterally exited and lives onchain \u2014 `Unroll.completeUnroll` is the only spend that reaches it";
12030
12123
  function omittedOutpoints(before, after) {
12031
12124
  if (before.length === after.length) return /* @__PURE__ */ new Set();
12032
12125
  const kept = new Set(after.map((vtxo) => `${vtxo.txid}:${vtxo.vout}`));
@@ -12359,7 +12452,7 @@ var ReadonlyWallet = class _ReadonlyWallet {
12359
12452
  */
12360
12453
  static async setupWalletConfig(config, pubKey) {
12361
12454
  const arkadeServerUrl = getArkadeServerUrl(config);
12362
- const arkProvider = config.arkProvider || new chunkZIRFXBKL_cjs.RestArkProvider(arkadeServerUrl);
12455
+ const arkProvider = config.arkProvider || new chunkEJOFL5WH_cjs.RestArkProvider(arkadeServerUrl);
12363
12456
  let indexerProvider = config.indexerProvider;
12364
12457
  if (!indexerProvider) {
12365
12458
  let indexerUrl = config.indexerUrl;
@@ -12376,7 +12469,7 @@ var ReadonlyWallet = class _ReadonlyWallet {
12376
12469
  indexerUrl = arkadeServerUrl;
12377
12470
  }
12378
12471
  }
12379
- indexerProvider = new chunk3S3JZUEN_cjs.RestIndexerProvider(indexerUrl);
12472
+ indexerProvider = new chunkPJR63FTK_cjs.RestIndexerProvider(indexerUrl);
12380
12473
  }
12381
12474
  const walletRepository = config.storage?.walletRepository ?? new IndexedDBWalletRepository();
12382
12475
  const contractRepository = config.storage?.contractRepository ?? new IndexedDBContractRepository();
@@ -12385,7 +12478,7 @@ var ReadonlyWallet = class _ReadonlyWallet {
12385
12478
  source: serverInfoSource,
12386
12479
  lastOnlineAt: serverInfoLastOnlineAt
12387
12480
  } = await resolveArkInfo(arkProvider, walletRepository);
12388
- const network = chunkZIRFXBKL_cjs.getNetwork(info.network);
12481
+ const network = chunkEJOFL5WH_cjs.getNetwork(info.network);
12389
12482
  if ("descriptor" in config.identity) {
12390
12483
  const descriptor = config.identity.descriptor;
12391
12484
  const identityIsMainnet = !descriptor.includes("tpub");
@@ -12425,18 +12518,18 @@ var ReadonlyWallet = class _ReadonlyWallet {
12425
12518
  value: info.boardingExitDelay,
12426
12519
  type: info.boardingExitDelay < 512n ? "blocks" : "seconds"
12427
12520
  };
12428
- const serverPubKey = chunkPXPPZF5K_cjs.toXOnly(base.hex.decode(info.signerPubkey), "ark signer key");
12429
- const delegatePubKey = config.delegateProvider ? await config.delegateProvider.getDelegateInfo().then((info2) => chunkPXPPZF5K_cjs.toXOnly(base.hex.decode(info2.pubkey), "delegate key")).catch(() => void 0) : config.delegatorProvider ? await config.delegatorProvider.getDelegateInfo().then((info2) => chunkPXPPZF5K_cjs.toXOnly(base.hex.decode(info2.pubkey), "delegate key")).catch(() => void 0) : void 0;
12521
+ const serverPubKey = chunk6YUACVX4_cjs.toXOnly(base.hex.decode(info.signerPubkey), "ark signer key");
12522
+ const delegatePubKey = config.delegateProvider ? await config.delegateProvider.getDelegateInfo().then((info2) => chunk6YUACVX4_cjs.toXOnly(base.hex.decode(info2.pubkey), "delegate key")).catch(() => void 0) : config.delegatorProvider ? await config.delegatorProvider.getDelegateInfo().then((info2) => chunk6YUACVX4_cjs.toXOnly(base.hex.decode(info2.pubkey), "delegate key")).catch(() => void 0) : void 0;
12430
12523
  const offchainOptions = {
12431
12524
  pubKey,
12432
12525
  serverPubKey,
12433
12526
  csvTimelock: exitTimelock
12434
12527
  };
12435
- const offchainTapscript = !delegatePubKey ? new chunkPXPPZF5K_cjs.DefaultVtxo.Script(offchainOptions) : new chunkPXPPZF5K_cjs.DelegateVtxo.Script({ ...offchainOptions, delegatePubKey });
12436
- const boardingTapscript = chunkPXPPZF5K_cjs.BoardingContractHandler.createScript({
12528
+ const offchainTapscript = !delegatePubKey ? new chunk6YUACVX4_cjs.DefaultVtxo.Script(offchainOptions) : new chunk6YUACVX4_cjs.DelegateVtxo.Script({ ...offchainOptions, delegatePubKey });
12529
+ const boardingTapscript = chunk6YUACVX4_cjs.BoardingContractHandler.createScript({
12437
12530
  pubKey: base.hex.encode(pubKey),
12438
12531
  serverPubKey: base.hex.encode(serverPubKey),
12439
- csvTimelock: chunkZIRFXBKL_cjs.timelockToSequence(boardingTimelock).toString()
12532
+ csvTimelock: chunkEJOFL5WH_cjs.timelockToSequence(boardingTimelock).toString()
12440
12533
  });
12441
12534
  return {
12442
12535
  arkProvider,
@@ -12526,7 +12619,11 @@ var ReadonlyWallet = class _ReadonlyWallet {
12526
12619
  this.getBoardingUtxos(),
12527
12620
  this.contractSnapshot()
12528
12621
  ]);
12529
- const vtxos = filterSnapshotVtxos(snapshot, void 0, this._pendingSpendOutpoints);
12622
+ const vtxos = filterSnapshotVtxos(
12623
+ snapshot,
12624
+ { withRecoverable: true, withUnrolled: true },
12625
+ this._pendingSpendOutpoints
12626
+ );
12530
12627
  let confirmed = 0;
12531
12628
  let unconfirmed = 0;
12532
12629
  for (const utxo of boardingUtxos) {
@@ -12554,6 +12651,7 @@ var ReadonlyWallet = class _ReadonlyWallet {
12554
12651
  intentLocked: offchain.intentLocked,
12555
12652
  recoverable: offchain.recoverable,
12556
12653
  pendingRecovery: offchain.pendingRecovery,
12654
+ unrolled: offchain.unrolled,
12557
12655
  total: totalBoarding + offchain.total,
12558
12656
  assets: offchain.assets,
12559
12657
  availableAssets: offchain.availableAssets
@@ -12594,6 +12692,13 @@ var ReadonlyWallet = class _ReadonlyWallet {
12594
12692
  "is locked by an in-flight settlement intent"
12595
12693
  )
12596
12694
  ]);
12695
+ if (!filter?.withUnrolled) {
12696
+ logExcludedVtxos(
12697
+ "getSpendableVtxos",
12698
+ snapshot.flatMap((contract) => contract.vtxos).filter((vtxo) => vtxo.isUnrolled && !chunkEJOFL5WH_cjs.hasTerminalSpend(vtxo)),
12699
+ [() => UNROLLED_REASON]
12700
+ );
12701
+ }
12597
12702
  return unlocked;
12598
12703
  }
12599
12704
  /**
@@ -12733,7 +12838,7 @@ var ReadonlyWallet = class _ReadonlyWallet {
12733
12838
  const response = await contractManager.getContractsWithVtxos();
12734
12839
  const allVtxos = response.flatMap((_) => _.vtxos);
12735
12840
  const { boardingTxs, commitmentsToIgnore } = await this.getBoardingTxs();
12736
- const resolveTxCreatedAt = (txids) => chunkZIRFXBKL_cjs.fetchVtxoCreatedAtByTxid(this.indexerProvider, txids);
12841
+ const resolveTxCreatedAt = (txids) => chunkEJOFL5WH_cjs.fetchVtxoCreatedAtByTxid(this.indexerProvider, txids);
12737
12842
  return buildTransactionHistory(
12738
12843
  allVtxos,
12739
12844
  boardingTxs,
@@ -12827,7 +12932,7 @@ var ReadonlyWallet = class _ReadonlyWallet {
12827
12932
  },
12828
12933
  isUnrolled: true,
12829
12934
  ...boardingFacts,
12830
- virtualStatus: chunkZIRFXBKL_cjs.toVirtualStatus(boardingFacts),
12935
+ virtualStatus: chunkEJOFL5WH_cjs.toVirtualStatus(boardingFacts),
12831
12936
  spentBy: "",
12832
12937
  createdAt: tx.status.confirmed ? new Date(tx.status.block_time * 1e3) : /* @__PURE__ */ new Date(0),
12833
12938
  script: scriptHex
@@ -12883,9 +12988,9 @@ var ReadonlyWallet = class _ReadonlyWallet {
12883
12988
  async getBoardingTapscripts(allowedSigners) {
12884
12989
  const byScript = /* @__PURE__ */ new Map();
12885
12990
  const add = (s) => byScript.set(base.hex.encode(s.pkScript), s);
12886
- const boardingCsv = this.boardingTapscript.options.csvTimelock ?? chunkPXPPZF5K_cjs.DefaultVtxo.Script.DEFAULT_TIMELOCK;
12991
+ const boardingCsv = this.boardingTapscript.options.csvTimelock ?? chunk6YUACVX4_cjs.DefaultVtxo.Script.DEFAULT_TIMELOCK;
12887
12992
  add(
12888
- new chunkPXPPZF5K_cjs.DefaultVtxo.Script({
12993
+ new chunk6YUACVX4_cjs.DefaultVtxo.Script({
12889
12994
  pubKey: await this.identity.xOnlyPublicKey(),
12890
12995
  serverPubKey: this.boardingTapscript.options.serverPubKey,
12891
12996
  csvTimelock: boardingCsv
@@ -12900,7 +13005,7 @@ var ReadonlyWallet = class _ReadonlyWallet {
12900
13005
  for (const c of boardingContracts) {
12901
13006
  if (!allowed.has(toXOnlySignerHex(c.params.serverPubKey))) continue;
12902
13007
  try {
12903
- add(chunkPXPPZF5K_cjs.BoardingContractHandler.createScript(c.params));
13008
+ add(chunk6YUACVX4_cjs.BoardingContractHandler.createScript(c.params));
12904
13009
  } catch (e) {
12905
13010
  console.warn("Skipping malformed boarding contract", c.script, e);
12906
13011
  }
@@ -12938,7 +13043,7 @@ var ReadonlyWallet = class _ReadonlyWallet {
12938
13043
  // Per-row CSV delay decoded from THIS tapscript's exit leaf —
12939
13044
  // not the wallet's current boarding timelock, which a signer
12940
13045
  // rotation may have changed.
12941
- csvTimelock: chunkZIRFXBKL_cjs.CSVMultisigTapscript.decode(base.hex.decode(tapscript.exitScript)).params.timelock,
13046
+ csvTimelock: chunkEJOFL5WH_cjs.CSVMultisigTapscript.decode(base.hex.decode(tapscript.exitScript)).params.timelock,
12942
13047
  coins: utxos
12943
13048
  });
12944
13049
  }
@@ -13071,7 +13176,7 @@ var ReadonlyWallet = class _ReadonlyWallet {
13071
13176
  /** Fetch Arkade transaction ids that are still pending final settlement. */
13072
13177
  async fetchPendingTxs() {
13073
13178
  const scripts = await this.getWalletScripts();
13074
- const vtxos = await chunkZIRFXBKL_cjs.getAllNormalizedVtxos(this.indexerProvider, scripts);
13179
+ const vtxos = await chunkEJOFL5WH_cjs.getAllNormalizedVtxos(this.indexerProvider, scripts);
13075
13180
  return vtxos.filter(
13076
13181
  (vtxo) => (vtxo.isSpent || vtxo.isPreconfirmed && !vtxo.isSwept) && vtxo.arkTxId !== void 0
13077
13182
  ).map((_) => _.arkTxId);
@@ -13102,7 +13207,7 @@ var ReadonlyWallet = class _ReadonlyWallet {
13102
13207
  });
13103
13208
  for (const contract of contracts) {
13104
13209
  if (map.has(contract.script)) continue;
13105
- const handler = chunkPXPPZF5K_cjs.contractHandlers.get(contract.type);
13210
+ const handler = chunk6YUACVX4_cjs.contractHandlers.get(contract.type);
13106
13211
  if (handler) {
13107
13212
  const script = handler.createScript(contract.params);
13108
13213
  map.set(contract.script, script);
@@ -13214,7 +13319,7 @@ var ReadonlyWallet = class _ReadonlyWallet {
13214
13319
  }
13215
13320
  });
13216
13321
  const baselinePubkey = await this.identity.xOnlyPublicKey();
13217
- const delegatePubKey = this.offchainTapscript instanceof chunkPXPPZF5K_cjs.DelegateVtxo.Script ? this.offchainTapscript.options.delegatePubKey : void 0;
13322
+ const delegatePubKey = this.offchainTapscript instanceof chunk6YUACVX4_cjs.DelegateVtxo.Script ? this.offchainTapscript.options.delegatePubKey : void 0;
13218
13323
  const baselineSigners = [
13219
13324
  this.offchainTapscript.options.serverPubKey,
13220
13325
  ...[...this._deprecatedSigners.keys()].map((h) => base.hex.decode(h))
@@ -13222,8 +13327,8 @@ var ReadonlyWallet = class _ReadonlyWallet {
13222
13327
  const seenBaselineScripts = /* @__PURE__ */ new Set();
13223
13328
  for (const serverPubKey of baselineSigners) {
13224
13329
  for (const csvTimelock of this.walletContractTimelocks) {
13225
- const csvTimelockStr = chunkZIRFXBKL_cjs.timelockToSequence(csvTimelock).toString();
13226
- const defaultScript = new chunkPXPPZF5K_cjs.DefaultVtxo.Script({
13330
+ const csvTimelockStr = chunkEJOFL5WH_cjs.timelockToSequence(csvTimelock).toString();
13331
+ const defaultScript = new chunk6YUACVX4_cjs.DefaultVtxo.Script({
13227
13332
  pubKey: baselinePubkey,
13228
13333
  serverPubKey,
13229
13334
  csvTimelock
@@ -13244,7 +13349,7 @@ var ReadonlyWallet = class _ReadonlyWallet {
13244
13349
  });
13245
13350
  }
13246
13351
  if (delegatePubKey) {
13247
- const delegateScript = new chunkPXPPZF5K_cjs.DelegateVtxo.Script({
13352
+ const delegateScript = new chunk6YUACVX4_cjs.DelegateVtxo.Script({
13248
13353
  pubKey: baselinePubkey,
13249
13354
  serverPubKey,
13250
13355
  delegatePubKey,
@@ -13268,9 +13373,9 @@ var ReadonlyWallet = class _ReadonlyWallet {
13268
13373
  }
13269
13374
  }
13270
13375
  }
13271
- const boardingCsvTimelock = this.boardingTapscript.options.csvTimelock ?? chunkPXPPZF5K_cjs.DefaultVtxo.Script.DEFAULT_TIMELOCK;
13376
+ const boardingCsvTimelock = this.boardingTapscript.options.csvTimelock ?? chunk6YUACVX4_cjs.DefaultVtxo.Script.DEFAULT_TIMELOCK;
13272
13377
  for (const serverPubKey of baselineSigners) {
13273
- const baselineBoarding = new chunkPXPPZF5K_cjs.DefaultVtxo.Script({
13378
+ const baselineBoarding = new chunk6YUACVX4_cjs.DefaultVtxo.Script({
13274
13379
  pubKey: baselinePubkey,
13275
13380
  serverPubKey,
13276
13381
  csvTimelock: boardingCsvTimelock
@@ -13283,7 +13388,7 @@ var ReadonlyWallet = class _ReadonlyWallet {
13283
13388
  params: {
13284
13389
  pubKey: base.hex.encode(baselineBoarding.options.pubKey),
13285
13390
  serverPubKey: base.hex.encode(serverPubKey),
13286
- csvTimelock: chunkZIRFXBKL_cjs.timelockToSequence(boardingCsvTimelock).toString()
13391
+ csvTimelock: chunkEJOFL5WH_cjs.timelockToSequence(boardingCsvTimelock).toString()
13287
13392
  },
13288
13393
  script: boardingScriptHex,
13289
13394
  address: baselineBoarding.address(this.network.hrp, serverPubKey).encode(),
@@ -13413,6 +13518,27 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
13413
13518
  console.warn("server-signer rotation on info change failed", e);
13414
13519
  }
13415
13520
  }
13521
+ /**
13522
+ * Await an `onServerInfoChanged` handler still applying a rotation.
13523
+ *
13524
+ * The provider emits synchronously but {@link handleServerInfoChanged} runs
13525
+ * off the emit, so between the two a caller can observe a half-applied
13526
+ * rotation: {@link rotateServerSigner} persists the active signer's contract
13527
+ * rows *before* committing the tapscripts, so `arkServerPublicKey` still
13528
+ * reads the old key while the new key's rows are already in the repository.
13529
+ * A path that refreshes server info and then reads signer-derived state must
13530
+ * drain the chain first, or it both reads that torn state and races the
13531
+ * handler for the rotation itself.
13532
+ *
13533
+ * Resolves once the chain is idle; a handler that threw already logged, and
13534
+ * its rejection is swallowed here.
13535
+ *
13536
+ * @internal Invoked by {@link dispose} and the {@link VtxoManager} migration
13537
+ * pass; not part of the stable public API.
13538
+ */
13539
+ async settleServerInfoChanges() {
13540
+ await this._serverInfoInFlight?.catch(() => void 0);
13541
+ }
13416
13542
  _receiveRotatorInstalled = false;
13417
13543
  /**
13418
13544
  * Descriptor-aware signer used by {@link _signerRouter} to sign
@@ -13462,7 +13588,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
13462
13588
  serverPubKey: this.offchainTapscript.options.serverPubKey,
13463
13589
  deprecatedSignerPubKeys: [...this._deprecatedSigners.keys()].map((h) => base.hex.decode(h)),
13464
13590
  csvTimelocks: this.walletContractTimelocks,
13465
- delegatePubKey: this.offchainTapscript instanceof chunkPXPPZF5K_cjs.DelegateVtxo.Script ? this.offchainTapscript.options.delegatePubKey : void 0
13591
+ delegatePubKey: this.offchainTapscript instanceof chunk6YUACVX4_cjs.DelegateVtxo.Script ? this.offchainTapscript.options.delegatePubKey : void 0
13466
13592
  };
13467
13593
  }
13468
13594
  _signerRouter;
@@ -13547,43 +13673,250 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
13547
13673
  * provider and keeps a single index-0 boarding address for its lifetime,
13548
13674
  * so this returns the existing {@link getBoardingAddress} unchanged
13549
13675
  * (no rotation, no index burned).
13676
+ *
13677
+ * **Behaviour change.** A wallet configured with a custom
13678
+ * {@link DescriptorProvider} (`walletMode: <provider>`) now rotates here.
13679
+ * It previously did not: allocation went through the contract manager,
13680
+ * which only wires an `allocate` hook for {@link HDDescriptorProvider}, so
13681
+ * such a wallet read as "declined to allocate" and silently kept its
13682
+ * index-0 boarding address forever. Those wallets now burn an index per
13683
+ * call — including via {@link maybeRotateBoardingAfterBoard}, which fires
13684
+ * on every settle that consumes a boarding UTXO. Funds at retired
13685
+ * addresses stay reachable: each rotation persists its `boarding` contract
13686
+ * before swapping, and {@link getBoardingUtxos} fans out over the full
13687
+ * historical set.
13688
+ *
13689
+ * @deprecated Use {@link getNewAddresses} — it mints any combination of
13690
+ * address types at one shared index, and reports the contract row behind
13691
+ * each. Note the difference in display behaviour: this method *swaps* the
13692
+ * advertised boarding address, where `getNewAddresses` mints side
13693
+ * addresses and leaves {@link getBoardingAddress} alone. To keep this
13694
+ * method's behaviour, keep calling this method.
13550
13695
  */
13551
13696
  async getNewBoardingAddress() {
13552
- const provider = this._descriptorProvider;
13553
- if (!provider) {
13554
- return this.getBoardingAddress();
13697
+ const [minted] = await this.allocateAddresses(["boarding"], false, true);
13698
+ if (!minted?.allocated) return this.getBoardingAddress();
13699
+ if (minted.type === "boarding") this.setBoardingTapscriptForRotation(minted.tapscript);
13700
+ return minted.address;
13701
+ }
13702
+ /**
13703
+ * Allocate a *fresh* address of each requested type, all derived from one
13704
+ * newly allocated HD index.
13705
+ *
13706
+ * This is the explicit allocator the receive path otherwise lacks:
13707
+ * {@link getAddress} and {@link getBoardingAddress} are stable reads of the
13708
+ * wallet's display addresses, and the display receive address only advances
13709
+ * when a payment arrives ({@link WalletReceiveRotator} rotates on
13710
+ * `vtxo_received`). Issuing a second address before the first is paid — one
13711
+ * invoice for Alice, another for Bob — has to go through here.
13712
+ *
13713
+ * Each call:
13714
+ *
13715
+ * - allocates **one** index from the shared HD stream, however many types
13716
+ * were asked for, so a `default` + `boarding` pair are siblings rather
13717
+ * than two burnt indices;
13718
+ * - builds each requested script at that index, preserving every other
13719
+ * option of the wallet's current script for that flavour (including a
13720
+ * delegate wallet's `delegate` shape);
13721
+ * - persists each as an `active` contract carrying its `signingDescriptor`,
13722
+ * so the ContractWatcher monitors it, the balance counts it, and
13723
+ * {@link signerForDescriptor} can recover the key;
13724
+ * - slides the look-ahead band, since the watermark moved past indices an
13725
+ * external issuer may still be handing out.
13726
+ *
13727
+ * The minted rows are deliberately left **untagged**: the boot lookups
13728
+ * adopt the newest {@link WALLET_RECEIVE_SOURCE}-tagged row as the display
13729
+ * address, and a side address issued to one counterparty must not become
13730
+ * the address the wallet advertises to everyone else. {@link getAddress}
13731
+ * and {@link getBoardingAddress} are unchanged by this call.
13732
+ *
13733
+ * A wallet with no HD stream (`walletMode: 'static'` / `'auto'`) has one
13734
+ * address per flavour for its lifetime. Without `forceNew` it returns those
13735
+ * — the real persisted rows, no index burned; with `forceNew` it throws
13736
+ * {@link WalletCannotAllocateAddressError} rather than hand back an address
13737
+ * that is not in fact fresh.
13738
+ *
13739
+ * @example
13740
+ * ```typescript
13741
+ * const [invoice] = await wallet.getNewAddresses({ forceNew: true });
13742
+ * // hand `invoice.address` to Alice, keep the descriptor with the invoice
13743
+ * const signer = await wallet.signerForDescriptor(invoice.signingDescriptor);
13744
+ * ```
13745
+ */
13746
+ async getNewAddresses(opts) {
13747
+ const minted = await this.allocateAddresses(
13748
+ opts?.types ?? ["default"],
13749
+ opts?.forceNew ?? false,
13750
+ false
13751
+ );
13752
+ return minted.map(({ address, signingDescriptor, contract }) => ({
13753
+ address,
13754
+ signingDescriptor,
13755
+ contract
13756
+ }));
13757
+ }
13758
+ /**
13759
+ * Shared allocation core behind {@link getNewAddresses} and the deprecated
13760
+ * {@link getNewBoardingAddress}, so the two cannot drift on what an
13761
+ * allocation costs or what gets persisted.
13762
+ *
13763
+ * @param tagSource - Tag the persisted rows {@link WALLET_RECEIVE_SOURCE},
13764
+ * making the next boot adopt them as the display address. Only the
13765
+ * deprecated boarding allocator passes `true`; `getNewAddresses` mints side
13766
+ * addresses and must not hijack what the wallet advertises.
13767
+ */
13768
+ async allocateAddresses(types, forceNew, tagSource) {
13769
+ if (types.length === 0) {
13770
+ throw new Error("getNewAddresses: `types` must name at least one address type");
13555
13771
  }
13556
13772
  const manager = await this.getContractManager();
13557
- const descriptor = await manager.getNextSigningDescriptor();
13558
- if (!descriptor) return this.getBoardingAddress();
13559
- const pubKey = chunkPXPPZF5K_cjs.deriveDescriptorLeafPubKey(descriptor);
13560
- const newBoarding = new chunkPXPPZF5K_cjs.DefaultVtxo.Script({
13773
+ const provider = this._descriptorProvider;
13774
+ const descriptor = !provider ? void 0 : provider instanceof HDDescriptorProvider ? await manager.getNextSigningDescriptor() : await provider.getNextSigningDescriptor();
13775
+ if (!descriptor) {
13776
+ if (forceNew) {
13777
+ throw new WalletCannotAllocateAddressError(
13778
+ provider ? "the descriptor provider declined to allocate an index" : "this wallet has no HD stream (walletMode 'static' / 'auto')"
13779
+ );
13780
+ }
13781
+ return this.currentAddresses(manager, types);
13782
+ }
13783
+ const allocated = [];
13784
+ try {
13785
+ for (const type of types) {
13786
+ allocated.push(await this.mintAddress(manager, type, descriptor, tagSource, true));
13787
+ }
13788
+ } finally {
13789
+ try {
13790
+ await manager.refillLookAhead();
13791
+ } catch (e) {
13792
+ console.warn("look-ahead refill after address allocation failed", e);
13793
+ }
13794
+ }
13795
+ return allocated;
13796
+ }
13797
+ /**
13798
+ * The wallet's existing display addresses, as persisted contract rows —
13799
+ * the honest answer for a wallet with no index to burn.
13800
+ *
13801
+ * Each type is minted from the descriptor that already owns its display
13802
+ * script ({@link displayDescriptor}), not from the identity key, so the
13803
+ * returned `signingDescriptor` is the one that signs for the returned
13804
+ * `address` even on a wallet that has rotated.
13805
+ */
13806
+ async currentAddresses(manager, types) {
13807
+ const out = [];
13808
+ for (const type of types) {
13809
+ const descriptor = await this.displayDescriptor(manager, type);
13810
+ out.push(await this.mintAddress(manager, type, descriptor, false, false));
13811
+ }
13812
+ return out;
13813
+ }
13814
+ /**
13815
+ * The descriptor that owns the wallet's current display script for `type`,
13816
+ * read off the row the wallet persisted when it adopted that script.
13817
+ *
13818
+ * Deriving it from the identity instead is only correct for a wallet that
13819
+ * never rotates. On one that has — an HD wallet whose provider later
13820
+ * declines to allocate — the display script belongs to an HD child, and
13821
+ * pairing its address with the identity descriptor hands the caller a
13822
+ * {@link NewAddress} whose `signingDescriptor` resolves, via
13823
+ * {@link signerForDescriptor}, to a signer holding the wrong key.
13824
+ *
13825
+ * Falls back to the identity's pathless `tr(pubkey)` when no row carries a
13826
+ * descriptor: the static / `auto` case, where the identity key genuinely
13827
+ * owns the display script and this is what `getNextSigningDescriptor`
13828
+ * answers too. (The index-0 baselines registered at construction carry no
13829
+ * `signingDescriptor` metadata, so those wallets take this path.)
13830
+ */
13831
+ async displayDescriptor(manager, type) {
13832
+ const display = type === "boarding" ? this._boardingTapscript : this.offchainTapscript;
13833
+ const [row] = await manager.getContracts({ script: base.hex.encode(display.pkScript) });
13834
+ const persisted = row?.metadata?.signingDescriptor;
13835
+ if (typeof persisted === "string") return persisted;
13836
+ return chunk6YUACVX4_cjs.identityDescriptor(this.identity);
13837
+ }
13838
+ /**
13839
+ * Build, persist and shape one address of `type` owned by `descriptor` —
13840
+ * the single build-and-register path behind both {@link allocateAddresses}
13841
+ * and {@link currentAddresses}, so a freshly allocated address and a
13842
+ * re-registered display address cannot disagree on what gets written.
13843
+ *
13844
+ * The descriptor is the sole source of the script's owner key in both
13845
+ * branches. Deriving one flavour from the descriptor and the other from a
13846
+ * tapscript field is what lets `address` and `signingDescriptor` drift
13847
+ * apart.
13848
+ */
13849
+ async mintAddress(manager, type, descriptor, tagSource, allocated) {
13850
+ if (type === "boarding") {
13851
+ const built2 = this.buildBoardingContract(
13852
+ chunk6YUACVX4_cjs.deriveDescriptorLeafPubKey(descriptor),
13853
+ descriptor,
13854
+ tagSource
13855
+ );
13856
+ const contract2 = await manager.createContract(built2.params);
13857
+ return {
13858
+ type,
13859
+ // `built.tapscript` is a `DefaultVtxo.Script` here without a
13860
+ // cast — the branch, not a widened local, does the narrowing.
13861
+ tapscript: built2.tapscript,
13862
+ // A boarding row persists the *ark* encoding of its script, so
13863
+ // `contract.address` is unusable for an onchain sender: the
13864
+ // onchain form has to be re-derived.
13865
+ address: built2.tapscript.onchainAddress(this.network),
13866
+ signingDescriptor: descriptor,
13867
+ contract: contract2,
13868
+ allocated
13869
+ };
13870
+ }
13871
+ const built = buildReceiveContract(
13872
+ this.offchainTapscript,
13873
+ descriptor,
13874
+ this.network.hrp,
13875
+ tagSource
13876
+ );
13877
+ const contract = await manager.createContract(built.params);
13878
+ return {
13879
+ type,
13880
+ tapscript: built.tapscript,
13881
+ // Offchain rows already store the address they advertise, and
13882
+ // reading it back keeps a coalesced row (`createContract` is
13883
+ // first-wins on script) honest about what was actually persisted.
13884
+ address: contract.address,
13885
+ signingDescriptor: descriptor,
13886
+ contract,
13887
+ allocated
13888
+ };
13889
+ }
13890
+ /**
13891
+ * Build the boarding contract owned by `pubKey`, keeping every other option
13892
+ * of the wallet's current boarding tapscript (notably the boarding-exit
13893
+ * CSV, which is index-independent). The offchain analogue lives in
13894
+ * {@link buildReceiveContract}.
13895
+ */
13896
+ buildBoardingContract(pubKey, descriptor, tagSource) {
13897
+ const tapscript = new chunk6YUACVX4_cjs.DefaultVtxo.Script({
13561
13898
  ...this._boardingTapscript.options,
13562
13899
  pubKey
13563
13900
  });
13564
- const csvTimelock = newBoarding.options.csvTimelock ?? chunkPXPPZF5K_cjs.DefaultVtxo.Script.DEFAULT_TIMELOCK;
13565
- await manager.createContract({
13566
- type: "boarding",
13901
+ const csvTimelock = tapscript.options.csvTimelock ?? chunk6YUACVX4_cjs.DefaultVtxo.Script.DEFAULT_TIMELOCK;
13902
+ return {
13903
+ tapscript,
13567
13904
  params: {
13568
- pubKey: base.hex.encode(pubKey),
13569
- serverPubKey: base.hex.encode(newBoarding.options.serverPubKey),
13570
- csvTimelock: chunkZIRFXBKL_cjs.timelockToSequence(csvTimelock).toString()
13571
- },
13572
- script: base.hex.encode(newBoarding.pkScript),
13573
- address: newBoarding.address(this.network.hrp, this.arkServerPublicKey).encode(),
13574
- state: "active",
13575
- metadata: {
13576
- source: chunkPXPPZF5K_cjs.WALLET_RECEIVE_SOURCE,
13577
- signingDescriptor: descriptor
13905
+ type: "boarding",
13906
+ params: {
13907
+ pubKey: base.hex.encode(pubKey),
13908
+ serverPubKey: base.hex.encode(tapscript.options.serverPubKey),
13909
+ csvTimelock: chunkEJOFL5WH_cjs.timelockToSequence(csvTimelock).toString()
13910
+ },
13911
+ script: base.hex.encode(tapscript.pkScript),
13912
+ address: tapscript.address(this.network.hrp, this.arkServerPublicKey).encode(),
13913
+ state: "active",
13914
+ metadata: {
13915
+ ...tagSource && { source: chunk6YUACVX4_cjs.WALLET_RECEIVE_SOURCE },
13916
+ signingDescriptor: descriptor
13917
+ }
13578
13918
  }
13579
- });
13580
- this.setBoardingTapscriptForRotation(newBoarding);
13581
- try {
13582
- await manager.refillLookAhead();
13583
- } catch (e) {
13584
- console.warn("look-ahead refill after boarding allocation failed", e);
13585
- }
13586
- return newBoarding.onchainAddress(this.network);
13919
+ };
13587
13920
  }
13588
13921
  /**
13589
13922
  * @see HDWalletCapable.getCurrentSigningDescriptor
@@ -13608,7 +13941,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
13608
13941
  if (this._descriptorProvider instanceof HDDescriptorProvider) {
13609
13942
  return (await this.getContractManager()).getNextSigningDescriptor();
13610
13943
  }
13611
- return chunkPXPPZF5K_cjs.identityDescriptor(this.identity);
13944
+ return chunk6YUACVX4_cjs.identityDescriptor(this.identity);
13612
13945
  }
13613
13946
  /**
13614
13947
  * @see HDAllocationCapable.advanceSigningDescriptorWatermark
@@ -13704,7 +14037,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
13704
14037
  * the stable public API.
13705
14038
  */
13706
14039
  async rotateServerSigner(newServerPubKey, checkpointTapscript) {
13707
- const xonly = chunkPXPPZF5K_cjs.toXOnly(newServerPubKey, "ark signer key");
14040
+ const xonly = chunk6YUACVX4_cjs.toXOnly(newServerPubKey, "ark signer key");
13708
14041
  const newServerUnrollScript = assertValidServerUnrollScript(
13709
14042
  checkpointTapscript,
13710
14043
  resolveCheckpointExitDelayPolicy(this.network, this.checkpointExitDelayPolicy)
@@ -13733,21 +14066,21 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
13733
14066
  const [currentBoardingRow] = await manager.getContracts({
13734
14067
  script: currentBoardingScript
13735
14068
  });
13736
- const newOffchain = this.offchainTapscript instanceof chunkPXPPZF5K_cjs.DelegateVtxo.Script ? new chunkPXPPZF5K_cjs.DelegateVtxo.Script({
14069
+ const newOffchain = this.offchainTapscript instanceof chunk6YUACVX4_cjs.DelegateVtxo.Script ? new chunk6YUACVX4_cjs.DelegateVtxo.Script({
13737
14070
  ...this.offchainTapscript.options,
13738
14071
  serverPubKey: xonly
13739
- }) : new chunkPXPPZF5K_cjs.DefaultVtxo.Script({
14072
+ }) : new chunk6YUACVX4_cjs.DefaultVtxo.Script({
13740
14073
  ...this.offchainTapscript.options,
13741
14074
  serverPubKey: xonly
13742
14075
  });
13743
- const newBoarding = new chunkPXPPZF5K_cjs.DefaultVtxo.Script({
14076
+ const newBoarding = new chunk6YUACVX4_cjs.DefaultVtxo.Script({
13744
14077
  ...this._boardingTapscript.options,
13745
14078
  serverPubKey: xonly
13746
14079
  });
13747
- const offchainCsv = chunkZIRFXBKL_cjs.timelockToSequence(newOffchain.options.csvTimelock).toString();
14080
+ const offchainCsv = chunkEJOFL5WH_cjs.timelockToSequence(newOffchain.options.csvTimelock).toString();
13748
14081
  const newOffchainScript = base.hex.encode(newOffchain.pkScript);
13749
14082
  const newOffchainAddress = newOffchain.address(this.network.hrp, xonly).encode();
13750
- if (newOffchain instanceof chunkPXPPZF5K_cjs.DelegateVtxo.Script) {
14083
+ if (newOffchain instanceof chunk6YUACVX4_cjs.DelegateVtxo.Script) {
13751
14084
  await manager.createContract({
13752
14085
  type: "delegate",
13753
14086
  params: {
@@ -13775,13 +14108,13 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
13775
14108
  metadata: currentOffchainRow?.metadata
13776
14109
  });
13777
14110
  }
13778
- const boardingCsv = newBoarding.options.csvTimelock ?? chunkPXPPZF5K_cjs.DefaultVtxo.Script.DEFAULT_TIMELOCK;
14111
+ const boardingCsv = newBoarding.options.csvTimelock ?? chunk6YUACVX4_cjs.DefaultVtxo.Script.DEFAULT_TIMELOCK;
13779
14112
  await manager.createContract({
13780
14113
  type: "boarding",
13781
14114
  params: {
13782
14115
  pubKey: base.hex.encode(newBoarding.options.pubKey),
13783
14116
  serverPubKey: base.hex.encode(xonly),
13784
- csvTimelock: chunkZIRFXBKL_cjs.timelockToSequence(boardingCsv).toString()
14117
+ csvTimelock: chunkEJOFL5WH_cjs.timelockToSequence(boardingCsv).toString()
13785
14118
  },
13786
14119
  script: base.hex.encode(newBoarding.pkScript),
13787
14120
  address: newBoarding.address(this.network.hrp, xonly).encode(),
@@ -13814,14 +14147,14 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
13814
14147
  _restoreInFlight;
13815
14148
  _addPendingSpends(inputs) {
13816
14149
  for (const input of inputs) {
13817
- if (chunkZIRFXBKL_cjs.isVirtualCoin(input)) {
14150
+ if (chunkEJOFL5WH_cjs.isVirtualCoin(input)) {
13818
14151
  this._pendingSpendOutpoints.add(`${input.txid}:${input.vout}`);
13819
14152
  }
13820
14153
  }
13821
14154
  }
13822
14155
  _removePendingSpends(inputs) {
13823
14156
  for (const input of inputs) {
13824
- if (chunkZIRFXBKL_cjs.isVirtualCoin(input)) {
14157
+ if (chunkEJOFL5WH_cjs.isVirtualCoin(input)) {
13825
14158
  this._pendingSpendOutpoints.delete(`${input.txid}:${input.vout}`);
13826
14159
  }
13827
14160
  }
@@ -13879,13 +14212,13 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
13879
14212
  const manager = await this.getContractManager();
13880
14213
  const provider = this._descriptorProvider;
13881
14214
  const hd = provider instanceof HDDescriptorProvider;
13882
- const staticDescriptor = hd ? void 0 : await chunkPXPPZF5K_cjs.identityDescriptor(this.identity);
14215
+ const staticDescriptor = hd ? void 0 : await chunk6YUACVX4_cjs.identityDescriptor(this.identity);
13883
14216
  const materialize = (index) => hd ? provider.materializeDescriptorAt(index) : staticDescriptor;
13884
- const delegatePubKey = this.offchainTapscript instanceof chunkPXPPZF5K_cjs.DelegateVtxo.Script ? this.offchainTapscript.options.delegatePubKey : void 0;
14217
+ const delegatePubKey = this.offchainTapscript instanceof chunk6YUACVX4_cjs.DelegateVtxo.Script ? this.offchainTapscript.options.delegatePubKey : void 0;
13885
14218
  const arkInfo = await this.arkProvider.getInfo();
13886
- const currentSignerPubKey = chunkPXPPZF5K_cjs.toXOnly(base.hex.decode(arkInfo.signerPubkey), "ark signer key");
14219
+ const currentSignerPubKey = chunk6YUACVX4_cjs.toXOnly(base.hex.decode(arkInfo.signerPubkey), "ark signer key");
13887
14220
  const deprecatedSignerPubKeys = arkInfo.deprecatedSigners.map(
13888
- (s) => chunkPXPPZF5K_cjs.toXOnly(base.hex.decode(s.pubkey), "deprecated signer key")
14221
+ (s) => chunk6YUACVX4_cjs.toXOnly(base.hex.decode(s.pubkey), "deprecated signer key")
13889
14222
  );
13890
14223
  const deps = {
13891
14224
  indexerProvider: this.indexerProvider,
@@ -13900,7 +14233,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
13900
14233
  csvTimelocks: this.walletContractTimelocks,
13901
14234
  // Boarding-exit CSV so the boarding handler can build its
13902
14235
  // candidate script (distinct from the unilateral-exit matrix).
13903
- boardingTimelock: this.boardingTapscript.options.csvTimelock ?? chunkPXPPZF5K_cjs.DefaultVtxo.Script.DEFAULT_TIMELOCK,
14236
+ boardingTimelock: this.boardingTapscript.options.csvTimelock ?? chunk6YUACVX4_cjs.DefaultVtxo.Script.DEFAULT_TIMELOCK,
13904
14237
  delegatePubKey
13905
14238
  };
13906
14239
  const result = await manager.scanContracts({
@@ -13968,7 +14301,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
13968
14301
  await this._restoreInFlight?.catch(() => void 0);
13969
14302
  this._serverInfoUnsub?.();
13970
14303
  this._serverInfoUnsub = void 0;
13971
- await this._serverInfoInFlight?.catch(() => void 0);
14304
+ await this.settleServerInfoChanges();
13972
14305
  let rotatorError;
13973
14306
  try {
13974
14307
  await this._receiveRotator?.dispose();
@@ -14014,7 +14347,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
14014
14347
  throw new Error("Invalid configured public key");
14015
14348
  }
14016
14349
  const setup = await ReadonlyWallet.setupWalletConfig(config, pubkey);
14017
- const forfeitPubkey = chunkPXPPZF5K_cjs.toXOnly(base.hex.decode(setup.info.forfeitPubkey), "forfeit key");
14350
+ const forfeitPubkey = chunk6YUACVX4_cjs.toXOnly(base.hex.decode(setup.info.forfeitPubkey), "forfeit key");
14018
14351
  const forfeitAddress = btcSigner.Address(setup.network).decode(setup.info.forfeitAddress);
14019
14352
  const forfeitOutputScript = btcSigner.OutScript.encode(forfeitAddress);
14020
14353
  const checkpointExitDelayOverrides = {
@@ -14163,7 +14496,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
14163
14496
  inputs: params.selectedVtxos,
14164
14497
  changeAmount: BigInt(changeAmount)
14165
14498
  };
14166
- const outputAddress = chunkZIRFXBKL_cjs.ArkAddress.decode(params.address);
14499
+ const outputAddress = chunkEJOFL5WH_cjs.ArkAddress.decode(params.address);
14167
14500
  assertRecipientArkAddress(
14168
14501
  params.address,
14169
14502
  outputAddress,
@@ -14229,13 +14562,13 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
14229
14562
  void this.logUngatedInputs("settle({ inputs })", params.inputs);
14230
14563
  }
14231
14564
  const offchainAddress = await this.getAddress();
14232
- const offchainPkScript = chunkZIRFXBKL_cjs.ArkAddress.decode(offchainAddress).pkScript;
14565
+ const offchainPkScript = chunkEJOFL5WH_cjs.ArkAddress.decode(offchainAddress).pkScript;
14233
14566
  const offchainOutputScript = base.hex.encode(offchainPkScript);
14234
14567
  if (!params) {
14235
14568
  const { fees, vtxoMaxAmount } = await this.arkProvider.getInfo();
14236
14569
  const estimator = new Estimator(fees.intentFee);
14237
14570
  let amount = 0;
14238
- const exitScript = chunkZIRFXBKL_cjs.CSVMultisigTapscript.decode(
14571
+ const exitScript = chunkEJOFL5WH_cjs.CSVMultisigTapscript.decode(
14239
14572
  base.hex.decode(this.boardingTapscript.exitScript)
14240
14573
  );
14241
14574
  const boardingTimelock = exitScript.params.timelock;
@@ -14264,7 +14597,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
14264
14597
  if (filteredVtxos.length >= MAX_VTXOS_PER_SETTLEMENT) {
14265
14598
  break;
14266
14599
  }
14267
- const inputFee = estimator.evalOffchainInput(chunkZIRFXBKL_cjs.toOffchainInputFeeParams(vtxo));
14600
+ const inputFee = estimator.evalOffchainInput(chunkEJOFL5WH_cjs.toOffchainInputFeeParams(vtxo));
14268
14601
  if (inputFee.satoshis >= vtxo.value) {
14269
14602
  continue;
14270
14603
  }
@@ -14311,7 +14644,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
14311
14644
  let script;
14312
14645
  let arkAddress;
14313
14646
  try {
14314
- arkAddress = chunkZIRFXBKL_cjs.ArkAddress.decode(output.address);
14647
+ arkAddress = chunkEJOFL5WH_cjs.ArkAddress.decode(output.address);
14315
14648
  } catch {
14316
14649
  arkAddress = void 0;
14317
14650
  }
@@ -14401,7 +14734,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
14401
14734
  const abortController = new AbortController();
14402
14735
  let stream;
14403
14736
  let committedTxid;
14404
- const settleInputVtxos = params.inputs.filter(chunkZIRFXBKL_cjs.isVirtualCoin);
14737
+ const settleInputVtxos = params.inputs.filter(chunkEJOFL5WH_cjs.isVirtualCoin);
14405
14738
  const contractManager = await this.getContractManager();
14406
14739
  await contractManager.assertAnnotatable(settleInputVtxos);
14407
14740
  await contractManager.assertSpendableNow?.(
@@ -14500,7 +14833,10 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
14500
14833
  * `typeof` guard skips the arknote strings settle also accepts.
14501
14834
  *
14502
14835
  * No-ops for static / `auto` wallets (no descriptor provider — boarding
14503
- * stays on its fixed index-0 address). Best-effort and non-fatal: the
14836
+ * stays on its fixed index-0 address). Wallets on a custom
14837
+ * {@link DescriptorProvider} DO rotate here now, where they previously
14838
+ * no-opped — see the behaviour-change note on {@link
14839
+ * getNewBoardingAddress}. Best-effort and non-fatal: the
14504
14840
  * settle has already committed and its txid must be returned, so a
14505
14841
  * rotation failure is logged and swallowed rather than thrown. Funds at
14506
14842
  * the retired boarding address remain discoverable — the old `boarding`
@@ -14510,7 +14846,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
14510
14846
  async maybeRotateBoardingAfterBoard(inputs) {
14511
14847
  if (!this._descriptorProvider) return;
14512
14848
  const consumedBoarding = inputs.some(
14513
- (input) => typeof input !== "string" && !chunkZIRFXBKL_cjs.isVirtualCoin(input)
14849
+ (input) => typeof input !== "string" && !chunkEJOFL5WH_cjs.isVirtualCoin(input)
14514
14850
  );
14515
14851
  if (!consumedBoarding) return;
14516
14852
  try {
@@ -14534,7 +14870,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
14534
14870
  let connectorIndex = 0;
14535
14871
  const connectorsLeaves = connectorsGraph?.leaves() || [];
14536
14872
  for (const input of inputs) {
14537
- if (!chunkZIRFXBKL_cjs.isVirtualCoin(input)) {
14873
+ if (!chunkEJOFL5WH_cjs.isVirtualCoin(input)) {
14538
14874
  for (let i = 0; i < settlementPsbt.inputsLength; i++) {
14539
14875
  const settlementInput = settlementPsbt.getInput(i);
14540
14876
  if (!settlementInput.txid || settlementInput.index === void 0) {
@@ -14565,7 +14901,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
14565
14901
  }
14566
14902
  continue;
14567
14903
  }
14568
- if (chunkZIRFXBKL_cjs.canRecoverOnchain(input, { timestamp: /* @__PURE__ */ new Date() }) || isSubdust({ value: input.value }, this.dustAmount)) {
14904
+ if (chunkEJOFL5WH_cjs.canRecoverOnchain(input, { timestamp: /* @__PURE__ */ new Date() }) || isSubdust({ value: input.value }, this.dustAmount)) {
14569
14905
  continue;
14570
14906
  }
14571
14907
  if (connectorsLeaves.length === 0) {
@@ -14593,7 +14929,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
14593
14929
  index: input.vout,
14594
14930
  witnessUtxo: {
14595
14931
  amount: BigInt(input.value),
14596
- script: chunkZIRFXBKL_cjs.VtxoScript.decode(input.tapTree).pkScript
14932
+ script: chunkEJOFL5WH_cjs.VtxoScript.decode(input.tapTree).pkScript
14597
14933
  },
14598
14934
  sighashType: btcSigner.SigHash.DEFAULT,
14599
14935
  tapLeafScript: [input.forfeitTapLeafScript]
@@ -14612,7 +14948,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
14612
14948
  forfeitTx = await this._signerRouter.sign(forfeitTx, [
14613
14949
  {
14614
14950
  index: 0,
14615
- lookupScript: chunkZIRFXBKL_cjs.VtxoScript.decode(input.tapTree).pkScript
14951
+ lookupScript: chunkEJOFL5WH_cjs.VtxoScript.decode(input.tapTree).pkScript
14616
14952
  }
14617
14953
  ]);
14618
14954
  signedForfeits.push(base.base64.encode(forfeitTx.toPSBT()));
@@ -14670,7 +15006,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
14670
15006
  resolveBatchExpiryPolicy(this.network, this.batchExpiryPolicy)
14671
15007
  );
14672
15008
  await this.arkProvider.confirmRegistration(intentId);
14673
- const sweepTapscript = chunkZIRFXBKL_cjs.CSVMultisigTapscript.encode({
15009
+ const sweepTapscript = chunkEJOFL5WH_cjs.CSVMultisigTapscript.encode({
14674
15010
  timelock,
14675
15011
  pubkeys: [this.forfeitPubkey]
14676
15012
  }).script;
@@ -14685,10 +15021,10 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
14685
15021
  throw new Error("Sweep tap tree root not set");
14686
15022
  }
14687
15023
  const xOnlyPublicKeys = event.cosignersPublicKeys.map(
14688
- (k) => base.hex.encode(chunkPXPPZF5K_cjs.toXOnly(base.hex.decode(k), "cosigner key"))
15024
+ (k) => base.hex.encode(chunk6YUACVX4_cjs.toXOnly(base.hex.decode(k), "cosigner key"))
14689
15025
  );
14690
15026
  const signerPublicKey = await session.getPublicKey();
14691
- const xonlySignerPublicKey = chunkPXPPZF5K_cjs.toXOnly(signerPublicKey, "signer key");
15027
+ const xonlySignerPublicKey = chunk6YUACVX4_cjs.toXOnly(signerPublicKey, "signer key");
14692
15028
  if (!xOnlyPublicKeys.includes(base.hex.encode(xonlySignerPublicKey))) {
14693
15029
  return { skip: true };
14694
15030
  }
@@ -14778,9 +15114,9 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
14778
15114
  ...existing ?? {},
14779
15115
  intentTxId,
14780
15116
  registerProof: intent.proof,
14781
- registerProofMessage: chunkZIRFXBKL_cjs.Intent.encodeMessage(intent.message),
15117
+ registerProofMessage: chunkEJOFL5WH_cjs.Intent.encodeMessage(intent.message),
14782
15118
  deleteProof: deleteIntent.proof,
14783
- deleteProofMessage: chunkZIRFXBKL_cjs.Intent.encodeMessage(deleteIntent.message),
15119
+ deleteProofMessage: chunkEJOFL5WH_cjs.Intent.encodeMessage(deleteIntent.message),
14784
15120
  intentVtxos: inputs.map((i) => ({
14785
15121
  txid: i.txid,
14786
15122
  vout: i.vout
@@ -14812,7 +15148,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
14812
15148
  try {
14813
15149
  return await this.arkProvider.registerIntent(intent);
14814
15150
  } catch (error) {
14815
- if (error instanceof chunkZIRFXBKL_cjs.ArkError && error.code === 0 && error.message.includes("duplicated input")) {
15151
+ if (error instanceof chunkEJOFL5WH_cjs.ArkError && error.code === 0 && error.message.includes("duplicated input")) {
14816
15152
  const deleteIntent = await this.makeDeleteIntentSignature(inputs);
14817
15153
  await this.arkProvider.deleteIntent(deleteIntent);
14818
15154
  return this.arkProvider.registerIntent(intent);
@@ -14828,7 +15164,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
14828
15164
  expire_at: 0,
14829
15165
  cosigners_public_keys: cosignerPubKeys
14830
15166
  };
14831
- const proof = chunkZIRFXBKL_cjs.Intent.create(message, coins, outputs);
15167
+ const proof = chunkEJOFL5WH_cjs.Intent.create(message, coins, outputs);
14832
15168
  const signedProof = await this._signerRouter.sign(proof, intentProofJobs(coins));
14833
15169
  return {
14834
15170
  proof: base.base64.encode(signedProof.toPSBT()),
@@ -14840,7 +15176,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
14840
15176
  type: "delete",
14841
15177
  expire_at: 0
14842
15178
  };
14843
- const proof = chunkZIRFXBKL_cjs.Intent.create(message, coins, []);
15179
+ const proof = chunkEJOFL5WH_cjs.Intent.create(message, coins, []);
14844
15180
  const signedProof = await this._signerRouter.sign(proof, intentProofJobs(coins));
14845
15181
  return {
14846
15182
  proof: base.base64.encode(signedProof.toPSBT()),
@@ -14852,7 +15188,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
14852
15188
  type: "get-pending-tx",
14853
15189
  expire_at: 0
14854
15190
  };
14855
- const proof = chunkZIRFXBKL_cjs.Intent.create(message, coins, []);
15191
+ const proof = chunkEJOFL5WH_cjs.Intent.create(message, coins, []);
14856
15192
  const signedProof = await this._signerRouter.sign(proof, intentProofJobs(coins));
14857
15193
  return {
14858
15194
  proof: base.base64.encode(signedProof.toPSBT()),
@@ -14873,7 +15209,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
14873
15209
  if (!vtxos || vtxos.length === 0) {
14874
15210
  const scriptMap = await this.getScriptMap();
14875
15211
  const allExtended = [];
14876
- const fetchedVtxos = await chunkZIRFXBKL_cjs.getAllNormalizedVtxos(this.indexerProvider, [
15212
+ const fetchedVtxos = await chunkEJOFL5WH_cjs.getAllNormalizedVtxos(this.indexerProvider, [
14877
15213
  ...scriptMap.keys()
14878
15214
  ]);
14879
15215
  for (const vtxo of fetchedVtxos) {
@@ -14915,9 +15251,11 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
14915
15251
  seen.add(pendingTx.arkTxid);
14916
15252
  batchPending.push(pendingTx.arkTxid);
14917
15253
  try {
14918
- const checkpointTxs = pendingTx.signedCheckpointTxs.map(
14919
- (c) => btcSigner.Transaction.fromPSBT(base.base64.decode(c))
14920
- );
15254
+ const checkpointTxs = pendingTx.signedCheckpointTxs.map((c) => {
15255
+ const tx = btcSigner.Transaction.fromPSBT(base.base64.decode(c));
15256
+ chunkEJOFL5WH_cjs.assertAllowedSighashTypes(tx);
15257
+ return tx;
15258
+ });
14921
15259
  assertCheckpointsMatchInputs(
14922
15260
  checkpointTxs,
14923
15261
  checkpointInputs,
@@ -14987,11 +15325,11 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
14987
15325
  * against the current key alone would leave it pending forever.
14988
15326
  */
14989
15327
  checkpointUnrollCandidates(info) {
14990
- const current = chunkZIRFXBKL_cjs.CSVMultisigTapscript.decode(base.hex.decode(info.checkpointTapscript));
15328
+ const current = chunkEJOFL5WH_cjs.CSVMultisigTapscript.decode(base.hex.decode(info.checkpointTapscript));
14991
15329
  const candidates = [this._serverUnrollScript, current];
14992
15330
  for (const deprecated of signerSetFromInfo(info).deprecated.keys()) {
14993
15331
  candidates.push(
14994
- chunkZIRFXBKL_cjs.CSVMultisigTapscript.encode({
15332
+ chunkEJOFL5WH_cjs.CSVMultisigTapscript.encode({
14995
15333
  ...current.params,
14996
15334
  pubkeys: [base.hex.decode(deprecated)]
14997
15335
  })
@@ -15082,10 +15420,12 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
15082
15420
  if (vtxos.length === 0) {
15083
15421
  throw new Error("No VTXOs found for this arkadeCash");
15084
15422
  }
15085
- const myPkScript = chunkZIRFXBKL_cjs.ArkAddress.decode(await this.getAddress()).pkScript;
15423
+ const myPkScript = chunkEJOFL5WH_cjs.ArkAddress.decode(await this.getAddress()).pkScript;
15086
15424
  let { spendable, unclaimed } = this.classifyCashVtxos(vtxos);
15087
15425
  let swept = 0;
15088
- const drainable = vtxos.filter((vtxo) => !isSubdust(vtxo, this.dustAmount));
15426
+ const drainable = vtxos.filter(
15427
+ (vtxo) => !isSubdust(vtxo, this.dustAmount) && !vtxo.isUnrolled
15428
+ );
15089
15429
  if (drainable.length > 0) {
15090
15430
  let drained = { count: 0, swept: 0, claimed: /* @__PURE__ */ new Set() };
15091
15431
  try {
@@ -15156,8 +15496,10 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
15156
15496
  const spendable = [];
15157
15497
  const unclaimed = [];
15158
15498
  for (const vtxo of vtxos) {
15159
- if (chunkZIRFXBKL_cjs.hasTerminalSpend(vtxo)) {
15499
+ if (chunkEJOFL5WH_cjs.hasTerminalSpend(vtxo)) {
15160
15500
  unclaimed.push(cashReport(vtxo, "already-spent"));
15501
+ } else if (vtxo.isUnrolled) {
15502
+ unclaimed.push(cashReport(vtxo, "exited"));
15161
15503
  } else if (isSubdust(vtxo, this.dustAmount)) {
15162
15504
  unclaimed.push(cashReport(vtxo, "subdust"));
15163
15505
  } else if (vtxo.isSwept) {
@@ -15176,7 +15518,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
15176
15518
  const all = [];
15177
15519
  const seen = /* @__PURE__ */ new Set();
15178
15520
  for (let pageIndex = 0; ; pageIndex++) {
15179
- const { vtxos, page } = await chunkZIRFXBKL_cjs.getNormalizedVtxos(this.indexerProvider, {
15521
+ const { vtxos, page } = await chunkEJOFL5WH_cjs.getNormalizedVtxos(this.indexerProvider, {
15180
15522
  scripts,
15181
15523
  pageIndex,
15182
15524
  pageSize
@@ -15223,7 +15565,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
15223
15565
  for (let i = 0; i < inputs.length; i += MAX_INPUTS_PER_INTENT) {
15224
15566
  const batch = inputs.slice(i, i + MAX_INPUTS_PER_INTENT);
15225
15567
  const message = { type: "get-pending-tx", expire_at: 0 };
15226
- const proof = chunkZIRFXBKL_cjs.Intent.create(message, batch, []);
15568
+ const proof = chunkEJOFL5WH_cjs.Intent.create(message, batch, []);
15227
15569
  const signedProof = await identity.sign(
15228
15570
  proof,
15229
15571
  Array.from({ length: batch.length + 1 }, (_, j) => j)
@@ -15243,9 +15585,11 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
15243
15585
  const unrollCandidates = this.checkpointUnrollCandidates(await this.arkProvider.getInfo());
15244
15586
  for (const pendingTx of pendingTxs) {
15245
15587
  try {
15246
- const checkpointTxs = pendingTx.signedCheckpointTxs.map(
15247
- (checkpoint) => btcSigner.Transaction.fromPSBT(base.base64.decode(checkpoint))
15248
- );
15588
+ const checkpointTxs = pendingTx.signedCheckpointTxs.map((checkpoint) => {
15589
+ const tx = btcSigner.Transaction.fromPSBT(base.base64.decode(checkpoint));
15590
+ chunkEJOFL5WH_cjs.assertAllowedSighashTypes(tx);
15591
+ return tx;
15592
+ });
15249
15593
  assertCheckpointsMatchInputs(
15250
15594
  checkpointTxs,
15251
15595
  inputs.map((input) => ({
@@ -15442,7 +15786,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
15442
15786
  script: recipient.script,
15443
15787
  amount: BigInt(recipient.amount),
15444
15788
  // Already checked against the recipient address in `validateRecipients`.
15445
- ...recipient.tapTree ? { tapTree: chunkZIRFXBKL_cjs.TapTreeCoder.decode(recipient.tapTree) } : {}
15789
+ ...recipient.tapTree ? { tapTree: chunkEJOFL5WH_cjs.TapTreeCoder.decode(recipient.tapTree) } : {}
15446
15790
  }));
15447
15791
  const totalBtcOutput = outputs.reduce((sum, o) => sum + Number(o.amount), 0);
15448
15792
  let changeAmount = totalBtcSelected - totalBtcOutput;
@@ -15586,10 +15930,10 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
15586
15930
  const serverPubKey = this.arkServerPublicKey;
15587
15931
  const serverUnrollScript = this.serverUnrollScript;
15588
15932
  const arkAddress = offchainTapscript.address(this.network.hrp, serverPubKey);
15589
- const normalizedInputs = inputs.map(chunkZIRFXBKL_cjs.normalizeVtxo);
15590
- const at = now ?? await chunkZIRFXBKL_cjs.resolveTimeHeight(this.onchainProvider);
15933
+ const normalizedInputs = inputs.map(chunkEJOFL5WH_cjs.normalizeVtxo);
15934
+ const at = now ?? await chunkEJOFL5WH_cjs.resolveTimeHeight(this.onchainProvider);
15591
15935
  for (const input of normalizedInputs) {
15592
- if (!chunkZIRFXBKL_cjs.canSpendOffchain(input, at)) {
15936
+ if (!chunkEJOFL5WH_cjs.canSpendOffchain(input, at)) {
15593
15937
  throw new Error(
15594
15938
  `sendSelectedVtxosToSelf: input ${input.txid}:${input.vout} is not cooperatively spendable`
15595
15939
  );
@@ -15659,7 +16003,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
15659
16003
  );
15660
16004
  const arkTxJobs = inputs.map((input, index) => ({
15661
16005
  index,
15662
- lookupScript: chunkZIRFXBKL_cjs.VtxoScript.decode(input.tapTree).pkScript
16006
+ lookupScript: chunkEJOFL5WH_cjs.VtxoScript.decode(input.tapTree).pkScript
15663
16007
  }));
15664
16008
  const identity = this.identity;
15665
16009
  const signer = {
@@ -15745,14 +16089,14 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
15745
16089
  const spentBy = checkpointIdByOutpoint.get(`${vtxo.txid}:${vtxo.vout}`);
15746
16090
  spentVtxos.push({
15747
16091
  ...spentFacts,
15748
- virtualStatus: chunkZIRFXBKL_cjs.toVirtualStatus(spentFacts),
16092
+ virtualStatus: chunkEJOFL5WH_cjs.toVirtualStatus(spentFacts),
15749
16093
  ...spentBy ? { spentBy } : {},
15750
16094
  arkTxId: arkTxid
15751
16095
  });
15752
16096
  for (const id of vtxo.commitmentTxIds) {
15753
16097
  commitmentTxIds.add(id);
15754
16098
  }
15755
- const vtxoExpiry = chunkZIRFXBKL_cjs.toBatchExpiry(vtxo);
16099
+ const vtxoExpiry = chunkEJOFL5WH_cjs.toBatchExpiry(vtxo);
15756
16100
  if (vtxoExpiry) {
15757
16101
  batchExpiry = Math.min(batchExpiry, vtxoExpiry);
15758
16102
  }
@@ -15765,7 +16109,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
15765
16109
  isSwept: false,
15766
16110
  isPreconfirmed: true,
15767
16111
  commitmentTxIds: Array.from(commitmentTxIds),
15768
- ...chunkZIRFXBKL_cjs.parseLegacyExpiry(batchExpiry)
16112
+ ...chunkEJOFL5WH_cjs.parseLegacyExpiry(batchExpiry)
15769
16113
  };
15770
16114
  changeVtxo = {
15771
16115
  txid: arkTxid,
@@ -15777,7 +16121,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
15777
16121
  tapTree: offchainTapscript.encode(),
15778
16122
  value: Number(changeAmount),
15779
16123
  ...changeFacts,
15780
- virtualStatus: chunkZIRFXBKL_cjs.toVirtualStatus(changeFacts),
16124
+ virtualStatus: chunkEJOFL5WH_cjs.toVirtualStatus(changeFacts),
15781
16125
  spentBy: "",
15782
16126
  status: {
15783
16127
  confirmed: false
@@ -15846,12 +16190,12 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
15846
16190
  const spentVtxos = [];
15847
16191
  const inputArkTxIds = /* @__PURE__ */ new Set();
15848
16192
  const boardingRemovalsByAddress = /* @__PURE__ */ new Map();
15849
- const vtxoInputs = inputs.filter(chunkZIRFXBKL_cjs.isVirtualCoin);
16193
+ const vtxoInputs = inputs.filter(chunkEJOFL5WH_cjs.isVirtualCoin);
15850
16194
  const cm = await this.getContractManager();
15851
16195
  const annotatedVtxos = await cm.annotateVtxos(vtxoInputs);
15852
16196
  const annotatedByKey = new Map(annotatedVtxos.map((v) => [`${v.txid}:${v.vout}`, v]));
15853
16197
  for (const input of inputs) {
15854
- if (chunkZIRFXBKL_cjs.isVirtualCoin(input)) {
16198
+ if (chunkEJOFL5WH_cjs.isVirtualCoin(input)) {
15855
16199
  const outpoint = `${input.txid}:${input.vout}`;
15856
16200
  const vtxo = annotatedByKey.get(outpoint);
15857
16201
  if (!vtxo) {
@@ -15863,13 +16207,13 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
15863
16207
  const settledFacts = { ...vtxo, isSpent: true };
15864
16208
  spentVtxos.push({
15865
16209
  ...settledFacts,
15866
- virtualStatus: chunkZIRFXBKL_cjs.toVirtualStatus(settledFacts),
16210
+ virtualStatus: chunkEJOFL5WH_cjs.toVirtualStatus(settledFacts),
15867
16211
  settledBy: commitmentTxid
15868
16212
  });
15869
16213
  } else {
15870
16214
  let sourceAddress;
15871
16215
  try {
15872
- sourceAddress = chunkZIRFXBKL_cjs.VtxoScript.decode(input.tapTree).onchainAddress(
16216
+ sourceAddress = chunkEJOFL5WH_cjs.VtxoScript.decode(input.tapTree).onchainAddress(
15873
16217
  this.network
15874
16218
  );
15875
16219
  } catch {
@@ -15927,9 +16271,9 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
15927
16271
  }
15928
16272
  };
15929
16273
  function selectVirtualCoins(coins, targetAmount) {
15930
- const sortedCoins = coins.map(chunkZIRFXBKL_cjs.normalizeVtxo).sort((a, b) => {
15931
- const expiryA = chunkZIRFXBKL_cjs.toBatchExpiry(a) || Number.MAX_SAFE_INTEGER;
15932
- const expiryB = chunkZIRFXBKL_cjs.toBatchExpiry(b) || Number.MAX_SAFE_INTEGER;
16274
+ const sortedCoins = coins.map(chunkEJOFL5WH_cjs.normalizeVtxo).sort((a, b) => {
16275
+ const expiryA = chunkEJOFL5WH_cjs.toBatchExpiry(a) || Number.MAX_SAFE_INTEGER;
16276
+ const expiryB = chunkEJOFL5WH_cjs.toBatchExpiry(b) || Number.MAX_SAFE_INTEGER;
15933
16277
  if (expiryA !== expiryB) {
15934
16278
  return expiryA - expiryB;
15935
16279
  }
@@ -16048,6 +16392,11 @@ var MessageBus = class {
16048
16392
  buildServicesFn;
16049
16393
  boundOnMessage = this.onMessage.bind(this);
16050
16394
  intentRepository;
16395
+ /** Pending broadcasts, drained FIFO by a single {@link drain} loop. */
16396
+ broadcastQueue = [];
16397
+ draining = false;
16398
+ /** Bumped wherever the generation owning the queued broadcasts ends. */
16399
+ broadcastEpoch = 0;
16051
16400
  /** Start the message bus and attach service-worker event listeners. */
16052
16401
  async start() {
16053
16402
  if (this.running) return;
@@ -16070,6 +16419,7 @@ var MessageBus = class {
16070
16419
  this.running = false;
16071
16420
  this.tickInProgress = false;
16072
16421
  this.initialized = false;
16422
+ this.invalidateBroadcasts();
16073
16423
  if (this.tickTimeout !== null) {
16074
16424
  self.clearTimeout(this.tickTimeout);
16075
16425
  this.tickTimeout = null;
@@ -16082,6 +16432,78 @@ var MessageBus = class {
16082
16432
  self.removeEventListener("message", this.boundOnMessage);
16083
16433
  await Promise.all(Array.from(this.handlers.values()).map((updater) => updater.stop()));
16084
16434
  }
16435
+ /** Invalidate every broadcast belonging to the outgoing generation. */
16436
+ invalidateBroadcasts() {
16437
+ this.broadcastEpoch++;
16438
+ this.broadcastQueue.length = 0;
16439
+ }
16440
+ broadcastToClients(responses) {
16441
+ this.broadcastQueue.push(...responses);
16442
+ void this.drain();
16443
+ }
16444
+ /**
16445
+ * Single fan-out loop, so pushes and tick responses keep one FIFO order.
16446
+ * A helper posting per response would race: `clients.matchAll()` gives no
16447
+ * cross-call resolution order, and it would de-batch `runTick`.
16448
+ */
16449
+ async drain() {
16450
+ if (this.draining) return;
16451
+ this.draining = true;
16452
+ try {
16453
+ while (this.broadcastQueue.length) {
16454
+ const epoch = this.broadcastEpoch;
16455
+ const batch = this.broadcastQueue.splice(0);
16456
+ if (!this.running) {
16457
+ this.logDroppedBroadcasts(batch, "bus stopped");
16458
+ return;
16459
+ }
16460
+ let clients;
16461
+ try {
16462
+ clients = await self.clients.matchAll({
16463
+ includeUncontrolled: true,
16464
+ type: "window"
16465
+ });
16466
+ } catch (err) {
16467
+ this.logDroppedBroadcasts(batch, "clients.matchAll failed", err);
16468
+ continue;
16469
+ }
16470
+ if (!this.running) {
16471
+ this.logDroppedBroadcasts(batch, "bus stopped during matchAll");
16472
+ return;
16473
+ }
16474
+ if (this.broadcastEpoch !== epoch) {
16475
+ this.logDroppedBroadcasts(batch, "re-init landed during matchAll");
16476
+ continue;
16477
+ }
16478
+ for (const message of batch) {
16479
+ for (const client of clients) {
16480
+ try {
16481
+ client.postMessage(message);
16482
+ } catch (err) {
16483
+ if (this.debug)
16484
+ console.warn(`[${message.tag}] broadcast to client failed`, err);
16485
+ }
16486
+ }
16487
+ }
16488
+ }
16489
+ } catch {
16490
+ } finally {
16491
+ this.draining = false;
16492
+ if (this.running && this.broadcastQueue.length) void this.drain();
16493
+ }
16494
+ }
16495
+ /**
16496
+ * A dropped batch has no periodic recovery to fall back on now that events
16497
+ * no longer ride the tick, so name the loss under {@link Options.debug}.
16498
+ */
16499
+ logDroppedBroadcasts(batch, reason, ...error) {
16500
+ if (!this.debug) return;
16501
+ console.warn(
16502
+ `dropping ${batch.length} broadcast(s): ${reason}`,
16503
+ batch.map((response) => response.tag),
16504
+ ...error
16505
+ );
16506
+ }
16085
16507
  scheduleNextTick() {
16086
16508
  if (!this.running) return;
16087
16509
  if (this.tickTimeout !== null) return;
@@ -16110,16 +16532,7 @@ var MessageBus = class {
16110
16532
  if (this.debug)
16111
16533
  console.log(`[${updater.messageTag}] outgoing tick response:`, response);
16112
16534
  if (response && response.length > 0) {
16113
- self.clients.matchAll({
16114
- includeUncontrolled: true,
16115
- type: "window"
16116
- }).then((clients) => {
16117
- for (const message of response) {
16118
- clients.forEach((client) => {
16119
- client.postMessage(message);
16120
- });
16121
- }
16122
- });
16535
+ this.broadcastToClients(response);
16123
16536
  }
16124
16537
  } catch (err) {
16125
16538
  if (this.debug) console.error(`[${updater.messageTag}] tick failed`, err);
@@ -16158,6 +16571,14 @@ var MessageBus = class {
16158
16571
  self.clearTimeout(this.tickTimeout);
16159
16572
  this.tickTimeout = null;
16160
16573
  }
16574
+ this.invalidateBroadcasts();
16575
+ const epoch = this.broadcastEpoch;
16576
+ const channel = {
16577
+ broadcast: (response) => {
16578
+ if (epoch !== this.broadcastEpoch) return;
16579
+ this.broadcastToClients([response]);
16580
+ }
16581
+ };
16161
16582
  if (this.initialized) {
16162
16583
  this.initialized = false;
16163
16584
  await Promise.all(
@@ -16174,9 +16595,7 @@ var MessageBus = class {
16174
16595
  try {
16175
16596
  for (const updater of this.handlers.values()) {
16176
16597
  if (this.debug) console.log(`Starting updater: ${updater.messageTag}`);
16177
- await updater.start(services, {
16178
- walletRepository: this.walletRepository
16179
- });
16598
+ await updater.start(services, { walletRepository: this.walletRepository }, channel);
16180
16599
  started.push(updater);
16181
16600
  }
16182
16601
  } catch (err) {
@@ -16189,7 +16608,7 @@ var MessageBus = class {
16189
16608
  this.initialized = true;
16190
16609
  }
16191
16610
  async buildServices(config) {
16192
- const arkProvider = new chunkZIRFXBKL_cjs.RestArkProvider(config.arkServer.url);
16611
+ const arkProvider = new chunkEJOFL5WH_cjs.RestArkProvider(config.arkServer.url);
16193
16612
  const storage = {
16194
16613
  walletRepository: this.walletRepository,
16195
16614
  contractRepository: this.contractRepository,
@@ -16531,7 +16950,7 @@ var offboardNetworkNames = [
16531
16950
  function offboardDestinationScript(destinationAddress) {
16532
16951
  for (const networkName of offboardNetworkNames) {
16533
16952
  try {
16534
- const network = chunkZIRFXBKL_cjs.networks[networkName];
16953
+ const network = chunkEJOFL5WH_cjs.networks[networkName];
16535
16954
  const addr = btcSigner.Address(network).decode(destinationAddress);
16536
16955
  return btcSigner.OutScript.encode(addr);
16537
16956
  } catch {
@@ -16595,7 +17014,7 @@ var Ramps = class {
16595
17014
  }
16596
17015
  amount = amount ?? totalAmount;
16597
17016
  const offchainAddress = await this.wallet.getAddress();
16598
- const offchainAddr = chunkZIRFXBKL_cjs.ArkAddress.decode(offchainAddress);
17017
+ const offchainAddr = chunkEJOFL5WH_cjs.ArkAddress.decode(offchainAddress);
16599
17018
  const offchainScript = base.hex.encode(offchainAddr.pkScript);
16600
17019
  const outputFee = estimator.evalOffchainOutput({
16601
17020
  amount,
@@ -16655,7 +17074,7 @@ var Ramps = class {
16655
17074
  const filteredVtxos = [];
16656
17075
  let totalAmount = 0n;
16657
17076
  for (const vtxo of vtxos) {
16658
- const inputFee = estimator.evalOffchainInput(chunkZIRFXBKL_cjs.toOffchainInputFeeParams(vtxo));
17077
+ const inputFee = estimator.evalOffchainInput(chunkEJOFL5WH_cjs.toOffchainInputFeeParams(vtxo));
16659
17078
  if (inputFee.satoshis >= vtxo.value) {
16660
17079
  continue;
16661
17080
  }
@@ -16846,6 +17265,17 @@ var WalletMessageHandler = class {
16846
17265
  incomingFundsSubscription;
16847
17266
  contractEventsSubscription;
16848
17267
  onNextTick = [];
17268
+ channel;
17269
+ // One counter per subscription field, bumped exactly where that field is
17270
+ // dropped — never where a neighbour's is. They cannot be merged:
17271
+ // `onWalletInitialized` re-subscribes incoming funds while
17272
+ // `ensureContractEventBroadcasting` deliberately keeps its subscription, so
17273
+ // a shared bump would leave the live contract-event emitter permanently
17274
+ // stale, and folding requests in would truncate an in-flight settle.
17275
+ incomingFundsEpoch = 0;
17276
+ contractEventsEpoch = 0;
17277
+ /** Per-request progress callbacks: ends with the handler, not with a re-init. */
17278
+ requestEpoch = 0;
16849
17279
  /**
16850
17280
  * Instantiate a new WalletUpdater.
16851
17281
  * Can override the default `messageTag` allowing more than one updater to run in parallel.
@@ -16856,13 +17286,20 @@ var WalletMessageHandler = class {
16856
17286
  }
16857
17287
  // lifecycle methods
16858
17288
  async start(...params) {
16859
- const [services, repositories] = params;
17289
+ const [services, repositories, channel] = params;
16860
17290
  this.readonlyWallet = services.readonlyWallet;
16861
17291
  this.wallet = services.wallet;
16862
17292
  this.arkProvider = services.arkProvider;
16863
17293
  this.walletRepository = repositories.walletRepository;
17294
+ this.channel = channel;
17295
+ this.onNextTick = [];
16864
17296
  }
16865
17297
  async stop() {
17298
+ this.requestEpoch++;
17299
+ this.incomingFundsEpoch++;
17300
+ this.contractEventsEpoch++;
17301
+ this.channel = void 0;
17302
+ this.onNextTick = [];
16866
17303
  if (this.incomingFundsSubscription) {
16867
17304
  this.incomingFundsSubscription();
16868
17305
  this.incomingFundsSubscription = void 0;
@@ -16885,8 +17322,8 @@ var WalletMessageHandler = class {
16885
17322
  this.indexerProvider = void 0;
16886
17323
  }
16887
17324
  async tick(_now) {
16888
- const results = await Promise.allSettled(this.onNextTick.map((fn) => fn()));
16889
- this.onNextTick = [];
17325
+ const pending = this.onNextTick.splice(0);
17326
+ const results = await Promise.allSettled(pending.map((fn) => fn()));
16890
17327
  return results.map((result) => {
16891
17328
  if (result.status === "fulfilled") {
16892
17329
  return result.value;
@@ -16896,8 +17333,46 @@ var WalletMessageHandler = class {
16896
17333
  }
16897
17334
  }).filter((response) => response !== null);
16898
17335
  }
16899
- scheduleForNextTick(callback) {
16900
- this.onNextTick.push(callback);
17336
+ epochOf(scope) {
17337
+ switch (scope) {
17338
+ case "incomingFunds":
17339
+ return this.incomingFundsEpoch;
17340
+ case "contractEvents":
17341
+ return this.contractEventsEpoch;
17342
+ case "request":
17343
+ return this.requestEpoch;
17344
+ default: {
17345
+ const _exhaustive = scope;
17346
+ throw new Error(`Unknown scope: ${_exhaustive}`);
17347
+ }
17348
+ }
17349
+ }
17350
+ newGeneration(scope) {
17351
+ const born = this.epochOf(scope);
17352
+ const stale = () => born !== this.epochOf(scope);
17353
+ return {
17354
+ get stale() {
17355
+ return stale();
17356
+ }
17357
+ };
17358
+ }
17359
+ /**
17360
+ * A handle rather than a `broadcast(response, epoch)` call, because it can
17361
+ * only be written where the closure it guards is created — an epoch passed
17362
+ * at the call site reads identically whether it guards anything or not.
17363
+ */
17364
+ newEmitter(scope) {
17365
+ const gen = this.newGeneration(scope);
17366
+ return {
17367
+ get stale() {
17368
+ return gen.stale;
17369
+ },
17370
+ emit: (response) => {
17371
+ if (!response || gen.stale) return;
17372
+ if (this.channel) return this.channel.broadcast(response);
17373
+ this.onNextTick.push(() => response);
17374
+ }
17375
+ };
16901
17376
  }
16902
17377
  requireWallet() {
16903
17378
  if (!this.wallet) {
@@ -16926,6 +17401,7 @@ var WalletMessageHandler = class {
16926
17401
  }
16927
17402
  async handleMessage(message) {
16928
17403
  const id = message.id;
17404
+ const emitter = this.newEmitter("request");
16929
17405
  if (message.type === "INIT_WALLET") {
16930
17406
  await this.handleInitWallet(message);
16931
17407
  return this.tagged({
@@ -17194,6 +17670,18 @@ var WalletMessageHandler = class {
17194
17670
  payload: { descriptor }
17195
17671
  });
17196
17672
  }
17673
+ case "GET_NEW_ADDRESSES": {
17674
+ const wallet = this.wallet;
17675
+ if (!wallet) throw new WalletNotInitializedError();
17676
+ const addresses = await wallet.getNewAddresses(
17677
+ message.payload
17678
+ );
17679
+ return this.tagged({
17680
+ id,
17681
+ type: "NEW_ADDRESSES",
17682
+ payload: { addresses }
17683
+ });
17684
+ }
17197
17685
  case "GET_USED_SIGNING_DESCRIPTORS": {
17198
17686
  const wallet = this.wallet;
17199
17687
  const descriptors = isHDWalletCapable(wallet) ? await wallet.getUsedSigningDescriptors(
@@ -17284,8 +17772,8 @@ var WalletMessageHandler = class {
17284
17772
  const wallet = this.requireWallet();
17285
17773
  const vtxoManager = await wallet.getVtxoManager();
17286
17774
  const txid = await vtxoManager.recoverVtxos((e) => {
17287
- this.scheduleForNextTick(
17288
- () => this.tagged({
17775
+ emitter.emit(
17776
+ this.tagged({
17289
17777
  id,
17290
17778
  type: "RECOVER_VTXOS_EVENT",
17291
17779
  payload: e
@@ -17329,8 +17817,8 @@ var WalletMessageHandler = class {
17329
17817
  const wallet = this.requireWallet();
17330
17818
  const vtxoManager = await wallet.getVtxoManager();
17331
17819
  const txid = await vtxoManager.renewVtxos((e) => {
17332
- this.scheduleForNextTick(
17333
- () => this.tagged({
17820
+ emitter.emit(
17821
+ this.tagged({
17334
17822
  id,
17335
17823
  type: "RENEW_VTXOS_EVENT",
17336
17824
  payload: e
@@ -17368,8 +17856,8 @@ var WalletMessageHandler = class {
17368
17856
  const vtxoManager = await wallet.getVtxoManager();
17369
17857
  const report = await vtxoManager.migrateDeprecatedSignerVtxos({
17370
17858
  eventCallback: (e) => {
17371
- this.scheduleForNextTick(
17372
- () => this.tagged({
17859
+ emitter.emit(
17860
+ this.tagged({
17373
17861
  id,
17374
17862
  type: "MIGRATE_DEPRECATED_SIGNER_VTXOS_EVENT",
17375
17863
  payload: e
@@ -17422,7 +17910,7 @@ var WalletMessageHandler = class {
17422
17910
  // Wallet methods
17423
17911
  async handleInitWallet({ payload }) {
17424
17912
  const { arkServerUrl } = payload;
17425
- this.indexerProvider = new chunk3S3JZUEN_cjs.RestIndexerProvider(arkServerUrl);
17913
+ this.indexerProvider = new chunkPJR63FTK_cjs.RestIndexerProvider(arkServerUrl);
17426
17914
  await this.onWalletInitialized();
17427
17915
  }
17428
17916
  /**
@@ -17472,6 +17960,7 @@ var WalletMessageHandler = class {
17472
17960
  intentLocked: offchain.intentLocked,
17473
17961
  recoverable: offchain.recoverable,
17474
17962
  pendingRecovery: offchain.pendingRecovery,
17963
+ unrolled: offchain.unrolled,
17475
17964
  total: totalBoarding + offchain.total,
17476
17965
  assets: offchain.assets,
17477
17966
  availableAssets: offchain.availableAssets
@@ -17482,11 +17971,15 @@ var WalletMessageHandler = class {
17482
17971
  return this.readonlyWallet.getBoardingUtxos();
17483
17972
  }
17484
17973
  async onWalletInitialized() {
17485
- if (!this.readonlyWallet || !this.arkProvider || !this.indexerProvider || !this.walletRepository) {
17974
+ const wallet = this.readonlyWallet;
17975
+ if (!wallet || !this.arkProvider || !this.indexerProvider || !this.walletRepository) {
17486
17976
  return;
17487
17977
  }
17978
+ const init = this.newGeneration("incomingFunds");
17488
17979
  await this.ensureContractEventBroadcasting();
17980
+ if (init.stale) return;
17489
17981
  await this.refreshCachedData();
17982
+ if (init.stale) return;
17490
17983
  if (this.wallet) {
17491
17984
  try {
17492
17985
  const vtxos = await this.getVtxosFromRepo();
@@ -17499,72 +17992,81 @@ var WalletMessageHandler = class {
17499
17992
  } catch (error) {
17500
17993
  console.error("Error recovering pending transactions:", error);
17501
17994
  }
17995
+ if (init.stale) return;
17502
17996
  }
17503
17997
  if (this.incomingFundsSubscription) this.incomingFundsSubscription();
17504
- const address = await this.readonlyWallet.getAddress();
17505
- this.incomingFundsSubscription = await this.readonlyWallet.notifyIncomingFunds(
17506
- async (funds) => {
17507
- if (funds.type === "vtxo") {
17508
- const { newVtxos, spentVtxos } = funds;
17509
- if (newVtxos.length + spentVtxos.length === 0) return;
17510
- const byScript = /* @__PURE__ */ new Map();
17511
- for (const v of [...newVtxos, ...spentVtxos]) {
17512
- if (!v.script) {
17513
- console.warn(
17514
- `WalletMessageHandler.notifyIncomingFunds: dropping VTXO without script ${v.txid}:${v.vout}`
17515
- );
17516
- continue;
17517
- }
17518
- const arr = byScript.get(v.script) ?? [];
17519
- arr.push(v);
17520
- byScript.set(v.script, arr);
17521
- }
17522
- let walletScript;
17523
- try {
17524
- walletScript = scriptFromArkAddress(address);
17525
- } catch {
17526
- walletScript = void 0;
17527
- }
17528
- const cm = await this.readonlyWallet.getContractManager();
17529
- const contracts = await cm.getContracts();
17530
- const addrByScript = new Map(contracts.map((c) => [c.script, c.address]));
17531
- for (const [script, vtxos] of byScript) {
17532
- const filtered = warnAndFilterVtxosForScript(
17533
- vtxos,
17534
- script,
17535
- "WalletMessageHandler.notifyIncomingFunds"
17998
+ this.incomingFundsSubscription = void 0;
17999
+ this.incomingFundsEpoch++;
18000
+ const emitter = this.newEmitter("incomingFunds");
18001
+ const address = await wallet.getAddress();
18002
+ const unsubscribe = await wallet.notifyIncomingFunds(async (funds) => {
18003
+ if (emitter.stale) return;
18004
+ if (funds.type === "vtxo") {
18005
+ const { newVtxos, spentVtxos } = funds;
18006
+ if (newVtxos.length + spentVtxos.length === 0) return;
18007
+ const byScript = /* @__PURE__ */ new Map();
18008
+ for (const v of [...newVtxos, ...spentVtxos]) {
18009
+ if (!v.script) {
18010
+ console.warn(
18011
+ `WalletMessageHandler.notifyIncomingFunds: dropping VTXO without script ${v.txid}:${v.vout}`
17536
18012
  );
17537
- if (filtered.length === 0) continue;
17538
- const targetAddress = script === walletScript ? address : addrByScript.get(script);
17539
- if (!targetAddress) continue;
17540
- if (this.walletRepository) {
17541
- await saveVtxosForContract(
17542
- this.walletRepository,
17543
- { script, address: targetAddress },
17544
- filtered
17545
- );
17546
- }
18013
+ continue;
17547
18014
  }
17548
- this.scheduleForNextTick(
17549
- () => this.tagged({
17550
- type: "VTXO_UPDATE",
17551
- broadcast: true,
17552
- payload: { newVtxos, spentVtxos }
17553
- })
17554
- );
18015
+ const arr = byScript.get(v.script) ?? [];
18016
+ arr.push(v);
18017
+ byScript.set(v.script, arr);
17555
18018
  }
17556
- if (funds.type === "utxo") {
17557
- const utxos = await this.readonlyWallet.getBoardingUtxos();
17558
- this.scheduleForNextTick(
17559
- () => this.tagged({
17560
- type: "UTXO_UPDATE",
17561
- broadcast: true,
17562
- payload: { coins: utxos }
17563
- })
18019
+ let walletScript;
18020
+ try {
18021
+ walletScript = scriptFromArkAddress(address);
18022
+ } catch {
18023
+ walletScript = void 0;
18024
+ }
18025
+ const cm = await wallet.getContractManager();
18026
+ if (emitter.stale) return;
18027
+ const contracts = await cm.getContracts();
18028
+ if (emitter.stale) return;
18029
+ const addrByScript = new Map(contracts.map((c) => [c.script, c.address]));
18030
+ for (const [script, vtxos] of byScript) {
18031
+ const filtered = warnAndFilterVtxosForScript(
18032
+ vtxos,
18033
+ script,
18034
+ "WalletMessageHandler.notifyIncomingFunds"
17564
18035
  );
18036
+ if (filtered.length === 0) continue;
18037
+ const targetAddress = script === walletScript ? address : addrByScript.get(script);
18038
+ if (!targetAddress) continue;
18039
+ if (this.walletRepository) {
18040
+ if (emitter.stale) return;
18041
+ await saveVtxosForContract(
18042
+ this.walletRepository,
18043
+ { script, address: targetAddress },
18044
+ filtered
18045
+ );
18046
+ }
17565
18047
  }
18048
+ emitter.emit(
18049
+ this.tagged({
18050
+ type: "VTXO_UPDATE",
18051
+ broadcast: true,
18052
+ payload: { newVtxos, spentVtxos }
18053
+ })
18054
+ );
17566
18055
  }
17567
- );
18056
+ if (funds.type === "utxo") {
18057
+ if (emitter.stale) return;
18058
+ const utxos = await wallet.getBoardingUtxos();
18059
+ emitter.emit(
18060
+ this.tagged({
18061
+ type: "UTXO_UPDATE",
18062
+ broadcast: true,
18063
+ payload: { coins: utxos }
18064
+ })
18065
+ );
18066
+ }
18067
+ });
18068
+ if (emitter.stale) return unsubscribe();
18069
+ this.incomingFundsSubscription = unsubscribe;
17568
18070
  if (this.wallet) {
17569
18071
  try {
17570
18072
  await this.wallet.getVtxoManager();
@@ -17609,10 +18111,11 @@ var WalletMessageHandler = class {
17609
18111
  await this.refreshCachedData();
17610
18112
  }
17611
18113
  async handleSettle(message) {
18114
+ const emitter = this.newEmitter("request");
17612
18115
  const wallet = this.requireWallet();
17613
18116
  const txid = await wallet.settle(message.payload.params, (e) => {
17614
- this.scheduleForNextTick(
17615
- () => this.tagged({
18117
+ emitter.emit(
18118
+ this.tagged({
17616
18119
  id: message.id,
17617
18120
  type: "SETTLE_EVENT",
17618
18121
  payload: e
@@ -17689,30 +18192,39 @@ var WalletMessageHandler = class {
17689
18192
  throw new WalletNotInitializedError();
17690
18193
  }
17691
18194
  const allVtxos = await this.getVtxosFromRepo();
17692
- const vtxos = allVtxos.filter((v) => !chunkZIRFXBKL_cjs.hasTerminalSpend(v));
17693
18195
  const dustAmount = this.readonlyWallet.dustAmount;
18196
+ const withUnrolled = message.payload.filter?.withUnrolled ?? false;
17694
18197
  const includeRecoverable = message.payload.filter?.withRecoverable ?? false;
17695
- const filteredVtxos = includeRecoverable ? vtxos : vtxos.filter((v) => {
18198
+ return allVtxos.filter((v) => {
18199
+ if (v.isUnrolled) {
18200
+ return withUnrolled;
18201
+ }
18202
+ if (chunkEJOFL5WH_cjs.hasTerminalSpend(v)) {
18203
+ return false;
18204
+ }
18205
+ if (includeRecoverable) {
18206
+ return true;
18207
+ }
17696
18208
  if (dustAmount != null && isSubdust(v, dustAmount)) {
17697
18209
  return false;
17698
18210
  }
17699
- if (chunkZIRFXBKL_cjs.isRecoverable(v)) {
18211
+ if (chunkEJOFL5WH_cjs.isRecoverable(v)) {
17700
18212
  return false;
17701
18213
  }
17702
- if (chunkZIRFXBKL_cjs.isExpired(v)) {
18214
+ if (chunkEJOFL5WH_cjs.isExpired(v)) {
17703
18215
  return false;
17704
18216
  }
17705
18217
  return true;
17706
18218
  });
17707
- if (!message.payload.filter?.withUnrolled) {
17708
- return filteredVtxos;
17709
- }
17710
- return filteredVtxos.concat(allVtxos.filter((v) => chunkZIRFXBKL_cjs.hasTerminalSpend(v) && v.isUnrolled));
17711
18219
  }
17712
18220
  /** Tear down handler subscriptions, then delegate the full wipe to the wallet. */
17713
18221
  async clear() {
17714
18222
  const wallet = this.wallet ?? this.readonlyWallet;
17715
18223
  if (!wallet) return;
18224
+ this.requestEpoch++;
18225
+ this.incomingFundsEpoch++;
18226
+ this.contractEventsEpoch++;
18227
+ this.onNextTick = [];
17716
18228
  if (this.incomingFundsSubscription) {
17717
18229
  this.incomingFundsSubscription();
17718
18230
  this.incomingFundsSubscription = void 0;
@@ -17797,17 +18309,21 @@ var WalletMessageHandler = class {
17797
18309
  if (!this.readonlyWallet) return null;
17798
18310
  const { boardingTxs, commitmentsToIgnore } = await this.readonlyWallet.getBoardingTxs();
17799
18311
  const indexerProvider = this.indexerProvider;
17800
- const resolveTxCreatedAt = indexerProvider ? (txids) => chunkZIRFXBKL_cjs.fetchVtxoCreatedAtByTxid(indexerProvider, txids) : void 0;
18312
+ const resolveTxCreatedAt = indexerProvider ? (txids) => chunkEJOFL5WH_cjs.fetchVtxoCreatedAtByTxid(indexerProvider, txids) : void 0;
17801
18313
  return buildTransactionHistory(vtxos, boardingTxs, commitmentsToIgnore, resolveTxCreatedAt);
17802
18314
  }
17803
18315
  async ensureContractEventBroadcasting() {
17804
- if (!this.readonlyWallet) return;
18316
+ const wallet = this.readonlyWallet;
18317
+ if (!wallet) return;
17805
18318
  if (this.contractEventsSubscription) return;
18319
+ const gen = this.newGeneration("contractEvents");
17806
18320
  try {
17807
- const manager = await this.readonlyWallet.getContractManager();
18321
+ const manager = await wallet.getContractManager();
18322
+ if (gen.stale || this.contractEventsSubscription) return;
18323
+ const emitter = this.newEmitter("contractEvents");
17808
18324
  this.contractEventsSubscription = manager.onContractEvent((event) => {
17809
- this.scheduleForNextTick(
17810
- () => this.tagged({
18325
+ emitter.emit(
18326
+ this.tagged({
17811
18327
  type: "CONTRACT_EVENT",
17812
18328
  broadcast: true,
17813
18329
  payload: { event }
@@ -17838,6 +18354,9 @@ var DEFAULT_MESSAGE_TIMEOUTS = {
17838
18354
  // Allocation is a local repository write plus a fire-and-forget band
17839
18355
  // slide — no indexer round trip on the request path.
17840
18356
  GET_NEXT_SIGNING_DESCRIPTOR: 1e4,
18357
+ // Same shape as the bare allocation above, plus one contract write per
18358
+ // requested type — still local, still no indexer round trip.
18359
+ GET_NEW_ADDRESSES: 1e4,
17841
18360
  GET_USED_SIGNING_DESCRIPTORS: 2e4,
17842
18361
  ADVANCE_SIGNING_DESCRIPTOR_WATERMARK: 1e4,
17843
18362
  // Medium reads — may involve indexer queries
@@ -18486,7 +19005,7 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
18486
19005
  };
18487
19006
  try {
18488
19007
  const response = await this.sendMessage(message);
18489
- return response.payload.vtxos.map(chunkZIRFXBKL_cjs.normalizeVtxo);
19008
+ return response.payload.vtxos.map(chunkEJOFL5WH_cjs.normalizeVtxo);
18490
19009
  } catch (error) {
18491
19010
  throw new Error(`Failed to get vtxos: ${error}`);
18492
19011
  }
@@ -18511,7 +19030,7 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
18511
19030
  };
18512
19031
  try {
18513
19032
  const response = await this.sendMessage(message);
18514
- return response.payload.vtxos.map(chunkZIRFXBKL_cjs.normalizeVtxo);
19033
+ return response.payload.vtxos.map(chunkEJOFL5WH_cjs.normalizeVtxo);
18515
19034
  } catch (error) {
18516
19035
  throw new Error(`Failed to get spendable vtxos: ${error}`);
18517
19036
  }
@@ -18642,7 +19161,7 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
18642
19161
  };
18643
19162
  try {
18644
19163
  const response = await sendContractMessage(message);
18645
- return response.payload.vtxos.map(chunkZIRFXBKL_cjs.normalizeVtxo);
19164
+ return response.payload.vtxos.map(chunkEJOFL5WH_cjs.normalizeVtxo);
18646
19165
  } catch (e) {
18647
19166
  throw new Error("Failed to annotate vtxos");
18648
19167
  }
@@ -18983,6 +19502,35 @@ var ServiceWorkerWallet = class _ServiceWorkerWallet extends ServiceWorkerReadon
18983
19502
  throw new Error(`Failed to allocate next signing descriptor: ${error}`);
18984
19503
  }
18985
19504
  }
19505
+ /**
19506
+ * @see Wallet.getNewAddresses
19507
+ *
19508
+ * Proxied as a single request rather than rebuilt page-side out of
19509
+ * {@link getNextSigningDescriptor}: the worker owns the HD watermark *and*
19510
+ * the contract repository, so splitting the operation would let a page burn
19511
+ * an index and then fail to register the script, leaving an address nothing
19512
+ * watches.
19513
+ *
19514
+ * Note the error shape — `WalletCannotAllocateAddressError` is thrown
19515
+ * worker-side and cannot cross the message boundary as a class, so a
19516
+ * `forceNew` refusal surfaces here as a plain `Error` carrying its message
19517
+ * (and the worker-side error as `cause`). Callers that must branch on the
19518
+ * refusal match the message rather than `instanceof`.
19519
+ */
19520
+ async getNewAddresses(opts) {
19521
+ const message = {
19522
+ id: getRandomId(),
19523
+ tag: this.messageTag,
19524
+ type: "GET_NEW_ADDRESSES",
19525
+ ...opts ? { payload: opts } : {}
19526
+ };
19527
+ try {
19528
+ const response = await this.sendMessage(message);
19529
+ return response.payload.addresses;
19530
+ } catch (error) {
19531
+ throw new Error(`Failed to allocate new addresses: ${error}`, { cause: error });
19532
+ }
19533
+ }
18986
19534
  /** @see HDWalletCapable.getUsedSigningDescriptors */
18987
19535
  async getUsedSigningDescriptors(opts) {
18988
19536
  const message = {
@@ -19214,7 +19762,7 @@ var ServiceWorkerWallet = class _ServiceWorkerWallet extends ServiceWorkerReadon
19214
19762
  };
19215
19763
  try {
19216
19764
  const response = await wallet.sendMessage(message);
19217
- return response.payload.vtxos.map(chunkZIRFXBKL_cjs.normalizeVtxo);
19765
+ return response.payload.vtxos.map(chunkEJOFL5WH_cjs.normalizeVtxo);
19218
19766
  } catch (e) {
19219
19767
  throw new Error(`Failed to get expiring vtxos: ${e}`);
19220
19768
  }
@@ -19326,12 +19874,12 @@ var OnchainWallet = class _OnchainWallet {
19326
19874
  * @returns Configured onchain wallet
19327
19875
  * @throws Error if the configured identity cannot produce a valid x-only public key
19328
19876
  */
19329
- static async create(identity, networkName = chunkZIRFXBKL_cjs.DEFAULT_NETWORK_NAME, provider) {
19877
+ static async create(identity, networkName = chunkEJOFL5WH_cjs.DEFAULT_NETWORK_NAME, provider) {
19330
19878
  const pubkey = await identity.xOnlyPublicKey();
19331
19879
  if (!pubkey) {
19332
19880
  throw new Error("Invalid configured public key");
19333
19881
  }
19334
- const network = chunkZIRFXBKL_cjs.getNetwork(networkName);
19882
+ const network = chunkEJOFL5WH_cjs.getNetwork(networkName);
19335
19883
  const onchainProvider = provider || new EsploraProvider(ESPLORA_URL[networkName]);
19336
19884
  const onchainP2TR = btcSigner.p2tr(pubkey, void 0, network);
19337
19885
  return new _OnchainWallet(identity, network, onchainP2TR, onchainProvider);
@@ -19437,7 +19985,7 @@ var OnchainWallet = class _OnchainWallet {
19437
19985
  if (!inputs) {
19438
19986
  throw new Error("Fee estimation failed");
19439
19987
  }
19440
- let tx = new chunkZIRFXBKL_cjs.Transaction();
19988
+ let tx = new chunkEJOFL5WH_cjs.Transaction();
19441
19989
  for (const input of inputs) {
19442
19990
  tx.addInput({
19443
19991
  txid: input.txid,
@@ -19495,7 +20043,7 @@ var OnchainWallet = class _OnchainWallet {
19495
20043
  * @throws If the parent has no anchor, or funding cannot be selected/signed
19496
20044
  */
19497
20045
  async bumpAnchor(parentHex, feeRate) {
19498
- const parent = chunkZIRFXBKL_cjs.Transaction.fromRaw(base.hex.decode(parentHex));
20046
+ const parent = chunkEJOFL5WH_cjs.Transaction.fromRaw(base.hex.decode(parentHex));
19499
20047
  const coins = (await this.getCoins()).filter((c) => c.status.confirmed);
19500
20048
  const child = await this.buildBumpPackage(parent, feeRate, coins);
19501
20049
  return [parent.hex, child.hex];
@@ -19949,6 +20497,10 @@ var ElectrumOnchainProvider = class {
19949
20497
  }
19950
20498
  throw new Error("Only 1 or 1P1C package can be broadcast");
19951
20499
  }
20500
+ async getRawTransaction(txid) {
20501
+ const [tx] = await this.chain.fetchTransactions([txid]);
20502
+ return base.hex.decode(tx.hex);
20503
+ }
19952
20504
  async getTxOutspends(txid) {
19953
20505
  const [txResult] = await this.chain.fetchTransactions([txid]);
19954
20506
  const tx = btcSigner.Transaction.fromRaw(base.hex.decode(txResult.hex), {
@@ -20254,13 +20806,190 @@ function childTxidFromHex(txHex) {
20254
20806
  });
20255
20807
  return tx.id;
20256
20808
  }
20809
+
20810
+ // src/providers/cachingArk.ts
20811
+ var DEFAULT_TTL_MS = 6e4;
20812
+ var CachingArkProvider = class {
20813
+ constructor(inner, ttlMs = DEFAULT_TTL_MS) {
20814
+ this.inner = inner;
20815
+ this.ttlMs = ttlMs;
20816
+ this.unsubscribe = inner.onServerInfoChanged?.((info) => {
20817
+ this.cached = info;
20818
+ this.expiresAt = Date.now() + this.ttlMs;
20819
+ this.generation++;
20820
+ }) ?? (() => {
20821
+ });
20822
+ }
20823
+ inner;
20824
+ ttlMs;
20825
+ cached;
20826
+ expiresAt = 0;
20827
+ inflight;
20828
+ /** Bumped on every event-driven cache write; see {@link getInfo}. */
20829
+ generation = 0;
20830
+ unsubscribe;
20831
+ /** Releases the inner provider's server-info subscription. */
20832
+ dispose() {
20833
+ this.unsubscribe();
20834
+ }
20835
+ get serverUrl() {
20836
+ const url = this.inner.serverUrl;
20837
+ return typeof url === "string" ? url : void 0;
20838
+ }
20839
+ async getInfo() {
20840
+ if (this.cached && Date.now() < this.expiresAt) return this.cached;
20841
+ if (!this.inflight) {
20842
+ const generation = this.generation;
20843
+ this.inflight = this.inner.getInfo().then((info) => {
20844
+ if (this.generation !== generation) return this.cached ?? info;
20845
+ this.cached = info;
20846
+ this.expiresAt = Date.now() + this.ttlMs;
20847
+ return info;
20848
+ }).finally(() => {
20849
+ this.inflight = void 0;
20850
+ });
20851
+ }
20852
+ return this.inflight;
20853
+ }
20854
+ submitTx(signedArkTx, checkpointTxs) {
20855
+ return this.inner.submitTx(signedArkTx, checkpointTxs);
20856
+ }
20857
+ finalizeTx(arkTxid, finalCheckpointTxs) {
20858
+ return this.inner.finalizeTx(arkTxid, finalCheckpointTxs);
20859
+ }
20860
+ registerIntent(intent) {
20861
+ return this.inner.registerIntent(intent);
20862
+ }
20863
+ deleteIntent(intent) {
20864
+ return this.inner.deleteIntent(intent);
20865
+ }
20866
+ confirmRegistration(intentId) {
20867
+ return this.inner.confirmRegistration(intentId);
20868
+ }
20869
+ submitTreeNonces(batchId, pubkey, nonces) {
20870
+ return this.inner.submitTreeNonces(batchId, pubkey, nonces);
20871
+ }
20872
+ submitTreeSignatures(batchId, pubkey, signatures) {
20873
+ return this.inner.submitTreeSignatures(batchId, pubkey, signatures);
20874
+ }
20875
+ submitSignedForfeitTxs(signedForfeitTxs, signedCommitmentTx) {
20876
+ return this.inner.submitSignedForfeitTxs(signedForfeitTxs, signedCommitmentTx);
20877
+ }
20878
+ getEventStream(signal, topics) {
20879
+ return this.inner.getEventStream(signal, topics);
20880
+ }
20881
+ getTransactionsStream(signal) {
20882
+ return this.inner.getTransactionsStream(signal);
20883
+ }
20884
+ getPendingTxs(intent) {
20885
+ return this.inner.getPendingTxs(intent);
20886
+ }
20887
+ onServerInfoChanged(listener) {
20888
+ return this.inner.onServerInfoChanged?.(listener) ?? (() => {
20889
+ });
20890
+ }
20891
+ };
20892
+ var PrevTxUnavailableError = class extends Error {
20893
+ constructor(message, txids = []) {
20894
+ super(message);
20895
+ this.txids = txids;
20896
+ this.name = "PrevTxUnavailableError";
20897
+ }
20898
+ txids;
20899
+ };
20900
+ async function resolvePrevTxs(txids, source, onchain) {
20901
+ const resolved = /* @__PURE__ */ new Map();
20902
+ const wanted = [...new Set(txids)];
20903
+ if (wanted.length === 0) return resolved;
20904
+ try {
20905
+ const { txs } = await source.getVirtualTxs(wanted);
20906
+ for (const psbt of txs) {
20907
+ const tx = chunkEJOFL5WH_cjs.Transaction.fromPSBT(base.base64.decode(psbt));
20908
+ resolved.set(tx.id, tx.toBytes());
20909
+ }
20910
+ } catch (err) {
20911
+ if (!onchain) throw err;
20912
+ }
20913
+ let missing = wanted.filter((txid) => !resolved.has(txid));
20914
+ if (missing.length > 0 && onchain) {
20915
+ const raw = await Promise.all(
20916
+ missing.map(async (txid) => {
20917
+ try {
20918
+ return await onchain.getRawTransaction(txid);
20919
+ } catch {
20920
+ return void 0;
20921
+ }
20922
+ })
20923
+ );
20924
+ for (const [i, bytes] of raw.entries()) {
20925
+ if (bytes) resolved.set(missing[i], bytes);
20926
+ }
20927
+ missing = missing.filter((txid) => !resolved.has(txid));
20928
+ }
20929
+ if (missing.length > 0) {
20930
+ throw new PrevTxUnavailableError(
20931
+ `cannot resolve the previous transaction of ${missing.join(", ")}` + (onchain ? "" : " (no onchain source configured)"),
20932
+ missing
20933
+ );
20934
+ }
20935
+ return resolved;
20936
+ }
20937
+ async function attachPrevArkTxs(tx, txids, source, onchain) {
20938
+ const pending = [];
20939
+ for (let i = 0; i < tx.inputsLength; i++) {
20940
+ if (chunkEJOFL5WH_cjs.getArkPsbtFields(tx, i, chunkEJOFL5WH_cjs.PrevArkTxField).length === 0) pending.push(i);
20941
+ }
20942
+ if (pending.length === 0) return;
20943
+ const resolved = await resolvePrevTxs(
20944
+ pending.map((i) => txidAt(txids, i)),
20945
+ source,
20946
+ onchain
20947
+ );
20948
+ for (const i of pending) {
20949
+ chunkEJOFL5WH_cjs.setArkPsbtField(tx, i, chunkEJOFL5WH_cjs.PrevArkTxField, resolved.get(txidAt(txids, i)));
20950
+ }
20951
+ }
20952
+ async function attachPrevoutTxs(tx, source) {
20953
+ const pending = [];
20954
+ for (let i = 0; i < tx.inputsLength; i++) {
20955
+ if (chunkEJOFL5WH_cjs.getArkPsbtFields(tx, i, chunkEJOFL5WH_cjs.PrevoutTxField).length > 0) continue;
20956
+ const input = tx.getInput(i);
20957
+ if (!input?.txid) throw new PrevTxUnavailableError(`input ${i} has no outpoint`);
20958
+ pending.push({ index: i, txid: base.hex.encode(input.txid) });
20959
+ }
20960
+ if (pending.length === 0) return;
20961
+ const resolved = /* @__PURE__ */ new Map();
20962
+ for (const txid of new Set(pending.map((p) => p.txid))) {
20963
+ resolved.set(txid, await source.getRawTransaction(txid));
20964
+ }
20965
+ for (const { index, txid } of pending) {
20966
+ chunkEJOFL5WH_cjs.setArkPsbtField(tx, index, chunkEJOFL5WH_cjs.PrevoutTxField, resolved.get(txid));
20967
+ }
20968
+ }
20969
+ async function withPrevTxs(coins, source, onchain) {
20970
+ const pending = coins.filter((c) => !c.prevTx);
20971
+ if (pending.length === 0) return coins;
20972
+ const resolved = await resolvePrevTxs(
20973
+ pending.map((c) => c.txid),
20974
+ source,
20975
+ onchain
20976
+ );
20977
+ return coins.map((c) => c.prevTx ? c : { ...c, prevTx: resolved.get(c.txid) });
20978
+ }
20979
+ function txidAt(txids, index) {
20980
+ const txid = txids[index];
20981
+ if (txid === void 0) {
20982
+ throw new PrevTxUnavailableError(`no source txid supplied for input ${index}`);
20983
+ }
20984
+ return txid;
20985
+ }
20257
20986
  var TAG_BIP322 = "BIP0322-signed-message";
20258
20987
  exports.BIP322 = void 0;
20259
20988
  ((BIP3222) => {
20260
20989
  async function sign2(message, identity, network) {
20261
20990
  const xOnlyPubKey = await identity.xOnlyPublicKey();
20262
20991
  const payment = btcSigner.p2tr(xOnlyPubKey, void 0, network);
20263
- const toSpend = chunkZIRFXBKL_cjs.craftToSpendTx(message, payment.script, TAG_BIP322);
20992
+ const toSpend = chunkEJOFL5WH_cjs.craftToSpendTx(message, payment.script, TAG_BIP322);
20264
20993
  const toSign = craftBIP322ToSignP2TR(toSpend, payment.script, xOnlyPubKey);
20265
20994
  const signed = await identity.sign(toSign, [0]);
20266
20995
  signed.finalizeIdx(0);
@@ -20318,7 +21047,7 @@ function verifyP2TR(message, witnessItems, pkScript, pubkey) {
20318
21047
  if (sighashType !== btcSigner.SigHash.DEFAULT && sighashType !== btcSigner.SigHash.ALL) {
20319
21048
  return false;
20320
21049
  }
20321
- const toSpend = chunkZIRFXBKL_cjs.craftToSpendTx(message, pkScript, TAG_BIP322);
21050
+ const toSpend = chunkEJOFL5WH_cjs.craftToSpendTx(message, pkScript, TAG_BIP322);
20322
21051
  const toSign = craftBIP322ToSignP2TR(toSpend, pkScript, pubkey);
20323
21052
  const sighash = toSign.preimageWitnessV1(0, [pkScript], sighashType, [0n]);
20324
21053
  const rawSig = sig.length === 65 ? sig.subarray(0, 64) : sig;
@@ -20339,7 +21068,7 @@ function verifyP2WPKH(message, witnessItems, pkScript, addressHash) {
20339
21068
  }
20340
21069
  const sighashType = sigWithHash[sigWithHash.length - 1];
20341
21070
  const derSig = sigWithHash.subarray(0, sigWithHash.length - 1);
20342
- const toSpend = chunkZIRFXBKL_cjs.craftToSpendTx(message, pkScript, TAG_BIP322);
21071
+ const toSpend = chunkEJOFL5WH_cjs.craftToSpendTx(message, pkScript, TAG_BIP322);
20343
21072
  const toSign = craftBIP322ToSignSimple(toSpend, pkScript);
20344
21073
  const scriptCode = btcSigner.OutScript.encode({ type: "pkh", hash: addressHash });
20345
21074
  const sighash = toSign.preimageWitnessV0(0, scriptCode, sighashType, 0n);
@@ -20392,7 +21121,7 @@ function encodeCompactSize(n) {
20392
21121
  return buf;
20393
21122
  }
20394
21123
  function craftBIP322ToSignP2TR(toSpend, pkScript, tapInternalKey) {
20395
- const tx = new chunkZIRFXBKL_cjs.Transaction({ version: 0 });
21124
+ const tx = new chunkEJOFL5WH_cjs.Transaction({ version: 0 });
20396
21125
  tx.addInput({
20397
21126
  txid: toSpend.id,
20398
21127
  index: 0,
@@ -20406,12 +21135,12 @@ function craftBIP322ToSignP2TR(toSpend, pkScript, tapInternalKey) {
20406
21135
  });
20407
21136
  tx.addOutput({
20408
21137
  amount: 0n,
20409
- script: chunkZIRFXBKL_cjs.OP_RETURN_EMPTY_PKSCRIPT
21138
+ script: chunkEJOFL5WH_cjs.OP_RETURN_EMPTY_PKSCRIPT
20410
21139
  });
20411
21140
  return tx;
20412
21141
  }
20413
21142
  function craftBIP322ToSignSimple(toSpend, pkScript) {
20414
- const tx = new chunkZIRFXBKL_cjs.Transaction({ version: 0 });
21143
+ const tx = new chunkEJOFL5WH_cjs.Transaction({ version: 0 });
20415
21144
  tx.addInput({
20416
21145
  txid: toSpend.id,
20417
21146
  index: 0,
@@ -20423,7 +21152,7 @@ function craftBIP322ToSignSimple(toSpend, pkScript) {
20423
21152
  });
20424
21153
  tx.addOutput({
20425
21154
  amount: 0n,
20426
- script: chunkZIRFXBKL_cjs.OP_RETURN_EMPTY_PKSCRIPT
21155
+ script: chunkEJOFL5WH_cjs.OP_RETURN_EMPTY_PKSCRIPT
20427
21156
  });
20428
21157
  return tx;
20429
21158
  }
@@ -20554,7 +21283,7 @@ var RestEmulatorProvider = class {
20554
21283
  }
20555
21284
  };
20556
21285
  function finalizeVirtualTx(type, psbtBase64) {
20557
- const tx = chunkZIRFXBKL_cjs.Transaction.fromPSBT(base.base64.decode(psbtBase64));
21286
+ const tx = chunkEJOFL5WH_cjs.Transaction.fromPSBT(base.base64.decode(psbtBase64));
20558
21287
  if (type === "INDEXER_CHAINED_TX_TYPE_TREE" /* TREE */) {
20559
21288
  const input = tx.getInput(0);
20560
21289
  if (!input) {
@@ -20581,14 +21310,14 @@ var ExitPathError = class extends Error {
20581
21310
  reason;
20582
21311
  };
20583
21312
  function delayWeight(sequence) {
20584
- const t = chunkZIRFXBKL_cjs.sequenceToTimelock(sequence);
21313
+ const t = chunkEJOFL5WH_cjs.sequenceToTimelock(sequence);
20585
21314
  return t.type === "blocks" ? Number(t.value) : Number(t.value) / 600;
20586
21315
  }
20587
21316
  async function resolveUnilateralPath(params) {
20588
21317
  const { vtxo, scriptHex, contractRepository } = params;
20589
21318
  const contract = contractRepository ? (await contractRepository.getContracts({ script: scriptHex }))[0] : void 0;
20590
21319
  if (contract) {
20591
- const handler = chunkPXPPZF5K_cjs.contractHandlers.get(contract.type);
21320
+ const handler = chunk6YUACVX4_cjs.contractHandlers.get(contract.type);
20592
21321
  if (!handler) {
20593
21322
  throw new ExitPathError(
20594
21323
  "no-handler",
@@ -20611,12 +21340,12 @@ async function resolveUnilateralPath(params) {
20611
21340
  paths.sort((a, b) => delayWeight(a.sequence) - delayWeight(b.sequence));
20612
21341
  return { selection: paths[0], label: `${contract.type}:unilateral` };
20613
21342
  }
20614
- const decoded = chunkZIRFXBKL_cjs.VtxoScript.decode(vtxo.tapTree);
21343
+ const decoded = chunkEJOFL5WH_cjs.VtxoScript.decode(vtxo.tapTree);
20615
21344
  let best;
20616
21345
  for (const exit of decoded.exitPaths()) {
20617
21346
  const leaf = decoded.findLeaf(base.hex.encode(exit.script));
20618
21347
  if (!leaf) continue;
20619
- const sequence = chunkZIRFXBKL_cjs.timelockToSequence(exit.params.timelock);
21348
+ const sequence = chunkEJOFL5WH_cjs.timelockToSequence(exit.params.timelock);
20620
21349
  const weight = delayWeight(sequence);
20621
21350
  if (!best || weight < best.weight) {
20622
21351
  best = { selection: { leaf, sequence }, weight };
@@ -20631,6 +21360,22 @@ async function resolveUnilateralPath(params) {
20631
21360
  return { selection: best.selection, label: "default:exit" };
20632
21361
  }
20633
21362
 
21363
+ // src/wallet/exitObserver.ts
21364
+ function exitObserverFor(manager) {
21365
+ return (outpoint) => manager.refreshOutpoints([outpoint]);
21366
+ }
21367
+ async function notifyExitObserved(onExitObserved, outpoint) {
21368
+ if (!onExitObserved) return;
21369
+ try {
21370
+ await onExitObserved(outpoint);
21371
+ } catch (e) {
21372
+ console.error(
21373
+ `exit observer failed for ${outpoint.txid}:${outpoint.vout} \u2014 the exit is unaffected`,
21374
+ e
21375
+ );
21376
+ }
21377
+ }
21378
+
20634
21379
  // src/wallet/unroll.ts
20635
21380
  function chainTxTypeToChainedExit2(t) {
20636
21381
  switch (t) {
@@ -20655,27 +21400,30 @@ exports.Unroll = void 0;
20655
21400
  })(Unroll2.StepType || (Unroll2.StepType = {}));
20656
21401
  class Session2 {
20657
21402
  /** Create an unroll session from a virtual output outpoint and its dependency chain. */
20658
- constructor(toUnroll, bumper, explorer, indexer, virtualTxRepository) {
21403
+ constructor(toUnroll, bumper, explorer, indexer, virtualTxRepository, onExitObserved) {
20659
21404
  this.toUnroll = toUnroll;
20660
21405
  this.bumper = bumper;
20661
21406
  this.explorer = explorer;
20662
21407
  this.indexer = indexer;
20663
21408
  this.virtualTxRepository = virtualTxRepository;
21409
+ this.onExitObserved = onExitObserved;
20664
21410
  }
20665
21411
  toUnroll;
20666
21412
  bumper;
20667
21413
  explorer;
20668
21414
  indexer;
20669
21415
  virtualTxRepository;
21416
+ onExitObserved;
20670
21417
  /** Create an unroll session by loading the virtual output chain from the indexer. */
20671
- static async create(toUnroll, bumper, explorer, indexer, virtualTxRepository) {
21418
+ static async create(toUnroll, bumper, explorer, indexer, virtualTxRepository, onExitObserved) {
20672
21419
  const { chain } = await indexer.getVtxoChain(toUnroll);
20673
21420
  return new Session2(
20674
21421
  { ...toUnroll, chain },
20675
21422
  bumper,
20676
21423
  explorer,
20677
21424
  indexer,
20678
- virtualTxRepository
21425
+ virtualTxRepository,
21426
+ onExitObserved
20679
21427
  );
20680
21428
  }
20681
21429
  /**
@@ -20711,6 +21459,14 @@ exports.Unroll = void 0;
20711
21459
  }
20712
21460
  /**
20713
21461
  * Get the next step to be executed
21462
+ *
21463
+ * @remarks
21464
+ * `do()` is the step, not a formality: every effect lives there, and at
21465
+ * `StepType.DONE` that includes firing {@link onExitObserved}. A caller
21466
+ * driving `next()` by hand must always await it — the async iterator
21467
+ * below does. Reading `type` and skipping `do()` leaves the exit
21468
+ * unobserved, and on the other step kinds unbroadcast.
21469
+ *
20714
21470
  * @returns The next step to be executed + the function to execute it
20715
21471
  */
20716
21472
  async next() {
@@ -20739,7 +21495,12 @@ exports.Unroll = void 0;
20739
21495
  return {
20740
21496
  type: 2 /* DONE */,
20741
21497
  vtxoTxid: this.toUnroll.txid,
20742
- do: () => Promise.resolve()
21498
+ // The observation rides on `do` rather than the iterator so
21499
+ // a caller driving `next()` by hand fires it too.
21500
+ do: () => notifyExitObserved(this.onExitObserved, {
21501
+ txid: this.toUnroll.txid,
21502
+ vout: this.toUnroll.vout
21503
+ })
20743
21504
  };
20744
21505
  }
20745
21506
  const virtualTxBase64 = await this.resolveVirtualTxBase64(nextTxToBroadcast);
@@ -20773,9 +21534,22 @@ exports.Unroll = void 0;
20773
21534
  }
20774
21535
  }
20775
21536
  Unroll2.Session = Session2;
21537
+ async function sessionFor(wallet, toUnroll, bumper) {
21538
+ const manager = await wallet.getContractManager();
21539
+ return Session2.create(
21540
+ toUnroll,
21541
+ bumper,
21542
+ wallet.onchainProvider,
21543
+ wallet.indexerProvider,
21544
+ wallet.virtualTxRepository,
21545
+ exitObserverFor(manager)
21546
+ );
21547
+ }
21548
+ Unroll2.sessionFor = sessionFor;
20776
21549
  async function completeUnroll(wallet, vtxoTxids, outputAddress) {
20777
21550
  const signedTx = await prepareUnrollTransaction(wallet, vtxoTxids, outputAddress);
20778
21551
  await wallet.onchainProvider.broadcastTransaction(signedTx.hex);
21552
+ await refreshSpentExitOutputs(wallet, signedTx);
20779
21553
  return signedTx.id;
20780
21554
  }
20781
21555
  Unroll2.completeUnroll = completeUnroll;
@@ -20791,9 +21565,9 @@ async function prepareUnrollTransaction(wallet, vtxoTxIds, outputAddress) {
20791
21565
  let totalAmount = 0n;
20792
21566
  const txWeightEstimator = TxWeightEstimator.create();
20793
21567
  for (const vtxo of vtxos) {
20794
- if (!vtxo.isUnrolled) {
21568
+ if (!chunkEJOFL5WH_cjs.canSweepOnchain(vtxo)) {
20795
21569
  throw new Error(
20796
- `Vtxo ${vtxo.txid}:${vtxo.vout} is not fully unrolled, use unroll first`
21570
+ `Vtxo ${vtxo.txid}:${vtxo.vout} cannot be swept onchain: it is not fully unrolled (use unroll first), or its exit output was already spent`
20797
21571
  );
20798
21572
  }
20799
21573
  const txStatus = await wallet.onchainProvider.getTxStatus(vtxo.txid);
@@ -20802,14 +21576,14 @@ async function prepareUnrollTransaction(wallet, vtxoTxIds, outputAddress) {
20802
21576
  }
20803
21577
  const resolved = await resolveUnilateralPath({
20804
21578
  vtxo,
20805
- scriptHex: base.hex.encode(chunkZIRFXBKL_cjs.VtxoScript.decode(vtxo.tapTree).pkScript),
21579
+ scriptHex: base.hex.encode(chunkEJOFL5WH_cjs.VtxoScript.decode(vtxo.tapTree).pkScript),
20806
21580
  contractRepository: wallet.contractRepository,
20807
21581
  walletPubKeyHex: base.hex.encode(await wallet.identity.xOnlyPublicKey()),
20808
21582
  currentTime: Date.now()
20809
21583
  });
20810
21584
  const spendingLeaf = resolved.selection.leaf;
20811
21585
  const sequence = resolved.selection.sequence;
20812
- const timelock = chunkZIRFXBKL_cjs.sequenceToTimelock(sequence);
21586
+ const timelock = chunkEJOFL5WH_cjs.sequenceToTimelock(sequence);
20813
21587
  const elapsed = timelock.type === "blocks" ? chainTip.height >= txStatus.blockHeight + Number(timelock.value) : chainTip.time >= txStatus.blockTime + Number(timelock.value);
20814
21588
  if (!elapsed) {
20815
21589
  throw new Error(`no available exit path found for vtxo ${vtxo.txid}:${vtxo.vout}`);
@@ -20822,7 +21596,7 @@ async function prepareUnrollTransaction(wallet, vtxoTxIds, outputAddress) {
20822
21596
  sequence,
20823
21597
  witnessUtxo: {
20824
21598
  amount: BigInt(vtxo.value),
20825
- script: chunkZIRFXBKL_cjs.VtxoScript.decode(vtxo.tapTree).pkScript
21599
+ script: chunkEJOFL5WH_cjs.VtxoScript.decode(vtxo.tapTree).pkScript
20826
21600
  },
20827
21601
  sighashType: btcSigner.SigHash.DEFAULT
20828
21602
  });
@@ -20832,7 +21606,7 @@ async function prepareUnrollTransaction(wallet, vtxoTxIds, outputAddress) {
20832
21606
  btcSigner.TaprootControlBlock.encode(spendingLeaf[0]).length
20833
21607
  );
20834
21608
  }
20835
- const tx = new chunkZIRFXBKL_cjs.Transaction({ version: 2 });
21609
+ const tx = new chunkEJOFL5WH_cjs.Transaction({ version: 2 });
20836
21610
  for (const input of inputs) {
20837
21611
  tx.addInput(input);
20838
21612
  }
@@ -20854,6 +21628,22 @@ async function prepareUnrollTransaction(wallet, vtxoTxIds, outputAddress) {
20854
21628
  signedTx.finalize();
20855
21629
  return signedTx;
20856
21630
  }
21631
+ async function refreshSpentExitOutputs(wallet, signedTx) {
21632
+ const outpoints = [];
21633
+ for (let i = 0; i < signedTx.inputsLength; i++) {
21634
+ const input = signedTx.getInput(i);
21635
+ if (input.txid && input.index !== void 0) {
21636
+ outpoints.push({ txid: base.hex.encode(input.txid), vout: input.index });
21637
+ }
21638
+ }
21639
+ if (outpoints.length === 0) return;
21640
+ try {
21641
+ const manager = await wallet.getContractManager();
21642
+ await manager.refreshOutpoints(outpoints);
21643
+ } catch (e) {
21644
+ console.error("completeUnroll: failed to refresh the spent exit outputs", e);
21645
+ }
21646
+ }
20857
21647
  function sleep2(ms) {
20858
21648
  return new Promise((resolve) => setTimeout(resolve, ms));
20859
21649
  }
@@ -20899,7 +21689,7 @@ async function buildSignedSweep(params) {
20899
21689
  `uneconomic vtxo ${vtxo.txid}:${vtxo.vout}: value ${vtxo.value} - fee ${fee} < dust`
20900
21690
  );
20901
21691
  }
20902
- const tx = new chunkZIRFXBKL_cjs.Transaction({ version: 2 });
21692
+ const tx = new chunkEJOFL5WH_cjs.Transaction({ version: 2 });
20903
21693
  tx.addInput({
20904
21694
  txid: vtxo.txid,
20905
21695
  index: vtxo.vout,
@@ -20924,7 +21714,7 @@ async function buildSignedSweep(params) {
20924
21714
  finalScriptWitness: [
20925
21715
  tapScriptSig[0][1],
20926
21716
  ...path.extraWitness,
20927
- chunkZIRFXBKL_cjs.scriptFromTapLeafScript(path.leaf),
21717
+ chunkEJOFL5WH_cjs.scriptFromTapLeafScript(path.leaf),
20928
21718
  btcSigner.TaprootControlBlock.encode(controlBlock)
20929
21719
  ]
20930
21720
  });
@@ -20932,7 +21722,7 @@ async function buildSignedSweep(params) {
20932
21722
  }
20933
21723
 
20934
21724
  // src/wallet/exit/estimate.ts
20935
- var CHILD_OUTPUT_DUST = 546;
21725
+ var CHILD_OUTPUT_DUST = CHILD_DUST_AMOUNT;
20936
21726
  function stepFundingAmount(stepFee) {
20937
21727
  return stepFee + CHILD_OUTPUT_DUST;
20938
21728
  }
@@ -20954,7 +21744,7 @@ async function resolveFeeRate(opts) {
20954
21744
  }
20955
21745
  async function selectExitVtxos(opts) {
20956
21746
  if (!opts.vtxos) return opts.wallet.getVtxos();
20957
- const res = await chunkZIRFXBKL_cjs.getNormalizedVtxos(opts.wallet.indexerProvider, { outpoints: opts.vtxos });
21747
+ const res = await chunkEJOFL5WH_cjs.getNormalizedVtxos(opts.wallet.indexerProvider, { outpoints: opts.vtxos });
20958
21748
  const tapTrees = /* @__PURE__ */ new Map();
20959
21749
  const out = [];
20960
21750
  for (const vtxo of res.vtxos) {
@@ -20969,7 +21759,7 @@ async function selectExitVtxos(opts) {
20969
21759
  `no contract registered for vtxo script ${vtxo.script} \u2014 register the contract before exiting`
20970
21760
  );
20971
21761
  }
20972
- const handler = chunkPXPPZF5K_cjs.contractHandlers.get(contract.type);
21762
+ const handler = chunk6YUACVX4_cjs.contractHandlers.get(contract.type);
20973
21763
  if (!handler) {
20974
21764
  throw new Error(`no contract handler registered for type '${contract.type}'`);
20975
21765
  }
@@ -20999,7 +21789,7 @@ async function computeExitLayout(opts, feeRate) {
20999
21789
  if (pendingNodes.length > 0) {
21000
21790
  const txs = await resolver.getVirtualTxs(pendingNodes.map((n) => n.txid));
21001
21791
  for (const psbt of txs) {
21002
- psbts.set(chunkZIRFXBKL_cjs.Transaction.fromPSBT(base.base64.decode(psbt)).id, psbt);
21792
+ psbts.set(chunkEJOFL5WH_cjs.Transaction.fromPSBT(base.base64.decode(psbt)).id, psbt);
21003
21793
  }
21004
21794
  }
21005
21795
  const childVsize = Number(
@@ -21035,7 +21825,7 @@ async function computeExitLayout(opts, feeRate) {
21035
21825
  try {
21036
21826
  const resolved = await resolveUnilateralPath({
21037
21827
  vtxo,
21038
- scriptHex: base.hex.encode(chunkZIRFXBKL_cjs.VtxoScript.decode(vtxo.tapTree).pkScript),
21828
+ scriptHex: base.hex.encode(chunkEJOFL5WH_cjs.VtxoScript.decode(vtxo.tapTree).pkScript),
21039
21829
  contractRepository: wallet.contractRepository,
21040
21830
  walletPubKeyHex,
21041
21831
  currentTime: Date.now()
@@ -21054,7 +21844,7 @@ async function computeExitLayout(opts, feeRate) {
21054
21844
  });
21055
21845
  continue;
21056
21846
  }
21057
- const t = chunkZIRFXBKL_cjs.sequenceToTimelock(resolved.selection.sequence);
21847
+ const t = chunkEJOFL5WH_cjs.sequenceToTimelock(resolved.selection.sequence);
21058
21848
  const delay = { type: t.type, value: Number(t.value) };
21059
21849
  infos.push({ outpoint, value: vtxo.value, sweepFee, path: resolved.label, delay });
21060
21850
  sweeps.push({ vtxo, resolved, sweepFee, delay });
@@ -21093,10 +21883,18 @@ async function computeExitLayout(opts, feeRate) {
21093
21883
  // splitter. funded: + 1 splitter tx and pre-signed children.
21094
21884
  txCount: (graph ? 0 : steps.length > 0 ? 1 : 0) + steps.length * 2 + sweeps.length,
21095
21885
  totalFeeSats: splitterFee + stepFees + sweepFees,
21096
- // graph funding is what the executor sends to its own fee address:
21097
- // just the CPFP fees (change recycles); funded also locks the
21098
- // per-child dust into the splitter.
21099
- fundingRequiredSats: graph ? stepFees : splitterFee + fundingTotal,
21886
+ // graph funding is what the executor sends to its own fee address: the
21887
+ // CPFP fees, plus one dust floor. Change recycles through that single
21888
+ // address, so each bump hands its remainder to the next and only the
21889
+ // *final* change has to clear `CHILD_DUST_AMOUNT` — but it does have to,
21890
+ // and `buildAnchorChild` throws rather than absorbing a short remainder
21891
+ // into the fee. Quoting bare fees quotes an amount that strands the last
21892
+ // bump and every sweep behind it.
21893
+ //
21894
+ // funded reserves the same floor per step instead of once overall (see
21895
+ // `stepFundingAmount`), because it pre-funds each child separately
21896
+ // through the splitter rather than recycling one output.
21897
+ fundingRequiredSats: graph ? steps.length > 0 ? stepFees + CHILD_OUTPUT_DUST : 0 : splitterFee + fundingTotal,
21100
21898
  recoveredSats: sweeps.reduce((s, x) => s + (x.vtxo.value - x.sweepFee), 0)
21101
21899
  };
21102
21900
  const expiries = pendingNodes.map((n) => n.expiresAt).filter((x) => x !== void 0);
@@ -21156,12 +21954,32 @@ var Executor = class {
21156
21954
  this.pollIntervalMs = opts?.pollIntervalMs ?? 5e3;
21157
21955
  this.feeWallet = opts?.feeWallet;
21158
21956
  this.signal = opts?.signal;
21957
+ this.onExitObserved = opts?.onExitObserved;
21159
21958
  }
21160
21959
  pkg;
21161
21960
  provider;
21162
21961
  pollIntervalMs;
21163
21962
  feeWallet;
21164
21963
  signal;
21964
+ onExitObserved;
21965
+ /**
21966
+ * Per-VTXO branch progress, which the executor otherwise does not track:
21967
+ * `dead` / `done` are per-step, and a VTXO is only onchain once EVERY
21968
+ * `package`/`bump` step naming it has confirmed. (`broadcast` — the funding
21969
+ * splitter — carries no `forVtxos` and serves no single VTXO.)
21970
+ */
21971
+ branchSteps() {
21972
+ const byVtxo = /* @__PURE__ */ new Map();
21973
+ this.pkg.steps.forEach((step, i) => {
21974
+ if (step.kind !== "package" && step.kind !== "bump") return;
21975
+ for (const vtxo of step.forVtxos) {
21976
+ let steps = byVtxo.get(vtxo);
21977
+ if (!steps) byVtxo.set(vtxo, steps = /* @__PURE__ */ new Set());
21978
+ steps.add(i);
21979
+ }
21980
+ });
21981
+ return byVtxo;
21982
+ }
21165
21983
  /**
21166
21984
  * Poll delay. Nearly all wall-clock time is spent here, so it must be the
21167
21985
  * thing that reacts to abort — checking only between polls would leave
@@ -21201,6 +22019,19 @@ var Executor = class {
21201
22019
  async *[Symbol.asyncIterator]() {
21202
22020
  throwIfAborted(this.signal);
21203
22021
  const dead = /* @__PURE__ */ new Set();
22022
+ const branchSteps = this.branchSteps();
22023
+ const onchainSteps = /* @__PURE__ */ new Set();
22024
+ const branchObserved = /* @__PURE__ */ new Set();
22025
+ const observeBranch = async (stepIndex, forVtxos) => {
22026
+ onchainSteps.add(stepIndex);
22027
+ for (const vtxo of forVtxos ?? []) {
22028
+ if (branchObserved.has(vtxo)) continue;
22029
+ const steps = branchSteps.get(vtxo);
22030
+ if (!steps || ![...steps].every((i) => onchainSteps.has(i))) continue;
22031
+ branchObserved.add(vtxo);
22032
+ await this.observe(vtxo);
22033
+ }
22034
+ };
21204
22035
  if (this.pkg.validUntil && Date.now() / 1e3 > this.pkg.validUntil) {
21205
22036
  yield {
21206
22037
  stepIndex: -1,
@@ -21230,6 +22061,7 @@ var Executor = class {
21230
22061
  const anchorTxid = step.kind === "package" || step.kind === "bump" ? step.parentTxid : step.txid;
21231
22062
  const existing = await this.status(anchorTxid);
21232
22063
  if (existing?.confirmed) {
22064
+ await observeBranch(i, forVtxos);
21233
22065
  yield {
21234
22066
  stepIndex: i,
21235
22067
  kind: step.kind,
@@ -21285,6 +22117,7 @@ var Executor = class {
21285
22117
  }
21286
22118
  }
21287
22119
  await this.waitConfirmed(anchorTxid);
22120
+ await observeBranch(i, forVtxos);
21288
22121
  yield {
21289
22122
  stepIndex: i,
21290
22123
  kind: step.kind,
@@ -21315,6 +22148,7 @@ var Executor = class {
21315
22148
  const swept = await this.status(step.txid);
21316
22149
  if (swept?.confirmed) {
21317
22150
  done.add(index);
22151
+ await this.observe(step.vtxo);
21318
22152
  yield {
21319
22153
  stepIndex: index,
21320
22154
  kind: "sweep",
@@ -21371,7 +22205,25 @@ var Executor = class {
21371
22205
  if (done.size < pending.length) await this.sleep();
21372
22206
  }
21373
22207
  }
22208
+ /** `"txid:vout"` -> outpoint, then hand it to the hook. A malformed entry is skipped. */
22209
+ async observe(outpoint) {
22210
+ if (!this.onExitObserved) return;
22211
+ const sep = outpoint.lastIndexOf(":");
22212
+ const rest = outpoint.slice(sep + 1);
22213
+ const vout = Number(rest);
22214
+ if (sep <= 0 || rest === "" || !Number.isInteger(vout)) return;
22215
+ await notifyExitObserved(this.onExitObserved, { txid: outpoint.slice(0, sep), vout });
22216
+ }
21374
22217
  };
22218
+
22219
+ // src/wallet/exit/execute.ts
22220
+ async function execute(wallet, pkg, opts) {
22221
+ const manager = await wallet.getContractManager();
22222
+ return new Executor(pkg, opts?.provider ?? wallet.onchainProvider, {
22223
+ ...opts,
22224
+ onExitObserved: opts?.onExitObserved ?? exitObserverFor(manager)
22225
+ });
22226
+ }
21375
22227
  async function prepare(opts) {
21376
22228
  const { wallet, onchainWallet } = opts;
21377
22229
  const feeRate = await resolveFeeRate(opts);
@@ -21393,7 +22245,7 @@ async function prepare(opts) {
21393
22245
  txid: sweep.vtxo.txid,
21394
22246
  vout: sweep.vtxo.vout,
21395
22247
  value: sweep.vtxo.value,
21396
- pkScript: chunkZIRFXBKL_cjs.VtxoScript.decode(sweep.vtxo.tapTree).pkScript
22248
+ pkScript: chunkEJOFL5WH_cjs.VtxoScript.decode(sweep.vtxo.tapTree).pkScript
21397
22249
  },
21398
22250
  path: sweep.resolved.selection,
21399
22251
  outputAddress: opts.sweepAddress,
@@ -21446,7 +22298,10 @@ async function prepare(opts) {
21446
22298
  totals: {
21447
22299
  txCount: bumpSteps.length * 2 + sweepSteps.length,
21448
22300
  totalFeeSats: stepFees2 + sweepFees2,
21449
- fundingRequiredSats: stepFees2,
22301
+ // Fees plus the single dust floor the recycling change output
22302
+ // must keep clear; see the note in `estimate.ts`. Must match
22303
+ // the quote `estimate` gives for the same package.
22304
+ fundingRequiredSats: bumpSteps.length > 0 ? stepFees2 + CHILD_OUTPUT_DUST : 0,
21450
22305
  recoveredSats: recovered2
21451
22306
  },
21452
22307
  vtxos: layout.infos,
@@ -21478,7 +22333,7 @@ async function prepare(opts) {
21478
22333
  if (newFee <= splitterFee) break;
21479
22334
  splitterFee = newFee;
21480
22335
  }
21481
- const splitter = new chunkZIRFXBKL_cjs.Transaction({ version: 2 });
22336
+ const splitter = new chunkEJOFL5WH_cjs.Transaction({ version: 2 });
21482
22337
  for (const coin of selected.inputs) {
21483
22338
  splitter.addInput({
21484
22339
  txid: coin.txid,
@@ -21615,47 +22470,48 @@ function isValidStep(step) {
21615
22470
  var UnilateralExit = {
21616
22471
  estimate,
21617
22472
  prepare,
22473
+ execute,
21618
22474
  Executor
21619
22475
  };
21620
22476
 
21621
22477
  // src/arkade/index.ts
21622
22478
  var arkade_exports = {};
21623
22479
  chunk5BLDMQED_cjs.__export(arkade_exports, {
21624
- ARKADE_OP: () => chunkPXPPZF5K_cjs.ARKADE_OP,
21625
- ARKADE_OPCODES: () => chunkPXPPZF5K_cjs.ARKADE_OPCODES,
21626
- ARKADE_OPCODE_NAMES: () => chunkPXPPZF5K_cjs.ARKADE_OPCODE_NAMES,
21627
- ARKADE_OPCODE_VALUES: () => chunkPXPPZF5K_cjs.ARKADE_OPCODE_VALUES,
21628
- ARKADE_OPS: () => chunkPXPPZF5K_cjs.ARKADE_OPS,
22480
+ ARKADE_OP: () => chunk6YUACVX4_cjs.ARKADE_OP,
22481
+ ARKADE_OPCODES: () => chunk6YUACVX4_cjs.ARKADE_OPCODES,
22482
+ ARKADE_OPCODE_NAMES: () => chunk6YUACVX4_cjs.ARKADE_OPCODE_NAMES,
22483
+ ARKADE_OPCODE_VALUES: () => chunk6YUACVX4_cjs.ARKADE_OPCODE_VALUES,
22484
+ ARKADE_OPS: () => chunk6YUACVX4_cjs.ARKADE_OPS,
21629
22485
  Arkade: () => Arkade,
21630
22486
  ArkadeContract: () => ArkadeContract,
21631
- ArkadeProgramScript: () => chunkPXPPZF5K_cjs.ArkadeProgramScript,
21632
- ArkadeScript: () => chunkPXPPZF5K_cjs.ArkadeScript,
22487
+ ArkadeProgramScript: () => chunk6YUACVX4_cjs.ArkadeProgramScript,
22488
+ ArkadeScript: () => chunk6YUACVX4_cjs.ArkadeScript,
21633
22489
  ArkadeTransactionBuilder: () => ArkadeTransactionBuilder,
21634
- BigNum: () => chunkPXPPZF5K_cjs.bignum_exports,
22490
+ BigNum: () => chunk6YUACVX4_cjs.bignum_exports,
21635
22491
  OP: () => btcSigner.OP,
21636
- OPCODE_NAMES: () => chunkPXPPZF5K_cjs.OPCODE_NAMES,
21637
- OPCODE_VALUES: () => chunkPXPPZF5K_cjs.OPCODE_VALUES,
21638
- SUPPORTED_PROGRAM_VERSION: () => chunkPXPPZF5K_cjs.SUPPORTED_PROGRAM_VERSION,
22492
+ OPCODE_NAMES: () => chunk6YUACVX4_cjs.OPCODE_NAMES,
22493
+ OPCODE_VALUES: () => chunk6YUACVX4_cjs.OPCODE_VALUES,
22494
+ SUPPORTED_PROGRAM_VERSION: () => chunk6YUACVX4_cjs.SUPPORTED_PROGRAM_VERSION,
21639
22495
  Script: () => btcSigner.Script,
21640
- arkadeScriptHash: () => chunkPXPPZF5K_cjs.arkadeScriptHash,
21641
- arkadeWitnessHash: () => chunkPXPPZF5K_cjs.arkadeWitnessHash,
21642
- asmToBytes: () => chunkPXPPZF5K_cjs.asmToBytes,
21643
- bytesToASM: () => chunkPXPPZF5K_cjs.bytesToASM,
21644
- computeArkadeScriptPublicKey: () => chunkPXPPZF5K_cjs.computeArkadeScriptPublicKey,
22496
+ arkadeScriptHash: () => chunk6YUACVX4_cjs.arkadeScriptHash,
22497
+ arkadeWitnessHash: () => chunk6YUACVX4_cjs.arkadeWitnessHash,
22498
+ asmToBytes: () => chunk6YUACVX4_cjs.asmToBytes,
22499
+ bytesToASM: () => chunk6YUACVX4_cjs.bytesToASM,
22500
+ computeArkadeScriptPublicKey: () => chunk6YUACVX4_cjs.computeArkadeScriptPublicKey,
21645
22501
  createArkadeBatchHandler: () => createArkadeBatchHandler,
21646
- deserializeArkadeContractParams: () => chunkPXPPZF5K_cjs.deserializeArkadeContractParams,
21647
- fromASM: () => chunkPXPPZF5K_cjs.fromASM,
21648
- getOpcodeName: () => chunkPXPPZF5K_cjs.getOpcodeName,
21649
- getOpcodeValue: () => chunkPXPPZF5K_cjs.getOpcodeValue,
21650
- parseArtifact: () => chunkPXPPZF5K_cjs.parseArtifact,
21651
- resolveAsm: () => chunkPXPPZF5K_cjs.resolveAsm,
21652
- serializeArkadeContractParams: () => chunkPXPPZF5K_cjs.serializeArkadeContractParams,
21653
- stringifyArtifact: () => chunkPXPPZF5K_cjs.stringifyArtifact,
21654
- toASM: () => chunkPXPPZF5K_cjs.toASM,
21655
- validateProgram: () => chunkPXPPZF5K_cjs.validateProgram,
21656
- witnessRefToBytes: () => chunkPXPPZF5K_cjs.witnessRefToBytes
22502
+ deserializeArkadeContractParams: () => chunk6YUACVX4_cjs.deserializeArkadeContractParams,
22503
+ fromASM: () => chunk6YUACVX4_cjs.fromASM,
22504
+ getOpcodeName: () => chunk6YUACVX4_cjs.getOpcodeName,
22505
+ getOpcodeValue: () => chunk6YUACVX4_cjs.getOpcodeValue,
22506
+ parseArtifact: () => chunk6YUACVX4_cjs.parseArtifact,
22507
+ resolveAsm: () => chunk6YUACVX4_cjs.resolveAsm,
22508
+ serializeArkadeContractParams: () => chunk6YUACVX4_cjs.serializeArkadeContractParams,
22509
+ stringifyArtifact: () => chunk6YUACVX4_cjs.stringifyArtifact,
22510
+ toASM: () => chunk6YUACVX4_cjs.toASM,
22511
+ validateProgram: () => chunk6YUACVX4_cjs.validateProgram,
22512
+ witnessRefToBytes: () => chunk6YUACVX4_cjs.witnessRefToBytes
21657
22513
  });
21658
- var isVtxoCoin = (input) => chunkZIRFXBKL_cjs.isVirtualCoin(input);
22514
+ var isVtxoCoin = (input) => chunkEJOFL5WH_cjs.isVirtualCoin(input);
21659
22515
  function createArkadeBatchHandler(intentId, inputs, signer, signedProof, message, session, arkProvider, emulator, network, recipients, batchExpiryPolicy) {
21660
22516
  let batchId;
21661
22517
  let sweepTapTreeRoot;
@@ -21676,23 +22532,23 @@ function createArkadeBatchHandler(intentId, inputs, signer, signedProof, message
21676
22532
  );
21677
22533
  await arkProvider.confirmRegistration(intentId);
21678
22534
  batchId = event.id;
21679
- const sweepTapscript = chunkZIRFXBKL_cjs.CSVMultisigTapscript.encode({
22535
+ const sweepTapscript = chunkEJOFL5WH_cjs.CSVMultisigTapscript.encode({
21680
22536
  timelock,
21681
- pubkeys: [chunkPXPPZF5K_cjs.toXOnly(base.hex.decode(info.forfeitPubkey), "forfeit key")]
22537
+ pubkeys: [chunk6YUACVX4_cjs.toXOnly(base.hex.decode(info.forfeitPubkey), "forfeit key")]
21682
22538
  }).script;
21683
22539
  sweepTapTreeRoot = payment_js.tapLeafHash(sweepTapscript);
21684
22540
  return { skip: false };
21685
22541
  },
21686
22542
  onTreeSigningStarted: async (event, vtxoTree) => {
21687
22543
  const signerPubKey = await session.getPublicKey();
21688
- const xonlySignerPubKey = chunkPXPPZF5K_cjs.toXOnly(signerPubKey, "signer key");
22544
+ const xonlySignerPubKey = chunk6YUACVX4_cjs.toXOnly(signerPubKey, "signer key");
21689
22545
  const xOnlyPubkeys = event.cosignersPublicKeys.map(
21690
- (k) => base.hex.encode(chunkPXPPZF5K_cjs.toXOnly(base.hex.decode(k), "cosigner key"))
22546
+ (k) => base.hex.encode(chunk6YUACVX4_cjs.toXOnly(base.hex.decode(k), "cosigner key"))
21691
22547
  );
21692
22548
  if (!xOnlyPubkeys.includes(base.hex.encode(xonlySignerPubKey))) {
21693
22549
  return { skip: true };
21694
22550
  }
21695
- const commitmentTx = chunkZIRFXBKL_cjs.Transaction.fromPSBT(base.base64.decode(event.unsignedCommitmentTx));
22551
+ const commitmentTx = chunkEJOFL5WH_cjs.Transaction.fromPSBT(base.base64.decode(event.unsignedCommitmentTx));
21696
22552
  validateVtxoTxGraph(vtxoTree, commitmentTx, sweepTapTreeRoot);
21697
22553
  if (recipients && recipients.length > 0) {
21698
22554
  validateBatchRecipients(commitmentTx, vtxoTree.leaves(), recipients, network);
@@ -21724,7 +22580,7 @@ function createArkadeBatchHandler(intentId, inputs, signer, signedProof, message
21724
22580
  if (connectorTree) {
21725
22581
  validateConnectorsTxGraph(event.commitmentTx, connectorTree);
21726
22582
  }
21727
- let commitmentPsbt = chunkZIRFXBKL_cjs.Transaction.fromPSBT(base.base64.decode(event.commitmentTx));
22583
+ let commitmentPsbt = chunkEJOFL5WH_cjs.Transaction.fromPSBT(base.base64.decode(event.commitmentTx));
21728
22584
  assertFinalCommitmentMatchesValidated(
21729
22585
  commitmentPsbt,
21730
22586
  validatedCommitmentTxid,
@@ -21759,7 +22615,7 @@ function createArkadeBatchHandler(intentId, inputs, signer, signedProof, message
21759
22615
  boardingIndices.push(boardingIdx);
21760
22616
  continue;
21761
22617
  }
21762
- if (chunkZIRFXBKL_cjs.isRecoverable(input) || isSubdust(input, info.dust)) {
22618
+ if (chunkEJOFL5WH_cjs.isRecoverable(input) || isSubdust(input, info.dust)) {
21763
22619
  continue;
21764
22620
  }
21765
22621
  if (connectorIndex >= connectorLeaves.length) {
@@ -21780,7 +22636,7 @@ function createArkadeBatchHandler(intentId, inputs, signer, signedProof, message
21780
22636
  index: input.vout,
21781
22637
  witnessUtxo: {
21782
22638
  amount: BigInt(input.value),
21783
- script: chunkZIRFXBKL_cjs.VtxoScript.decode(input.tapTree).pkScript
22639
+ script: chunkEJOFL5WH_cjs.VtxoScript.decode(input.tapTree).pkScript
21784
22640
  },
21785
22641
  sighashType: btcSigner.SigHash.DEFAULT,
21786
22642
  tapLeafScript: [input.forfeitTapLeafScript]
@@ -21871,16 +22727,16 @@ var Arkade = class _Arkade {
21871
22727
  /** Connect and resolve the server key, checkpoint closure and (if present) the co-signer key. */
21872
22728
  static async connect(opts) {
21873
22729
  const info = await opts.arkade.getInfo();
21874
- const serverKey = chunkPXPPZF5K_cjs.toXOnly(base.hex.decode(info.signerPubkey), "ark signer key");
21875
- const checkpoint = chunkZIRFXBKL_cjs.CSVMultisigTapscript.decode(base.hex.decode(info.checkpointTapscript));
21876
- const network = opts.network ?? chunkZIRFXBKL_cjs.DEFAULT_NETWORK;
22730
+ const serverKey = chunk6YUACVX4_cjs.toXOnly(base.hex.decode(info.signerPubkey), "ark signer key");
22731
+ const checkpoint = chunkEJOFL5WH_cjs.CSVMultisigTapscript.decode(base.hex.decode(info.checkpointTapscript));
22732
+ const network = opts.network ?? chunkEJOFL5WH_cjs.DEFAULT_NETWORK;
21877
22733
  let emulatorKey;
21878
22734
  if (opts.emulator) {
21879
- emulatorKey = base.hex.decode(chunkZIRFXBKL_cjs.resolveEmulatorPubkey(network, opts.emulatorPubkey));
22735
+ emulatorKey = base.hex.decode(chunkEJOFL5WH_cjs.resolveEmulatorPubkey(network, opts.emulatorPubkey));
21880
22736
  }
21881
22737
  let userKey;
21882
22738
  if (opts.identity) {
21883
- userKey = chunkPXPPZF5K_cjs.toXOnly(await opts.identity.xOnlyPublicKey(), "identity key");
22739
+ userKey = chunk6YUACVX4_cjs.toXOnly(await opts.identity.xOnlyPublicKey(), "identity key");
21884
22740
  }
21885
22741
  return new _Arkade({
21886
22742
  arkProvider: opts.arkade,
@@ -21906,7 +22762,7 @@ var Arkade = class _Arkade {
21906
22762
  * key respectively; explicit args always win.
21907
22763
  */
21908
22764
  contract(program, args = {}) {
21909
- const declared = (program.params ?? []).map(chunkPXPPZF5K_cjs.inputName);
22765
+ const declared = (program.params ?? []).map(chunk6YUACVX4_cjs.inputName);
21910
22766
  if (declared.includes("server") && args.server === void 0) {
21911
22767
  args = { ...args, server: this.serverKey };
21912
22768
  }
@@ -21926,7 +22782,7 @@ var ArkadeContract = class _ArkadeContract {
21926
22782
  userKey: client.userKey,
21927
22783
  emulatorKey: client.emulatorKey
21928
22784
  };
21929
- this.vtxoScript = new chunkPXPPZF5K_cjs.ArkadeProgramScript(program, args, this.keys);
22785
+ this.vtxoScript = new chunk6YUACVX4_cjs.ArkadeProgramScript(program, args, this.keys);
21930
22786
  this.tapTree = this.vtxoScript.encode();
21931
22787
  this.compiled = this.vtxoScript.compiled;
21932
22788
  }
@@ -21954,7 +22810,7 @@ var ArkadeContract = class _ArkadeContract {
21954
22810
  `ArkadeContract.fromContract: expected contract type 'arkade', got '${contract.type}'`
21955
22811
  );
21956
22812
  }
21957
- const typed = chunkPXPPZF5K_cjs.deserializeArkadeContractParams(contract.params);
22813
+ const typed = chunk6YUACVX4_cjs.deserializeArkadeContractParams(contract.params);
21958
22814
  return new _ArkadeContract(client, typed.program, typed.args, {
21959
22815
  serverKey: typed.serverKey,
21960
22816
  userKey: typed.userKey,
@@ -21995,7 +22851,7 @@ var ArkadeContract = class _ArkadeContract {
21995
22851
  toContractParams() {
21996
22852
  return {
21997
22853
  type: "arkade",
21998
- params: chunkPXPPZF5K_cjs.serializeArkadeContractParams({
22854
+ params: chunk6YUACVX4_cjs.serializeArkadeContractParams({
21999
22855
  program: this.program,
22000
22856
  args: this.args,
22001
22857
  serverKey: this.keys.serverKey,
@@ -22032,6 +22888,10 @@ var ArkadeContract = class _ArkadeContract {
22032
22888
  * When a `contractManager` is configured and this contract is registered,
22033
22889
  * reads the repository-backed state (offline-first, kept fresh by the
22034
22890
  * contract watcher). Otherwise falls back to a direct indexer query.
22891
+ *
22892
+ * Both branches refuse a spent or unilaterally exited output. They are not
22893
+ * otherwise interchangeable: the fallback asks `spendableOnly`, which also
22894
+ * drops swept coins — the manager branch keeps those.
22035
22895
  */
22036
22896
  async getUtxos() {
22037
22897
  const manager = this.client.contractManager;
@@ -22040,17 +22900,19 @@ var ArkadeContract = class _ArkadeContract {
22040
22900
  const [registered] = await manager.getContracts({ script: scriptHex });
22041
22901
  if (registered) {
22042
22902
  const [withVtxos] = await manager.getContractsWithVtxos({ script: scriptHex });
22043
- return (withVtxos?.vtxos ?? []).filter((v) => !chunkZIRFXBKL_cjs.hasTerminalSpend(v));
22903
+ return (withVtxos?.vtxos ?? []).filter(
22904
+ (v) => !chunkEJOFL5WH_cjs.hasTerminalSpend(v) && !v.isUnrolled
22905
+ );
22044
22906
  }
22045
22907
  }
22046
22908
  if (!this.client.indexer) {
22047
22909
  throw new Error("ArkadeContract.getUtxos: an indexer is required");
22048
22910
  }
22049
- const { vtxos } = await chunkZIRFXBKL_cjs.getNormalizedVtxos(this.client.indexer, {
22911
+ const { vtxos } = await chunkEJOFL5WH_cjs.getNormalizedVtxos(this.client.indexer, {
22050
22912
  scripts: [scriptHex],
22051
22913
  spendableOnly: true
22052
22914
  });
22053
- return vtxos;
22915
+ return vtxos.filter((v) => !chunkEJOFL5WH_cjs.hasTerminalSpend(v) && !v.isUnrolled);
22054
22916
  }
22055
22917
  /** Total spendable balance (requires an indexer). */
22056
22918
  async getBalance() {
@@ -22148,12 +23010,25 @@ var ArkadeTransactionBuilder = class {
22148
23010
  this.contract.client.checkpoint
22149
23011
  );
22150
23012
  if (coin.sourceTx) {
22151
- chunkZIRFXBKL_cjs.setArkPsbtField(arkTx, 0, chunkZIRFXBKL_cjs.PrevArkTxField, coin.sourceTx);
23013
+ chunkEJOFL5WH_cjs.setArkPsbtField(arkTx, 0, chunkEJOFL5WH_cjs.PrevArkTxField, coin.sourceTx);
23014
+ }
23015
+ if (this.fn.arkadeScript) {
23016
+ const indexer = this.contract.client.indexer;
23017
+ if (!indexer) {
23018
+ throw new PrevTxUnavailableError(
23019
+ "covenant spends require an `indexer` on the Arkade client to resolve the previous ark tx of each input"
23020
+ );
23021
+ }
23022
+ await attachPrevArkTxs(
23023
+ arkTx,
23024
+ [coin.txid, ...this.fundingCoins.map((c) => c.txid)],
23025
+ indexer
23026
+ );
22152
23027
  }
22153
23028
  const condition = (def.tapscript.witness ?? []).map((w) => this.witnessBytes(w));
22154
23029
  if (condition.length > 0) {
22155
- chunkZIRFXBKL_cjs.setArkPsbtField(arkTx, 0, chunkZIRFXBKL_cjs.ConditionWitness, condition);
22156
- chunkZIRFXBKL_cjs.setArkPsbtField(checkpoints[0], 0, chunkZIRFXBKL_cjs.ConditionWitness, condition);
23030
+ chunkEJOFL5WH_cjs.setArkPsbtField(arkTx, 0, chunkEJOFL5WH_cjs.ConditionWitness, condition);
23031
+ chunkEJOFL5WH_cjs.setArkPsbtField(checkpoints[0], 0, chunkEJOFL5WH_cjs.ConditionWitness, condition);
22157
23032
  }
22158
23033
  const packets = [];
22159
23034
  if (this.assetSpecs.length > 0) {
@@ -22192,7 +23067,7 @@ var ArkadeTransactionBuilder = class {
22192
23067
  base.base64.encode(signedArk2.toPSBT()),
22193
23068
  signedCps.map((c) => base.base64.encode(c.toPSBT()))
22194
23069
  );
22195
- const txid = chunkZIRFXBKL_cjs.Transaction.fromPSBT(base.base64.decode(res2.signedArkTx)).id;
23070
+ const txid = chunkEJOFL5WH_cjs.Transaction.fromPSBT(base.base64.decode(res2.signedArkTx)).id;
22196
23071
  return {
22197
23072
  txid,
22198
23073
  signedArkTx: res2.signedArkTx,
@@ -22251,23 +23126,23 @@ var ArkadeTransactionBuilder = class {
22251
23126
  }
22252
23127
  buildAssetPacket() {
22253
23128
  const groups = this.assetSpecs.map((s) => {
22254
- const id = typeof s.assetId === "string" ? chunk3S3JZUEN_cjs.AssetId.fromString(s.assetId) : chunk3S3JZUEN_cjs.AssetId.fromBytes(s.assetId);
22255
- return chunk3S3JZUEN_cjs.AssetGroup.create(
23129
+ const id = typeof s.assetId === "string" ? chunkPJR63FTK_cjs.AssetId.fromString(s.assetId) : chunkPJR63FTK_cjs.AssetId.fromBytes(s.assetId);
23130
+ return chunkPJR63FTK_cjs.AssetGroup.create(
22256
23131
  id,
22257
23132
  null,
22258
- s.inputs.map((i) => chunk3S3JZUEN_cjs.AssetInput.create(i.vin, i.amount)),
22259
- s.outputs.map((o) => chunk3S3JZUEN_cjs.AssetOutput.create(o.vout, o.amount)),
22260
- (s.metadata ?? []).map((m) => chunk3S3JZUEN_cjs.Metadata.create(m.key, m.value))
23133
+ s.inputs.map((i) => chunkPJR63FTK_cjs.AssetInput.create(i.vin, i.amount)),
23134
+ s.outputs.map((o) => chunkPJR63FTK_cjs.AssetOutput.create(o.vout, o.amount)),
23135
+ (s.metadata ?? []).map((m) => chunkPJR63FTK_cjs.Metadata.create(m.key, m.value))
22261
23136
  );
22262
23137
  });
22263
- return chunk3S3JZUEN_cjs.Packet.create(groups);
23138
+ return chunkPJR63FTK_cjs.Packet.create(groups);
22264
23139
  }
22265
23140
  witnessBytes(ref) {
22266
- return chunkPXPPZF5K_cjs.witnessRefToBytes(ref, this.args, this.contract.args);
23141
+ return chunk6YUACVX4_cjs.witnessRefToBytes(ref, this.args, this.contract.args);
22267
23142
  }
22268
23143
  };
22269
23144
  function bindInputs(fn, callArgs) {
22270
- const names = (fn.def.inputs ?? []).map(chunkPXPPZF5K_cjs.inputName);
23145
+ const names = (fn.def.inputs ?? []).map(chunk6YUACVX4_cjs.inputName);
22271
23146
  if (callArgs.length !== names.length) {
22272
23147
  throw new Error(`${fn.name}: expected ${names.length} argument(s), got ${callArgs.length}`);
22273
23148
  }
@@ -22667,6 +23542,7 @@ exports.AssetManager = AssetManager;
22667
23542
  exports.BIP21 = BIP21;
22668
23543
  exports.BIP21Error = BIP21Error;
22669
23544
  exports.BLOCKED_UPGRADE_TIMEOUT_MS = BLOCKED_UPGRADE_TIMEOUT_MS;
23545
+ exports.CachingArkProvider = CachingArkProvider;
22670
23546
  exports.ChainedTxType = ChainedTxType;
22671
23547
  exports.ConnectionDisposedError = ConnectionDisposedError;
22672
23548
  exports.ContractManager = ContractManager;
@@ -22717,6 +23593,7 @@ exports.MnemonicIdentity = MnemonicIdentity;
22717
23593
  exports.OnchainWallet = OnchainWallet;
22718
23594
  exports.P2A = P2A;
22719
23595
  exports.PaymentRouter = PaymentRouter;
23596
+ exports.PrevTxUnavailableError = PrevTxUnavailableError;
22720
23597
  exports.REGTEST_MIN_BATCH_EXPIRY_SECONDS = REGTEST_MIN_BATCH_EXPIRY_SECONDS;
22721
23598
  exports.REGTEST_MIN_CHECKPOINT_EXIT_DELAY_SECONDS = REGTEST_MIN_CHECKPOINT_EXIT_DELAY_SECONDS;
22722
23599
  exports.Ramps = Ramps;
@@ -22742,6 +23619,7 @@ exports.UnilateralExit = UnilateralExit;
22742
23619
  exports.UnknownPacket = UnknownPacket;
22743
23620
  exports.VtxoManager = VtxoManager;
22744
23621
  exports.Wallet = Wallet2;
23622
+ exports.WalletCannotAllocateAddressError = WalletCannotAllocateAddressError;
22745
23623
  exports.WalletCannotSignError = WalletCannotSignError;
22746
23624
  exports.WalletMessageHandler = WalletMessageHandler;
22747
23625
  exports.WalletNotInitializedError = WalletNotInitializedError;
@@ -22758,6 +23636,8 @@ exports.assertSubmittedArkTxid = assertSubmittedArkTxid;
22758
23636
  exports.assertValidBatchExpiry = assertValidBatchExpiry;
22759
23637
  exports.assertValidServerUnrollScript = assertValidServerUnrollScript;
22760
23638
  exports.assetMintResolver = assetMintResolver;
23639
+ exports.attachPrevArkTxs = attachPrevArkTxs;
23640
+ exports.attachPrevoutTxs = attachPrevoutTxs;
22761
23641
  exports.awaitTransaction = awaitTransaction;
22762
23642
  exports.boardingResolver = boardingResolver;
22763
23643
  exports.btcTarget = btcTarget;
@@ -22789,7 +23669,9 @@ exports.deserializeExitPackage = deserializeExitPackage;
22789
23669
  exports.deserializeUtxo = deserializeUtxo;
22790
23670
  exports.deserializeVtxo = deserializeVtxo;
22791
23671
  exports.encodeArkContract = encodeArkContract;
23672
+ exports.exitObserverFor = exitObserverFor;
22792
23673
  exports.extendVirtualCoinForContract = extendVirtualCoinForContract;
23674
+ exports.extractArkProviderUrl = extractArkProviderUrl;
22793
23675
  exports.gateExclusion = gateExclusion;
22794
23676
  exports.gatedContracts = gatedContracts;
22795
23677
  exports.getAllByIndexValues = getAllByIndexValues;
@@ -22800,6 +23682,7 @@ exports.hasCandidates = hasCandidates;
22800
23682
  exports.intentMatchesFilter = intentMatchesFilter;
22801
23683
  exports.intentPageBounds = intentPageBounds;
22802
23684
  exports.invoiceTarget = invoiceTarget;
23685
+ exports.isAddressAllocationCapable = isAddressAllocationCapable;
22803
23686
  exports.isArkContract = isArkContract;
22804
23687
  exports.isBatchSignable = isBatchSignable;
22805
23688
  exports.isBtcAddress = isBtcAddress;
@@ -22827,6 +23710,7 @@ exports.makeHandle = makeHandle;
22827
23710
  exports.matchServerCheckpoints = matchServerCheckpoints;
22828
23711
  exports.mergeChainedTxType = mergeChainedTxType;
22829
23712
  exports.migrateWalletRepository = migrateWalletRepository;
23713
+ exports.notifyExitObserved = notifyExitObserved;
22830
23714
  exports.onchainRail = onchainRail;
22831
23715
  exports.openDatabase = openDatabase;
22832
23716
  exports.outpointExclusion = outpointExclusion;
@@ -22838,6 +23722,7 @@ exports.requiresMigration = requiresMigration;
22838
23722
  exports.resolveBatchExpiryPolicy = resolveBatchExpiryPolicy;
22839
23723
  exports.resolveCheckpointExitDelayPolicy = resolveCheckpointExitDelayPolicy;
22840
23724
  exports.resolveDescriptorSigner = resolveDescriptorSigner;
23725
+ exports.resolvePrevTxs = resolvePrevTxs;
22841
23726
  exports.resolveSendAmount = resolveSendAmount;
22842
23727
  exports.rollbackMigration = rollbackMigration;
22843
23728
  exports.saveVtxosForContract = saveVtxosForContract;
@@ -22861,5 +23746,6 @@ exports.validateVtxoTxGraph = validateVtxoTxGraph;
22861
23746
  exports.verifyTapscriptSignatures = verifyTapscriptSignatures;
22862
23747
  exports.waitForIncomingFunds = waitForIncomingFunds;
22863
23748
  exports.warnAndFilterVtxosForScript = warnAndFilterVtxosForScript;
22864
- //# sourceMappingURL=chunk-5E6IZNRG.cjs.map
22865
- //# sourceMappingURL=chunk-5E6IZNRG.cjs.map
23749
+ exports.withPrevTxs = withPrevTxs;
23750
+ //# sourceMappingURL=chunk-WCJVKFAP.cjs.map
23751
+ //# sourceMappingURL=chunk-WCJVKFAP.cjs.map