@arkade-os/sdk 0.4.32 → 0.4.34

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 (82) hide show
  1. package/README.md +1 -1
  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/{ark-ibLW4Hte.d.cts → ark-Dsv5Jq4E.d.cts} +81 -10
  9. package/dist/{ark-ibLW4Hte.d.ts → ark-Dsv5Jq4E.d.ts} +81 -10
  10. package/dist/{asyncStorageTaskQueue-BEOFPNc0.d.ts → asyncStorageTaskQueue-BH-zuth5.d.ts} +1 -1
  11. package/dist/{asyncStorageTaskQueue-VGHXWR9F.d.cts → asyncStorageTaskQueue-D92ch8yI.d.cts} +1 -1
  12. package/dist/{chunk-ABWRLTX5.js → chunk-5WDBHWX3.js} +4 -4
  13. package/dist/{chunk-ABWRLTX5.js.map → chunk-5WDBHWX3.js.map} +1 -1
  14. package/dist/{chunk-GIGILVVP.cjs → chunk-CCLNFHJ5.cjs} +11 -11
  15. package/dist/{chunk-GIGILVVP.cjs.map → chunk-CCLNFHJ5.cjs.map} +1 -1
  16. package/dist/{chunk-WMIPYZSB.cjs → chunk-CMPJR3HS.cjs} +42 -9
  17. package/dist/chunk-CMPJR3HS.cjs.map +1 -0
  18. package/dist/{chunk-YA4G7RFB.js → chunk-CUSABEUQ.js} +166 -38
  19. package/dist/chunk-CUSABEUQ.js.map +1 -0
  20. package/dist/{chunk-6FLL2Q36.cjs → chunk-FSAXPBGP.cjs} +9 -9
  21. package/dist/chunk-FSAXPBGP.cjs.map +1 -0
  22. package/dist/{chunk-6NWNOLL3.js → chunk-FXFBPXV3.js} +4 -4
  23. package/dist/chunk-FXFBPXV3.js.map +1 -0
  24. package/dist/{chunk-IEO3XDKI.cjs → chunk-GUTKJMSF.cjs} +190 -58
  25. package/dist/chunk-GUTKJMSF.cjs.map +1 -0
  26. package/dist/{chunk-XROGFOPX.js → chunk-HFXEUW55.js} +740 -175
  27. package/dist/chunk-HFXEUW55.js.map +1 -0
  28. package/dist/{chunk-TU3LVAPX.js → chunk-OUVTG72A.js} +43 -11
  29. package/dist/chunk-OUVTG72A.js.map +1 -0
  30. package/dist/{chunk-SHEBNWOQ.js → chunk-VVGD3JIP.js} +3 -3
  31. package/dist/{chunk-SHEBNWOQ.js.map → chunk-VVGD3JIP.js.map} +1 -1
  32. package/dist/{chunk-KQK4PP6L.cjs → chunk-XCHBQVMK.cjs} +879 -314
  33. package/dist/chunk-XCHBQVMK.cjs.map +1 -0
  34. package/dist/{chunk-I2UIKZM5.cjs → chunk-ZS3OZHC7.cjs} +7 -7
  35. package/dist/{chunk-I2UIKZM5.cjs.map → chunk-ZS3OZHC7.cjs.map} +1 -1
  36. package/dist/contracts/handlers/index.cjs +10 -6
  37. package/dist/contracts/handlers/index.d.cts +3 -3
  38. package/dist/contracts/handlers/index.d.ts +3 -3
  39. package/dist/contracts/handlers/index.js +2 -2
  40. package/dist/{delegate-BvNTw44a.d.cts → delegate-BaS5SCIW.d.cts} +10 -2
  41. package/dist/{delegate-BXaR1RNG.d.ts → delegate-Baz_hb83.d.ts} +10 -2
  42. package/dist/{index-BusKawmy.d.ts → index-FwXZveaX.d.ts} +63 -3
  43. package/dist/{index-C-5Tw7VA.d.cts → index-lNZ6qaO3.d.cts} +63 -3
  44. package/dist/index.cjs +143 -127
  45. package/dist/index.d.cts +89 -16
  46. package/dist/index.d.ts +89 -16
  47. package/dist/index.js +4 -4
  48. package/dist/repositories/realm/index.cjs +13 -13
  49. package/dist/repositories/realm/index.d.cts +1 -1
  50. package/dist/repositories/realm/index.d.ts +1 -1
  51. package/dist/repositories/realm/index.js +4 -4
  52. package/dist/repositories/sqlite/index.cjs +13 -13
  53. package/dist/repositories/sqlite/index.d.cts +1 -1
  54. package/dist/repositories/sqlite/index.d.ts +1 -1
  55. package/dist/repositories/sqlite/index.js +4 -4
  56. package/dist/{taskRunner-B1igKGAo.d.ts → taskRunner-B1NUWyWR.d.ts} +1 -1
  57. package/dist/{taskRunner-By92TQ1m.d.cts → taskRunner-vFRA3F9b.d.cts} +1 -1
  58. package/dist/wallet/expo/background.cjs +14 -14
  59. package/dist/wallet/expo/background.d.cts +3 -3
  60. package/dist/wallet/expo/background.d.ts +3 -3
  61. package/dist/wallet/expo/background.js +6 -6
  62. package/dist/wallet/expo/index.cjs +14 -14
  63. package/dist/wallet/expo/index.cjs.map +1 -1
  64. package/dist/wallet/expo/index.d.cts +5 -5
  65. package/dist/wallet/expo/index.d.ts +5 -5
  66. package/dist/wallet/expo/index.js +6 -6
  67. package/dist/wallet/expo/index.js.map +1 -1
  68. package/dist/{wallet-B_rxgQTu.d.cts → wallet-By9HIo0Q.d.cts} +160 -5
  69. package/dist/{wallet-CyM4F7Bs.d.ts → wallet-D6uoBLmS.d.ts} +160 -5
  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 +4 -4
  75. package/dist/chunk-6FLL2Q36.cjs.map +0 -1
  76. package/dist/chunk-6NWNOLL3.js.map +0 -1
  77. package/dist/chunk-IEO3XDKI.cjs.map +0 -1
  78. package/dist/chunk-KQK4PP6L.cjs.map +0 -1
  79. package/dist/chunk-TU3LVAPX.js.map +0 -1
  80. package/dist/chunk-WMIPYZSB.cjs.map +0 -1
  81. package/dist/chunk-XROGFOPX.js.map +0 -1
  82. package/dist/chunk-YA4G7RFB.js.map +0 -1
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var chunk6FLL2Q36_cjs = require('./chunk-6FLL2Q36.cjs');
4
- var chunkIEO3XDKI_cjs = require('./chunk-IEO3XDKI.cjs');
5
- var chunkWMIPYZSB_cjs = require('./chunk-WMIPYZSB.cjs');
3
+ var chunkFSAXPBGP_cjs = require('./chunk-FSAXPBGP.cjs');
4
+ var chunkGUTKJMSF_cjs = require('./chunk-GUTKJMSF.cjs');
5
+ var chunkCMPJR3HS_cjs = require('./chunk-CMPJR3HS.cjs');
6
6
  var utils_js = require('@scure/btc-signer/utils.js');
7
7
  var btcSigner = require('@scure/btc-signer');
8
8
  var base = require('@scure/base');
@@ -181,7 +181,7 @@ var TreeSignerSession = class _TreeSignerSession {
181
181
  noncesByPubkey.set(base.hex.encode(myPublicKey.subarray(1)), myNonce);
182
182
  const tx = this.graph.find(txid);
183
183
  if (!tx) throw new Error(`missing tx for txid ${txid}`);
184
- const cosigners = chunk6FLL2Q36_cjs.getArkPsbtFields(tx.root, 0, chunk6FLL2Q36_cjs.CosignerPublicKey).map(
184
+ const cosigners = chunkFSAXPBGP_cjs.getArkPsbtFields(tx.root, 0, chunkFSAXPBGP_cjs.CosignerPublicKey).map(
185
185
  (c) => base.hex.encode(c.key.subarray(1))
186
186
  // xonly pubkey
187
187
  );
@@ -233,7 +233,7 @@ var TreeSignerSession = class _TreeSignerSession {
233
233
  if (!aggNonce) throw new Error("missing aggregate nonce");
234
234
  const prevoutAmounts = [];
235
235
  const prevoutScripts = [];
236
- const cosigners = chunk6FLL2Q36_cjs.getArkPsbtFields(g.root, 0, chunk6FLL2Q36_cjs.CosignerPublicKey).map((c) => c.key);
236
+ const cosigners = chunkFSAXPBGP_cjs.getArkPsbtFields(g.root, 0, chunkFSAXPBGP_cjs.CosignerPublicKey).map((c) => c.key);
237
237
  const { finalKey } = aggregateKeys(cosigners, true, {
238
238
  taprootTweak: this.scriptRoot
239
239
  });
@@ -411,7 +411,7 @@ var SeedIdentity = class _SeedIdentity {
411
411
  let network;
412
412
  if ("descriptor" in opts && typeof opts.descriptor === "string") {
413
413
  descriptor = opts.descriptor;
414
- network = chunkIEO3XDKI_cjs.isMainnetDescriptor(descriptor) ? descriptorsScure.networks.bitcoin : descriptorsScure.networks.testnet;
414
+ network = chunkGUTKJMSF_cjs.isMainnetDescriptor(descriptor) ? descriptorsScure.networks.bitcoin : descriptorsScure.networks.testnet;
415
415
  } else {
416
416
  network = opts.isMainnet ?? true ? descriptorsScure.networks.bitcoin : descriptorsScure.networks.testnet;
417
417
  descriptor = descriptorsScure.scriptExpressions.trBIP32({
@@ -496,7 +496,7 @@ var SeedIdentity = class _SeedIdentity {
496
496
  * `StaticDescriptorProvider` for legacy single-key wallets.
497
497
  */
498
498
  isOurs(descriptor) {
499
- return chunkIEO3XDKI_cjs.descriptorIsOurs(descriptor, this.descriptor, utils_js.pubSchnorr(this.derivedKey));
499
+ return chunkGUTKJMSF_cjs.descriptorIsOurs(descriptor, this.descriptor, utils_js.pubSchnorr(this.derivedKey));
500
500
  }
501
501
  /**
502
502
  * Signs each request with the key derived from its descriptor.
@@ -533,7 +533,7 @@ var SeedIdentity = class _SeedIdentity {
533
533
  }
534
534
  // ── internal helpers ─────────────────────────────────────────────
535
535
  derivePrivateKeyForDescriptor(descriptor) {
536
- const network = chunkIEO3XDKI_cjs.isMainnetDescriptor(descriptor) ? descriptorsScure.networks.bitcoin : descriptorsScure.networks.testnet;
536
+ const network = chunkGUTKJMSF_cjs.isMainnetDescriptor(descriptor) ? descriptorsScure.networks.bitcoin : descriptorsScure.networks.testnet;
537
537
  const expansion = descriptorsScure.expand({ descriptor, network });
538
538
  if (expansion.isRanged) {
539
539
  throw new Error(
@@ -619,7 +619,7 @@ var ReadonlyDescriptorIdentity = class _ReadonlyDescriptorIdentity {
619
619
  */
620
620
  descriptor;
621
621
  constructor(descriptor) {
622
- const network = chunkIEO3XDKI_cjs.isMainnetDescriptor(descriptor) ? descriptorsScure.networks.bitcoin : descriptorsScure.networks.testnet;
622
+ const network = chunkGUTKJMSF_cjs.isMainnetDescriptor(descriptor) ? descriptorsScure.networks.bitcoin : descriptorsScure.networks.testnet;
623
623
  let expansion;
624
624
  try {
625
625
  expansion = descriptorsScure.expand({ descriptor, network, index: 0 });
@@ -669,7 +669,7 @@ var ReadonlyDescriptorIdentity = class _ReadonlyDescriptorIdentity {
669
669
  * `StaticDescriptorProvider` for legacy single-key wallets.
670
670
  */
671
671
  isOurs(descriptor) {
672
- return chunkIEO3XDKI_cjs.descriptorIsOurs(descriptor, this.descriptor, this.indexZero.pubkey);
672
+ return chunkGUTKJMSF_cjs.descriptorIsOurs(descriptor, this.descriptor, this.indexZero.pubkey);
673
673
  }
674
674
  };
675
675
  function serializeSeedOwnedSigningIdentity(identity) {
@@ -987,7 +987,7 @@ var RestDelegateProvider = class {
987
987
  },
988
988
  body: JSON.stringify({
989
989
  intent: {
990
- message: chunk6FLL2Q36_cjs.Intent.encodeMessage(intent.message),
990
+ message: chunkFSAXPBGP_cjs.Intent.encodeMessage(intent.message),
991
991
  proof: intent.proof
992
992
  },
993
993
  forfeit_txs: forfeitTxs,
@@ -1031,10 +1031,10 @@ var ESPLORA_URL = {
1031
1031
  testnet: "https://mempool.space/testnet/api",
1032
1032
  signet: "https://mempool.signet.arkade.sh/api",
1033
1033
  mutinynet: "https://mempool.mutinynet.arkade.sh/api",
1034
- regtest: "http://localhost:3000"
1034
+ regtest: "http://localhost:3000/api"
1035
1035
  };
1036
1036
  var EsploraProvider = class {
1037
- constructor(baseUrl = ESPLORA_URL[chunkWMIPYZSB_cjs.DEFAULT_NETWORK_NAME], opts) {
1037
+ constructor(baseUrl = ESPLORA_URL[chunkCMPJR3HS_cjs.DEFAULT_NETWORK_NAME], opts) {
1038
1038
  this.baseUrl = baseUrl;
1039
1039
  this.pollingInterval = opts?.pollingInterval ?? 15e3;
1040
1040
  this.forcePolling = opts?.forcePolling ?? false;
@@ -1050,6 +1050,9 @@ var EsploraProvider = class {
1050
1050
  }
1051
1051
  async getFeeRate() {
1052
1052
  const response = await fetch(`${this.baseUrl}/fee-estimates`);
1053
+ if (response.status === 404) {
1054
+ return void 0;
1055
+ }
1053
1056
  if (!response.ok) {
1054
1057
  throw new Error(`Failed to fetch fee rate: ${response.statusText}`);
1055
1058
  }
@@ -1175,7 +1178,7 @@ var EsploraProvider = class {
1175
1178
  return stopFunc;
1176
1179
  }
1177
1180
  async getChainTip() {
1178
- const tipBlocks = await fetch(`${this.baseUrl}/blocks/tip`);
1181
+ const tipBlocks = await fetch(`${this.baseUrl}/blocks`);
1179
1182
  if (!tipBlocks.ok) {
1180
1183
  throw new Error(`Failed to get chain tip: ${tipBlocks.statusText}`);
1181
1184
  }
@@ -1277,7 +1280,7 @@ function buildForfeitTx(inputs, forfeitPkScript, txLocktime) {
1277
1280
  );
1278
1281
  }
1279
1282
  function buildForfeitTxWithOutput(inputs, output, txLocktime) {
1280
- const tx = new chunk6FLL2Q36_cjs.Transaction({
1283
+ const tx = new chunkFSAXPBGP_cjs.Transaction({
1281
1284
  version: 3,
1282
1285
  lockTime: txLocktime
1283
1286
  });
@@ -1353,7 +1356,7 @@ function validateVtxoTxGraph(graph, roundTransaction, sweepTapTreeRoot) {
1353
1356
  if (previousScriptKey.length !== 32) {
1354
1357
  throw new Error(`parent output ${childIndex} has invalid script`);
1355
1358
  }
1356
- const cosigners = chunk6FLL2Q36_cjs.getArkPsbtFields(child.root, 0, chunk6FLL2Q36_cjs.CosignerPublicKey);
1359
+ const cosigners = chunkFSAXPBGP_cjs.getArkPsbtFields(child.root, 0, chunkFSAXPBGP_cjs.CosignerPublicKey);
1357
1360
  if (cosigners.length === 0) {
1358
1361
  throw ErrMissingCosignersPublicKeys;
1359
1362
  }
@@ -1453,7 +1456,7 @@ var Extension = class _Extension {
1453
1456
  `expected magic prefix ${base.hex.encode(ARKADE_MAGIC)}, got ${base.hex.encode(payload.slice(0, Math.min(payload.length, ARKADE_MAGIC.length)))}`
1454
1457
  );
1455
1458
  }
1456
- const reader = new chunk6FLL2Q36_cjs.BufferReader(payload.slice(ARKADE_MAGIC.length));
1459
+ const reader = new chunkFSAXPBGP_cjs.BufferReader(payload.slice(ARKADE_MAGIC.length));
1457
1460
  const packets = [];
1458
1461
  while (reader.remaining() > 0) {
1459
1462
  const packetType = reader.readByte();
@@ -1527,7 +1530,7 @@ var Extension = class _Extension {
1527
1530
  */
1528
1531
  getAssetPacket() {
1529
1532
  for (const p of this.packets) {
1530
- if (p instanceof chunk6FLL2Q36_cjs.Packet) {
1533
+ if (p instanceof chunkFSAXPBGP_cjs.Packet) {
1531
1534
  return p;
1532
1535
  }
1533
1536
  }
@@ -1535,8 +1538,8 @@ var Extension = class _Extension {
1535
1538
  }
1536
1539
  };
1537
1540
  function parsePacket(packetType, data) {
1538
- if (packetType === chunk6FLL2Q36_cjs.Packet.PACKET_TYPE) {
1539
- return chunk6FLL2Q36_cjs.Packet.fromBytes(data);
1541
+ if (packetType === chunkFSAXPBGP_cjs.Packet.PACKET_TYPE) {
1542
+ return chunkFSAXPBGP_cjs.Packet.fromBytes(data);
1540
1543
  }
1541
1544
  return new UnknownPacket(packetType, data);
1542
1545
  }
@@ -1594,7 +1597,7 @@ function validateBatchRecipients(commitmentTx, vtxoTreeLeaves, recipients, netwo
1594
1597
  for (const recipient of recipients) {
1595
1598
  let arkAddress;
1596
1599
  try {
1597
- arkAddress = chunkWMIPYZSB_cjs.ArkAddress.decode(recipient.address);
1600
+ arkAddress = chunkCMPJR3HS_cjs.ArkAddress.decode(recipient.address);
1598
1601
  } catch {
1599
1602
  validateOnchainRecipient(commitmentTx, recipient, network, usedOnchainOutputs);
1600
1603
  continue;
@@ -1727,7 +1730,7 @@ function createAssetPacket(assetInputs, receivers, changeReceiver) {
1727
1730
  const existing = inputsByAssetId.get(asset.assetId);
1728
1731
  inputsByAssetId.set(asset.assetId, [
1729
1732
  ...existing ?? [],
1730
- chunk6FLL2Q36_cjs.AssetInput.create(inputIndex, asset.amount)
1733
+ chunkFSAXPBGP_cjs.AssetInput.create(inputIndex, asset.amount)
1731
1734
  ]);
1732
1735
  }
1733
1736
  }
@@ -1739,7 +1742,7 @@ function createAssetPacket(assetInputs, receivers, changeReceiver) {
1739
1742
  const existing = outputsByAssetId.get(asset.assetId);
1740
1743
  outputsByAssetId.set(asset.assetId, [
1741
1744
  ...existing ?? [],
1742
- chunk6FLL2Q36_cjs.AssetOutput.create(outputIndex, asset.amount)
1745
+ chunkFSAXPBGP_cjs.AssetOutput.create(outputIndex, asset.amount)
1743
1746
  ]);
1744
1747
  }
1745
1748
  }
@@ -1750,7 +1753,7 @@ function createAssetPacket(assetInputs, receivers, changeReceiver) {
1750
1753
  const existing = outputsByAssetId.get(asset.assetId);
1751
1754
  outputsByAssetId.set(asset.assetId, [
1752
1755
  ...existing ?? [],
1753
- chunk6FLL2Q36_cjs.AssetOutput.create(outputIndex, asset.amount)
1756
+ chunkFSAXPBGP_cjs.AssetOutput.create(outputIndex, asset.amount)
1754
1757
  ]);
1755
1758
  }
1756
1759
  }
@@ -1759,11 +1762,11 @@ function createAssetPacket(assetInputs, receivers, changeReceiver) {
1759
1762
  for (const assetIdStr of allAssetIds) {
1760
1763
  const inputs = inputsByAssetId.get(assetIdStr);
1761
1764
  const outputs = outputsByAssetId.get(assetIdStr);
1762
- const assetId = chunk6FLL2Q36_cjs.AssetId.fromString(assetIdStr);
1763
- const group = chunk6FLL2Q36_cjs.AssetGroup.create(assetId, null, inputs ?? [], outputs ?? [], []);
1765
+ const assetId = chunkFSAXPBGP_cjs.AssetId.fromString(assetIdStr);
1766
+ const group = chunkFSAXPBGP_cjs.AssetGroup.create(assetId, null, inputs ?? [], outputs ?? [], []);
1764
1767
  groups.push(group);
1765
1768
  }
1766
- return chunk6FLL2Q36_cjs.Packet.create(groups);
1769
+ return chunkFSAXPBGP_cjs.Packet.create(groups);
1767
1770
  }
1768
1771
  function selectCoinsWithAsset(coins, assetId, requiredAmount) {
1769
1772
  const coinsWithAsset = coins.filter((coin) => coin.assets?.some((a) => a.assetId === assetId));
@@ -1829,8 +1832,8 @@ function buildOffchainTx(inputs, outputs, serverUnrollScript) {
1829
1832
  function buildVirtualTx(inputs, outputs) {
1830
1833
  let lockTime = 0n;
1831
1834
  for (const input of inputs) {
1832
- const tapscript = chunkWMIPYZSB_cjs.decodeTapscript(chunkWMIPYZSB_cjs.scriptFromTapLeafScript(input.tapLeafScript));
1833
- if (chunkWMIPYZSB_cjs.CLTVMultisigTapscript.is(tapscript)) {
1835
+ const tapscript = chunkCMPJR3HS_cjs.decodeTapscript(chunkCMPJR3HS_cjs.scriptFromTapLeafScript(input.tapLeafScript));
1836
+ if (chunkCMPJR3HS_cjs.CLTVMultisigTapscript.is(tapscript)) {
1834
1837
  if (lockTime !== 0n) {
1835
1838
  if (isSeconds(lockTime) !== isSeconds(tapscript.params.absoluteTimelock)) {
1836
1839
  throw new Error("cannot mix seconds and blocks locktime");
@@ -1841,7 +1844,7 @@ function buildVirtualTx(inputs, outputs) {
1841
1844
  }
1842
1845
  }
1843
1846
  }
1844
- const tx = new chunk6FLL2Q36_cjs.Transaction({
1847
+ const tx = new chunkFSAXPBGP_cjs.Transaction({
1845
1848
  version: 3,
1846
1849
  lockTime: Number(lockTime)
1847
1850
  });
@@ -1851,12 +1854,12 @@ function buildVirtualTx(inputs, outputs) {
1851
1854
  index: input.vout,
1852
1855
  sequence: lockTime ? btcSigner.DEFAULT_SEQUENCE - 1 : void 0,
1853
1856
  witnessUtxo: {
1854
- script: chunkWMIPYZSB_cjs.VtxoScript.decode(input.tapTree).pkScript,
1857
+ script: chunkCMPJR3HS_cjs.VtxoScript.decode(input.tapTree).pkScript,
1855
1858
  amount: BigInt(input.value)
1856
1859
  },
1857
1860
  tapLeafScript: [input.tapLeafScript]
1858
1861
  });
1859
- chunk6FLL2Q36_cjs.setArkPsbtField(tx, i, chunk6FLL2Q36_cjs.VtxoTaprootTree, input.tapTree);
1862
+ chunkFSAXPBGP_cjs.setArkPsbtField(tx, i, chunkFSAXPBGP_cjs.VtxoTaprootTree, input.tapTree);
1860
1863
  }
1861
1864
  for (const output of outputs) {
1862
1865
  tx.addOutput(output);
@@ -1865,8 +1868,8 @@ function buildVirtualTx(inputs, outputs) {
1865
1868
  return tx;
1866
1869
  }
1867
1870
  function buildCheckpointTx(vtxo, serverUnrollScript) {
1868
- const collaborativeClosure = chunkWMIPYZSB_cjs.decodeTapscript(chunkWMIPYZSB_cjs.scriptFromTapLeafScript(vtxo.tapLeafScript));
1869
- const checkpointVtxoScript = new chunkWMIPYZSB_cjs.VtxoScript([
1871
+ const collaborativeClosure = chunkCMPJR3HS_cjs.decodeTapscript(chunkCMPJR3HS_cjs.scriptFromTapLeafScript(vtxo.tapLeafScript));
1872
+ const checkpointVtxoScript = new chunkCMPJR3HS_cjs.VtxoScript([
1870
1873
  serverUnrollScript.script,
1871
1874
  collaborativeClosure.script
1872
1875
  ]);
@@ -1988,19 +1991,29 @@ function verifyTapscriptSignatures(tx, inputIndex, requiredSigners, excludePubke
1988
1991
  }
1989
1992
  }
1990
1993
  function combineTapscriptSigs(signedTx, originalTx) {
1994
+ if (signedTx.inputsLength !== originalTx.inputsLength) {
1995
+ throw new Error(
1996
+ `combineTapscriptSigs: input count mismatch (signedTx ${signedTx.inputsLength}, originalTx ${originalTx.inputsLength})`
1997
+ );
1998
+ }
1991
1999
  for (let i = 0; i < signedTx.inputsLength; i++) {
1992
2000
  const input = originalTx.getInput(i);
1993
2001
  const signedInput = signedTx.getInput(i);
1994
- if (!input.tapScriptSig) throw new Error("No tapScriptSig");
2002
+ if (!input.tapScriptSig) {
2003
+ throw new Error(`combineTapscriptSigs: originalTx input ${i} has no tapScriptSig`);
2004
+ }
2005
+ if (!signedInput.tapScriptSig) {
2006
+ throw new Error(`combineTapscriptSigs: signedTx input ${i} has no tapScriptSig`);
2007
+ }
1995
2008
  originalTx.updateInput(i, {
1996
- tapScriptSig: input.tapScriptSig?.concat(signedInput.tapScriptSig)
2009
+ tapScriptSig: input.tapScriptSig.concat(signedInput.tapScriptSig)
1997
2010
  });
1998
2011
  }
1999
2012
  return originalTx;
2000
2013
  }
2001
2014
  function isValidArkAddress(address) {
2002
2015
  try {
2003
- chunkWMIPYZSB_cjs.ArkAddress.decode(address);
2016
+ chunkCMPJR3HS_cjs.ArkAddress.decode(address);
2004
2017
  return true;
2005
2018
  } catch (e) {
2006
2019
  return false;
@@ -2270,16 +2283,16 @@ var FALLBACK_WALLET_DUST_AMOUNT = 330n;
2270
2283
  function getDustAmount(wallet) {
2271
2284
  return "dustAmount" in wallet ? wallet.dustAmount : FALLBACK_WALLET_DUST_AMOUNT;
2272
2285
  }
2273
- function extendCoin(wallet, utxo) {
2286
+ function extendCoinWithTapscript(boardingTapscript, utxo) {
2274
2287
  return {
2275
2288
  ...utxo,
2276
- forfeitTapLeafScript: wallet.boardingTapscript.forfeit(),
2277
- intentTapLeafScript: wallet.boardingTapscript.forfeit(),
2278
- tapTree: wallet.boardingTapscript.encode()
2289
+ forfeitTapLeafScript: boardingTapscript.forfeit(),
2290
+ intentTapLeafScript: boardingTapscript.forfeit(),
2291
+ tapTree: boardingTapscript.encode()
2279
2292
  };
2280
2293
  }
2281
2294
  function deriveContractTapscripts(contract) {
2282
- const handler = chunkIEO3XDKI_cjs.contractHandlers.get(contract.type);
2295
+ const handler = chunkGUTKJMSF_cjs.contractHandlers.get(contract.type);
2283
2296
  if (!handler) {
2284
2297
  throw new Error(`No handler for contract type '${contract.type}'`);
2285
2298
  }
@@ -2349,7 +2362,7 @@ function validateRecipients(recipients, dustAmount) {
2349
2362
  for (const recipient of recipients) {
2350
2363
  let address;
2351
2364
  try {
2352
- address = chunkWMIPYZSB_cjs.ArkAddress.decode(recipient.address);
2365
+ address = chunkCMPJR3HS_cjs.ArkAddress.decode(recipient.address);
2353
2366
  } catch (e) {
2354
2367
  throw new Error(`Invalid Arkade address: ${recipient.address}`);
2355
2368
  }
@@ -2369,12 +2382,12 @@ function validateRecipients(recipients, dustAmount) {
2369
2382
 
2370
2383
  // src/wallet/vtxo-manager.ts
2371
2384
  function isSweepCapable(wallet) {
2372
- return "boardingTapscript" in wallet && "onchainProvider" in wallet && "arkProvider" in wallet && "network" in wallet;
2385
+ return "boardingTapscript" in wallet && "onchainProvider" in wallet && "arkProvider" in wallet && "network" in wallet && "signOnchainBoardingTx" in wallet;
2373
2386
  }
2374
2387
  function assertSweepCapable(wallet) {
2375
2388
  if (!isSweepCapable(wallet)) {
2376
2389
  throw new Error(
2377
- "Boarding UTXO sweep requires a Wallet instance with boardingTapscript, onchainProvider, arkProvider, and network"
2390
+ "Boarding UTXO sweep requires a Wallet instance with boardingTapscript, onchainProvider, arkProvider, network, and signOnchainBoardingTx"
2378
2391
  );
2379
2392
  }
2380
2393
  }
@@ -2390,6 +2403,21 @@ async function runWithCrossInstanceLock(name, fn) {
2390
2403
  await fn();
2391
2404
  });
2392
2405
  }
2406
+ var MAX_VTXOS_PER_SETTLEMENT = 50;
2407
+ function byValueDescending(vtxos) {
2408
+ return [...vtxos].sort((a, b) => b.value - a.value);
2409
+ }
2410
+ function byExpiryAscending(vtxos) {
2411
+ const expiryKey = (vtxo) => {
2412
+ if (isRecoverable(vtxo)) return -Infinity;
2413
+ const batchExpiry = vtxo.virtualStatus.batchExpiry;
2414
+ if (isExpired(vtxo)) return batchExpiry ?? -Infinity;
2415
+ if (!batchExpiry) return Infinity;
2416
+ if (new Date(batchExpiry).getFullYear() < 2025) return Infinity;
2417
+ return batchExpiry;
2418
+ };
2419
+ return [...vtxos].sort((a, b) => expiryKey(a) - expiryKey(b));
2420
+ }
2393
2421
  var DEFAULT_THRESHOLD_SECONDS = 259200;
2394
2422
  var DEFAULT_THRESHOLD_MS = DEFAULT_THRESHOLD_SECONDS * 1e3;
2395
2423
  var DEFAULT_RENEWAL_CONFIG = {
@@ -2549,10 +2577,20 @@ var VtxoManager = class _VtxoManager {
2549
2577
  withUnrolled: false
2550
2578
  });
2551
2579
  const dustAmount = getDustAmount(this.wallet);
2552
- const { vtxosToRecover, totalAmount } = getRecoverableWithSubdust(allVtxos, dustAmount);
2580
+ let { vtxosToRecover, totalAmount } = getRecoverableWithSubdust(allVtxos, dustAmount);
2553
2581
  if (vtxosToRecover.length === 0) {
2554
2582
  throw new Error("No recoverable VTXOs found");
2555
2583
  }
2584
+ if (vtxosToRecover.length > MAX_VTXOS_PER_SETTLEMENT) {
2585
+ const recoverableCount = vtxosToRecover.length;
2586
+ const capped = byValueDescending(vtxosToRecover).slice(0, MAX_VTXOS_PER_SETTLEMENT);
2587
+ ({ vtxosToRecover, totalAmount } = getRecoverableWithSubdust(capped, dustAmount));
2588
+ if (vtxosToRecover.length === 0) {
2589
+ throw new Error(
2590
+ `Capped recovery batch (highest-value ${MAX_VTXOS_PER_SETTLEMENT} of ${recoverableCount} recoverable VTXOs) is below the dust threshold ${dustAmount}`
2591
+ );
2592
+ }
2593
+ }
2556
2594
  const arkAddress = await this.wallet.getAddress();
2557
2595
  return this.wallet.settle(
2558
2596
  {
@@ -2702,6 +2740,9 @@ var VtxoManager = class _VtxoManager {
2702
2740
  if (vtxos.length === 0) {
2703
2741
  throw new Error("No VTXOs available to renew");
2704
2742
  }
2743
+ if (vtxos.length > MAX_VTXOS_PER_SETTLEMENT) {
2744
+ vtxos = byExpiryAscending(vtxos).slice(0, MAX_VTXOS_PER_SETTLEMENT);
2745
+ }
2705
2746
  const totalAmount = vtxos.reduce((sum, vtxo) => sum + vtxo.value, 0);
2706
2747
  const dustAmount = getDustAmount(this.wallet);
2707
2748
  if (BigInt(totalAmount) < dustAmount) {
@@ -2809,7 +2850,6 @@ var VtxoManager = class _VtxoManager {
2809
2850
  const boardingAddress = await this.wallet.getBoardingAddress();
2810
2851
  const feeRate = await this.getOnchainProvider().getFeeRate() ?? 1;
2811
2852
  const exitTapLeafScript = this.getBoardingExitLeaf();
2812
- const sequence = chunkWMIPYZSB_cjs.getSequence(exitTapLeafScript);
2813
2853
  const leafScript = exitTapLeafScript[1];
2814
2854
  const leafScriptSize = leafScript.length - 1;
2815
2855
  const controlBlockSize = exitTapLeafScript[0].merklePath.length * 32;
@@ -2828,21 +2868,30 @@ var VtxoManager = class _VtxoManager {
2828
2868
  `Sweep not economical: output ${outputAmount} sats after ${fee} sats fee is below dust (${dustAmount} sats)`
2829
2869
  );
2830
2870
  }
2831
- const tx = new chunk6FLL2Q36_cjs.Transaction();
2871
+ const tx = new chunkFSAXPBGP_cjs.Transaction();
2832
2872
  for (const utxo of expiredUtxos) {
2873
+ const utxoScript = chunkCMPJR3HS_cjs.VtxoScript.decode(utxo.tapTree);
2874
+ const utxoExitLeaf = utxoScript.leaves.find(
2875
+ (leaf) => chunkCMPJR3HS_cjs.CSVMultisigTapscript.isScriptValid(chunkCMPJR3HS_cjs.scriptFromTapLeafScript(leaf)) === true
2876
+ );
2877
+ if (!utxoExitLeaf) {
2878
+ throw new Error(
2879
+ `Boarding sweep: no CSV exit leaf for UTXO ${utxo.txid}:${utxo.vout}`
2880
+ );
2881
+ }
2833
2882
  tx.addInput({
2834
2883
  txid: utxo.txid,
2835
2884
  index: utxo.vout,
2836
2885
  witnessUtxo: {
2837
- script: this.getBoardingOutputScript(),
2886
+ script: utxoScript.pkScript,
2838
2887
  amount: BigInt(utxo.value)
2839
2888
  },
2840
- tapLeafScript: [exitTapLeafScript],
2841
- sequence
2889
+ tapLeafScript: [utxoExitLeaf],
2890
+ sequence: chunkCMPJR3HS_cjs.getSequence(utxoExitLeaf)
2842
2891
  });
2843
2892
  }
2844
2893
  tx.addOutputAddress(boardingAddress, outputAmount, this.getNetwork());
2845
- const signedTx = await this.getIdentity().sign(tx);
2894
+ const signedTx = await this.getSweepWallet().signOnchainBoardingTx(tx);
2846
2895
  signedTx.finalize();
2847
2896
  const txid = await this.getOnchainProvider().broadcastTransaction(signedTx.hex);
2848
2897
  for (const u of expiredUtxos) {
@@ -2860,7 +2909,7 @@ var VtxoManager = class _VtxoManager {
2860
2909
  /** Decodes the boarding tapscript exit path to extract the CSV timelock. */
2861
2910
  getBoardingTimelock() {
2862
2911
  const wallet = this.getSweepWallet();
2863
- const exitScript = chunkWMIPYZSB_cjs.CSVMultisigTapscript.decode(
2912
+ const exitScript = chunkCMPJR3HS_cjs.CSVMultisigTapscript.decode(
2864
2913
  base.hex.decode(wallet.boardingTapscript.exitScript)
2865
2914
  );
2866
2915
  return exitScript.params.timelock;
@@ -2869,10 +2918,6 @@ var VtxoManager = class _VtxoManager {
2869
2918
  getBoardingExitLeaf() {
2870
2919
  return this.getSweepWallet().boardingTapscript.exit();
2871
2920
  }
2872
- /** Returns the pkScript (output script) of the boarding tapscript. */
2873
- getBoardingOutputScript() {
2874
- return this.getSweepWallet().boardingTapscript.pkScript;
2875
- }
2876
2921
  /** Returns the onchain provider for fee estimation and broadcasting. */
2877
2922
  getOnchainProvider() {
2878
2923
  return this.getSweepWallet().onchainProvider;
@@ -2885,10 +2930,6 @@ var VtxoManager = class _VtxoManager {
2885
2930
  getNetwork() {
2886
2931
  return this.getSweepWallet().network;
2887
2932
  }
2888
- /** Returns the wallet's identity for transaction signing. */
2889
- getIdentity() {
2890
- return this.wallet.identity;
2891
- }
2892
2933
  async initializeSubscription() {
2893
2934
  if (this.settlementConfig === false) {
2894
2935
  return void 0;
@@ -2989,7 +3030,7 @@ var VtxoManager = class _VtxoManager {
2989
3030
  * or doesn't carry the metadata.
2990
3031
  */
2991
3032
  extractSpentOutpoint(error) {
2992
- const ark = chunk6FLL2Q36_cjs.maybeArkError(error);
3033
+ const ark = chunkFSAXPBGP_cjs.maybeArkError(error);
2993
3034
  if (!ark || ark.name !== "VTXO_ALREADY_SPENT") return void 0;
2994
3035
  const raw = ark.metadata?.vtxo_outpoint;
2995
3036
  if (typeof raw !== "string") return void 0;
@@ -3169,7 +3210,10 @@ var VtxoManager = class _VtxoManager {
3169
3210
  totalAmount += BigInt(u.value) - BigInt(inputFee.satoshis);
3170
3211
  }
3171
3212
  const filteredVtxos = [];
3172
- for (const v of expiringVtxos) {
3213
+ for (const v of byExpiryAscending(expiringVtxos)) {
3214
+ if (filteredVtxos.length >= MAX_VTXOS_PER_SETTLEMENT) {
3215
+ break;
3216
+ }
3173
3217
  const inputFee = estimator.evalOffchainInput({
3174
3218
  amount: BigInt(v.value),
3175
3219
  type: v.virtualStatus.state === "swept" ? "recoverable" : "vtxo",
@@ -3189,7 +3233,7 @@ var VtxoManager = class _VtxoManager {
3189
3233
  const arkAddress = await this.wallet.getAddress();
3190
3234
  const outputFee = estimator.evalOffchainOutput({
3191
3235
  amount: totalAmount,
3192
- script: base.hex.encode(chunkWMIPYZSB_cjs.ArkAddress.decode(arkAddress).pkScript)
3236
+ script: base.hex.encode(chunkCMPJR3HS_cjs.ArkAddress.decode(arkAddress).pkScript)
3193
3237
  });
3194
3238
  totalAmount -= BigInt(outputFee.satoshis);
3195
3239
  if (totalAmount < dustAmount) return;
@@ -3270,7 +3314,7 @@ var ArkNote = class _ArkNote {
3270
3314
  this.value = value;
3271
3315
  this.HRP = HRP;
3272
3316
  const preimageHash = utils_js.sha256(this.preimage);
3273
- this.vtxoScript = new chunkWMIPYZSB_cjs.VtxoScript([noteTapscript(preimageHash)]);
3317
+ this.vtxoScript = new chunkCMPJR3HS_cjs.VtxoScript([noteTapscript(preimageHash)]);
3274
3318
  const leaf = this.vtxoScript.leaves[0];
3275
3319
  this.txid = base.hex.encode(new Uint8Array(preimageHash).reverse());
3276
3320
  this.tapTree = this.vtxoScript.encode();
@@ -3884,7 +3928,7 @@ var AssetManager = class extends ReadonlyAssetManager {
3884
3928
  const virtualCoins = await this.wallet.getVtxos({
3885
3929
  withRecoverable: false
3886
3930
  });
3887
- const controlAssetRef = params.controlAssetId ? chunk6FLL2Q36_cjs.AssetRef.fromId(chunk6FLL2Q36_cjs.AssetId.fromString(params.controlAssetId)) : null;
3931
+ const controlAssetRef = params.controlAssetId ? chunkFSAXPBGP_cjs.AssetRef.fromId(chunkFSAXPBGP_cjs.AssetId.fromString(params.controlAssetId)) : null;
3888
3932
  const coinSelection = selectVirtualCoins(virtualCoins, Number(this.wallet.dustAmount));
3889
3933
  let totalBtcSelected = 0n;
3890
3934
  const assetChanges = /* @__PURE__ */ new Map();
@@ -3897,8 +3941,8 @@ var AssetManager = class extends ReadonlyAssetManager {
3897
3941
  }
3898
3942
  }
3899
3943
  const groups = [];
3900
- const issuedAssetOutput = chunk6FLL2Q36_cjs.AssetOutput.create(0, params.amount);
3901
- const issuedAssetGroup = chunk6FLL2Q36_cjs.AssetGroup.create(
3944
+ const issuedAssetOutput = chunkFSAXPBGP_cjs.AssetOutput.create(0, params.amount);
3945
+ const issuedAssetGroup = chunkFSAXPBGP_cjs.AssetGroup.create(
3902
3946
  null,
3903
3947
  controlAssetRef,
3904
3948
  [],
@@ -3913,28 +3957,28 @@ var AssetManager = class extends ReadonlyAssetManager {
3913
3957
  for (const [inputIndex, assets] of assetInputs) {
3914
3958
  for (const asset of assets) {
3915
3959
  if (asset.assetId !== assetId) continue;
3916
- changeInputs.push(chunk6FLL2Q36_cjs.AssetInput.create(inputIndex, asset.amount));
3960
+ changeInputs.push(chunkFSAXPBGP_cjs.AssetInput.create(inputIndex, asset.amount));
3917
3961
  }
3918
3962
  }
3919
3963
  groups.push(
3920
- chunk6FLL2Q36_cjs.AssetGroup.create(
3921
- chunk6FLL2Q36_cjs.AssetId.fromString(assetId),
3964
+ chunkFSAXPBGP_cjs.AssetGroup.create(
3965
+ chunkFSAXPBGP_cjs.AssetId.fromString(assetId),
3922
3966
  null,
3923
3967
  changeInputs,
3924
- [chunk6FLL2Q36_cjs.AssetOutput.create(0, amount)],
3968
+ [chunkFSAXPBGP_cjs.AssetOutput.create(0, amount)],
3925
3969
  []
3926
3970
  )
3927
3971
  );
3928
3972
  }
3929
3973
  }
3930
3974
  const address = await this.wallet.getAddress();
3931
- const outputAddress = chunkWMIPYZSB_cjs.ArkAddress.decode(address);
3975
+ const outputAddress = chunkCMPJR3HS_cjs.ArkAddress.decode(address);
3932
3976
  const outputs = [
3933
3977
  {
3934
3978
  script: outputAddress.pkScript,
3935
3979
  amount: BigInt(totalBtcSelected)
3936
3980
  },
3937
- Extension.create([chunk6FLL2Q36_cjs.Packet.create(groups)]).txOut()
3981
+ Extension.create([chunkFSAXPBGP_cjs.Packet.create(groups)]).txOut()
3938
3982
  ];
3939
3983
  const { arkTxid } = await this.wallet.buildAndSubmitOffchainTx(
3940
3984
  coinSelection.inputs,
@@ -3942,7 +3986,7 @@ var AssetManager = class extends ReadonlyAssetManager {
3942
3986
  );
3943
3987
  return {
3944
3988
  arkTxId: arkTxid,
3945
- assetId: chunk6FLL2Q36_cjs.AssetId.create(arkTxid, 0).toString()
3989
+ assetId: chunkFSAXPBGP_cjs.AssetId.create(arkTxid, 0).toString()
3946
3990
  };
3947
3991
  }
3948
3992
  /**
@@ -4014,16 +4058,16 @@ var AssetManager = class extends ReadonlyAssetManager {
4014
4058
  for (const [inputIndex, assets] of assetInputs) {
4015
4059
  for (const asset of assets) {
4016
4060
  if (asset.assetId !== params.assetId) continue;
4017
- reissueInputs.push(chunk6FLL2Q36_cjs.AssetInput.create(inputIndex, asset.amount));
4061
+ reissueInputs.push(chunkFSAXPBGP_cjs.AssetInput.create(inputIndex, asset.amount));
4018
4062
  }
4019
4063
  }
4020
4064
  const totalAssetAmount = assetToReissueAmount + params.amount;
4021
- const reissueAssetIdObj = chunk6FLL2Q36_cjs.AssetId.fromString(params.assetId);
4022
- const reissueAssetGroup = chunk6FLL2Q36_cjs.AssetGroup.create(
4065
+ const reissueAssetIdObj = chunkFSAXPBGP_cjs.AssetId.fromString(params.assetId);
4066
+ const reissueAssetGroup = chunkFSAXPBGP_cjs.AssetGroup.create(
4023
4067
  reissueAssetIdObj,
4024
4068
  null,
4025
4069
  reissueInputs,
4026
- [chunk6FLL2Q36_cjs.AssetOutput.create(0, totalAssetAmount)],
4070
+ [chunkFSAXPBGP_cjs.AssetOutput.create(0, totalAssetAmount)],
4027
4071
  []
4028
4072
  );
4029
4073
  const groups = [reissueAssetGroup];
@@ -4032,27 +4076,27 @@ var AssetManager = class extends ReadonlyAssetManager {
4032
4076
  for (const [inputIndex, assets] of assetInputs) {
4033
4077
  for (const asset of assets) {
4034
4078
  if (asset.assetId !== assetId) continue;
4035
- changeInputs.push(chunk6FLL2Q36_cjs.AssetInput.create(inputIndex, asset.amount));
4079
+ changeInputs.push(chunkFSAXPBGP_cjs.AssetInput.create(inputIndex, asset.amount));
4036
4080
  }
4037
4081
  }
4038
4082
  groups.push(
4039
- chunk6FLL2Q36_cjs.AssetGroup.create(
4040
- chunk6FLL2Q36_cjs.AssetId.fromString(assetId),
4083
+ chunkFSAXPBGP_cjs.AssetGroup.create(
4084
+ chunkFSAXPBGP_cjs.AssetId.fromString(assetId),
4041
4085
  null,
4042
4086
  changeInputs,
4043
- [chunk6FLL2Q36_cjs.AssetOutput.create(0, amount)],
4087
+ [chunkFSAXPBGP_cjs.AssetOutput.create(0, amount)],
4044
4088
  []
4045
4089
  )
4046
4090
  );
4047
4091
  }
4048
4092
  const address = await this.wallet.getAddress();
4049
- const outputAddress = chunkWMIPYZSB_cjs.ArkAddress.decode(address);
4093
+ const outputAddress = chunkCMPJR3HS_cjs.ArkAddress.decode(address);
4050
4094
  const outputs = [
4051
4095
  {
4052
4096
  script: outputAddress.pkScript,
4053
4097
  amount: BigInt(totalBtcSelected)
4054
4098
  },
4055
- Extension.create([chunk6FLL2Q36_cjs.Packet.create(groups)]).txOut()
4099
+ Extension.create([chunkFSAXPBGP_cjs.Packet.create(groups)]).txOut()
4056
4100
  ];
4057
4101
  const { arkTxid } = await this.wallet.buildAndSubmitOffchainTx(selectedCoins, outputs);
4058
4102
  return arkTxid;
@@ -4119,27 +4163,27 @@ var AssetManager = class extends ReadonlyAssetManager {
4119
4163
  for (const [inputIndex, assets] of assetInputs) {
4120
4164
  for (const asset of assets) {
4121
4165
  if (asset.assetId !== assetId) continue;
4122
- changeInputs.push(chunk6FLL2Q36_cjs.AssetInput.create(inputIndex, asset.amount));
4166
+ changeInputs.push(chunkFSAXPBGP_cjs.AssetInput.create(inputIndex, asset.amount));
4123
4167
  }
4124
4168
  }
4125
4169
  groups.push(
4126
- chunk6FLL2Q36_cjs.AssetGroup.create(
4127
- chunk6FLL2Q36_cjs.AssetId.fromString(assetId),
4170
+ chunkFSAXPBGP_cjs.AssetGroup.create(
4171
+ chunkFSAXPBGP_cjs.AssetId.fromString(assetId),
4128
4172
  null,
4129
4173
  changeInputs,
4130
- amount > 0n ? [chunk6FLL2Q36_cjs.AssetOutput.create(0, amount)] : [],
4174
+ amount > 0n ? [chunkFSAXPBGP_cjs.AssetOutput.create(0, amount)] : [],
4131
4175
  []
4132
4176
  )
4133
4177
  );
4134
4178
  }
4135
4179
  const address = await this.wallet.getAddress();
4136
- const outputAddress = chunkWMIPYZSB_cjs.ArkAddress.decode(address);
4180
+ const outputAddress = chunkCMPJR3HS_cjs.ArkAddress.decode(address);
4137
4181
  const outputs = [
4138
4182
  {
4139
4183
  script: outputAddress.pkScript,
4140
4184
  amount: BigInt(totalBtcSelected)
4141
4185
  },
4142
- Extension.create([chunk6FLL2Q36_cjs.Packet.create(groups)]).txOut()
4186
+ Extension.create([chunkFSAXPBGP_cjs.Packet.create(groups)]).txOut()
4143
4187
  ];
4144
4188
  const { arkTxid } = await this.wallet.buildAndSubmitOffchainTx(selectedCoins, outputs);
4145
4189
  return arkTxid;
@@ -4164,7 +4208,7 @@ function castMetadata(metadata) {
4164
4208
  } else {
4165
4209
  throw new Error("Invalid metadata value type");
4166
4210
  }
4167
- md.push(chunk6FLL2Q36_cjs.Metadata.create(textEncoder.encode(key), valueBytes));
4211
+ md.push(chunkFSAXPBGP_cjs.Metadata.create(textEncoder.encode(key), valueBytes));
4168
4212
  }
4169
4213
  return md;
4170
4214
  }
@@ -4182,7 +4226,7 @@ var DelegateManagerImpl = class {
4182
4226
  if (vtxos.length === 0) {
4183
4227
  return { delegated: [], failed: [] };
4184
4228
  }
4185
- const destinationScript = chunkWMIPYZSB_cjs.ArkAddress.decode(destination).pkScript;
4229
+ const destinationScript = chunkCMPJR3HS_cjs.ArkAddress.decode(destination).pkScript;
4186
4230
  const arkInfo = await this.arkInfoProvider.getInfo();
4187
4231
  const delegateInfo = await this.delegateProvider.getDelegateInfo();
4188
4232
  const eligible = vtxos.filter(
@@ -4330,7 +4374,7 @@ async function delegate(identity, delegateProvider, arkInfo, delegateInfo, vtxos
4330
4374
  const delegateFee = BigInt(Number(fee));
4331
4375
  if (delegateFee > 0n) {
4332
4376
  outputs.push({
4333
- script: chunkWMIPYZSB_cjs.ArkAddress.decode(delegateAddress).pkScript,
4377
+ script: chunkCMPJR3HS_cjs.ArkAddress.decode(delegateAddress).pkScript,
4334
4378
  amount: delegateFee
4335
4379
  });
4336
4380
  }
@@ -4363,7 +4407,7 @@ async function delegate(identity, delegateProvider, arkInfo, delegateInfo, vtxos
4363
4407
  destinationScript
4364
4408
  );
4365
4409
  const forfeitOutputScript = btcSigner.OutScript.encode(
4366
- btcSigner.Address(chunkWMIPYZSB_cjs.getNetwork(network)).decode(forfeitAddress)
4410
+ btcSigner.Address(chunkCMPJR3HS_cjs.getNetwork(network)).decode(forfeitAddress)
4367
4411
  );
4368
4412
  const forfeits = await Promise.all(
4369
4413
  vtxos.filter((v) => !isRecoverable(v)).map(async (coin) => {
@@ -4391,7 +4435,7 @@ async function makeDelegateForfeitTx(input, connectorAmount, delegatePubkey, for
4391
4435
  index: input.vout,
4392
4436
  witnessUtxo: {
4393
4437
  amount: BigInt(input.value),
4394
- script: chunkWMIPYZSB_cjs.VtxoScript.decode(input.tapTree).pkScript
4438
+ script: chunkCMPJR3HS_cjs.VtxoScript.decode(input.tapTree).pkScript
4395
4439
  },
4396
4440
  sighashType: btcSigner.SigHash.ALL_ANYONECANPAY,
4397
4441
  tapLeafScript: [delegateTapLeaf]
@@ -4449,7 +4493,7 @@ async function makeSignedDelegateIntent(identity, coins, outputs, onchainOutputs
4449
4493
  expire_at: 0,
4450
4494
  cosigners_public_keys: cosignerPubKeys
4451
4495
  };
4452
- const proof = chunk6FLL2Q36_cjs.Intent.create(message, coins, outputs);
4496
+ const proof = chunkFSAXPBGP_cjs.Intent.create(message, coins, outputs);
4453
4497
  const signedProof = await identity.sign(proof);
4454
4498
  return {
4455
4499
  proof: base.base64.encode(signedProof.toPSBT()),
@@ -4467,10 +4511,10 @@ function getDayTimestamp(timestamp) {
4467
4511
  function findDelegateTapLeaf(vtxo, delegatePubkey) {
4468
4512
  if (!vtxo.tapTree) return void 0;
4469
4513
  const pk = delegatePubkey.length === 66 ? delegatePubkey.slice(2) : delegatePubkey;
4470
- const vtxoScript = chunkWMIPYZSB_cjs.VtxoScript.decode(vtxo.tapTree);
4514
+ const vtxoScript = chunkCMPJR3HS_cjs.VtxoScript.decode(vtxo.tapTree);
4471
4515
  return vtxoScript.leaves.find((tapLeaf) => {
4472
- const arkTapscript = chunkWMIPYZSB_cjs.decodeTapscript(chunkWMIPYZSB_cjs.scriptFromTapLeafScript(tapLeaf));
4473
- if (!chunkWMIPYZSB_cjs.MultisigTapscript.is(arkTapscript)) return false;
4516
+ const arkTapscript = chunkCMPJR3HS_cjs.decodeTapscript(chunkCMPJR3HS_cjs.scriptFromTapLeafScript(tapLeaf));
4517
+ if (!chunkCMPJR3HS_cjs.MultisigTapscript.is(arkTapscript)) return false;
4474
4518
  return arkTapscript.params.pubkeys.map(base.hex.encode).includes(pk);
4475
4519
  });
4476
4520
  }
@@ -4674,7 +4718,7 @@ var InMemoryContractRepository = class {
4674
4718
  }
4675
4719
  };
4676
4720
  function scriptFromArkAddress(address) {
4677
- return base.hex.encode(chunkWMIPYZSB_cjs.ArkAddress.decode(address).pkScript);
4721
+ return base.hex.encode(chunkCMPJR3HS_cjs.ArkAddress.decode(address).pkScript);
4678
4722
  }
4679
4723
 
4680
4724
  // src/repositories/indexedDB/schema.ts
@@ -6189,7 +6233,7 @@ var ContractWatcher = class {
6189
6233
  this.connectionState = "connected";
6190
6234
  this.reconnectAttempts = 0;
6191
6235
  this.listenLoop().catch((e) => {
6192
- if (chunk6FLL2Q36_cjs.isEventSourceError(e)) {
6236
+ if (chunkFSAXPBGP_cjs.isEventSourceError(e)) {
6193
6237
  console.debug("ContractWatcher subscription disconnected; reconnecting");
6194
6238
  } else {
6195
6239
  console.error(e);
@@ -6527,8 +6571,11 @@ function cursorCutoff(requestStartedAt) {
6527
6571
  }
6528
6572
 
6529
6573
  // src/contracts/contractManager.ts
6530
- var DEFAULT_PAGE_SIZE = 500;
6574
+ function areCoalescibleContractTypes(a, b) {
6575
+ return a === "default" && b === "boarding" || a === "boarding" && b === "default";
6576
+ }
6531
6577
  var SCAN_MAX_INDEX = 1e4;
6578
+ var DEFAULT_SCAN_BATCH = 10;
6532
6579
  var ContractManager = class _ContractManager {
6533
6580
  config;
6534
6581
  watcher;
@@ -6629,7 +6676,7 @@ var ContractManager = class _ContractManager {
6629
6676
  * `persisted` is `true`.
6630
6677
  */
6631
6678
  async upsertContract(params) {
6632
- const handler = chunkIEO3XDKI_cjs.contractHandlers.get(params.type);
6679
+ const handler = chunkGUTKJMSF_cjs.contractHandlers.get(params.type);
6633
6680
  if (!handler) {
6634
6681
  throw new Error(`No handler registered for contract type '${params.type}'`);
6635
6682
  }
@@ -6652,8 +6699,11 @@ var ContractManager = class _ContractManager {
6652
6699
  const [existing] = await this.getContracts({ script: params.script });
6653
6700
  if (existing) {
6654
6701
  if (existing.type === params.type) return { contract: existing, persisted: false };
6702
+ if (areCoalescibleContractTypes(existing.type, params.type)) {
6703
+ return { contract: existing, persisted: false };
6704
+ }
6655
6705
  throw new Error(
6656
- `Contract with script ${params.script} already exists with with type ${existing.type}.`
6706
+ `Contract with script ${params.script} already exists with type ${existing.type}.`
6657
6707
  );
6658
6708
  }
6659
6709
  const contract = {
@@ -6682,6 +6732,19 @@ var ContractManager = class _ContractManager {
6682
6732
  * other handler hit it).
6683
6733
  * - `persistAndWatchContract` rejecting is operational/fatal and
6684
6734
  * propagates (only `discoverAt` is guarded).
6735
+ * - Within an index the handler probes run concurrently (independent
6736
+ * network reads); their hits are persisted sequentially in
6737
+ * `discoverables` order to preserve the first-wins collision tie-break.
6738
+ * - Indices are probed `batchSize` at a time (a second concurrency layer
6739
+ * over the per-index probes), but each window is CAPPED to
6740
+ * `gapLimit - unused` indices — the most a serial scan could still reach
6741
+ * before the gap window is guaranteed to close. So every index probed in
6742
+ * a window is one a one-index-at-a-time scan would also reach: nothing is
6743
+ * over-scanned, nothing is discarded, and `materialize`/`discoverAt` are
6744
+ * invoked on exactly the same index set. The window's hits are still
6745
+ * processed strictly in ascending index order, so the discovered set,
6746
+ * persisted rows, `lastIndexUsed`, and `handlerErrors` are byte-for-byte
6747
+ * identical to the serial path — only the wall-clock differs.
6685
6748
  */
6686
6749
  async scanContracts(opts) {
6687
6750
  const gapLimit = opts.gapLimit ?? 20;
@@ -6690,35 +6753,69 @@ var ContractManager = class _ContractManager {
6690
6753
  `scanContracts: gapLimit must be a positive integer (got ${String(opts.gapLimit)})`
6691
6754
  );
6692
6755
  }
6693
- const discoverables = chunkIEO3XDKI_cjs.contractHandlers.getRegisteredTypes().map((t) => chunkIEO3XDKI_cjs.contractHandlers.get(t)).filter(isDiscoverable);
6756
+ const batchSize = opts.batchSize ?? DEFAULT_SCAN_BATCH;
6757
+ if (!Number.isInteger(batchSize) || batchSize <= 0) {
6758
+ throw new Error(
6759
+ `scanContracts: batchSize must be a positive integer (got ${String(opts.batchSize)})`
6760
+ );
6761
+ }
6762
+ const registered = chunkGUTKJMSF_cjs.contractHandlers.getRegisteredTypes().map((t) => chunkGUTKJMSF_cjs.contractHandlers.get(t)).filter(isDiscoverable);
6763
+ const discoverables = [
6764
+ ...registered.filter((h) => h.type === "boarding"),
6765
+ ...registered.filter((h) => h.type !== "boarding")
6766
+ ];
6694
6767
  const maxIdx = opts.hd ? SCAN_MAX_INDEX : 0;
6695
6768
  const handlerErrors = [];
6696
6769
  let lastIndexUsed = -1;
6697
6770
  let unused = 0;
6698
6771
  let i = 0;
6772
+ const probeIndex = async (index) => {
6773
+ const descriptor = opts.materialize(index);
6774
+ return Promise.all(
6775
+ discoverables.map(async (h) => {
6776
+ try {
6777
+ return {
6778
+ ok: true,
6779
+ found: await h.discoverAt(index, descriptor, opts.deps)
6780
+ };
6781
+ } catch (error) {
6782
+ return { ok: false, error };
6783
+ }
6784
+ })
6785
+ );
6786
+ };
6699
6787
  while (i <= maxIdx && unused < gapLimit) {
6700
- const descriptor = opts.materialize(i);
6701
- let hitAtThisIndex = false;
6702
- for (const h of discoverables) {
6703
- let found;
6704
- try {
6705
- found = await h.discoverAt(i, descriptor, opts.deps);
6706
- } catch (error) {
6707
- handlerErrors.push({ handler: h.type, index: i, error });
6708
- continue;
6788
+ const windowEnd = Math.min(maxIdx, i + Math.min(batchSize, gapLimit - unused) - 1);
6789
+ const windowIndices = [];
6790
+ for (let idx = i; idx <= windowEnd; idx++) windowIndices.push(idx);
6791
+ const windowProbes = await Promise.all(windowIndices.map(probeIndex));
6792
+ for (let w = 0; w < windowIndices.length; w++) {
6793
+ const index = windowIndices[w];
6794
+ const probes = windowProbes[w];
6795
+ let hitAtThisIndex = false;
6796
+ for (let h = 0; h < discoverables.length; h++) {
6797
+ const probe = probes[h];
6798
+ if (!probe.ok) {
6799
+ handlerErrors.push({
6800
+ handler: discoverables[h].type,
6801
+ index,
6802
+ error: probe.error
6803
+ });
6804
+ continue;
6805
+ }
6806
+ for (const c of probe.found) {
6807
+ await this.persistAndWatchContract(c);
6808
+ hitAtThisIndex = true;
6809
+ }
6709
6810
  }
6710
- for (const c of found) {
6711
- await this.persistAndWatchContract(c);
6712
- hitAtThisIndex = true;
6811
+ if (hitAtThisIndex) {
6812
+ lastIndexUsed = index;
6813
+ unused = 0;
6814
+ } else {
6815
+ unused += 1;
6713
6816
  }
6714
6817
  }
6715
- if (hitAtThisIndex) {
6716
- lastIndexUsed = i;
6717
- unused = 0;
6718
- } else {
6719
- unused += 1;
6720
- }
6721
- i += 1;
6818
+ i = windowEnd + 1;
6722
6819
  }
6723
6820
  if (opts.hd && i > maxIdx && unused < gapLimit) {
6724
6821
  throw new Error(
@@ -6846,7 +6943,7 @@ var ContractManager = class _ContractManager {
6846
6943
  const { contractScript, collaborative = true, walletPubKey, vtxo } = options;
6847
6944
  const [contract] = await this.getContracts({ script: contractScript });
6848
6945
  if (!contract) return [];
6849
- const handler = chunkIEO3XDKI_cjs.contractHandlers.get(contract.type);
6946
+ const handler = chunkGUTKJMSF_cjs.contractHandlers.get(contract.type);
6850
6947
  if (!handler) return [];
6851
6948
  const script = handler.createScript(contract.params);
6852
6949
  const context = {
@@ -6866,7 +6963,7 @@ var ContractManager = class _ContractManager {
6866
6963
  const { contractScript, collaborative = true, walletPubKey } = options;
6867
6964
  const [contract] = await this.getContracts({ script: contractScript });
6868
6965
  if (!contract) return [];
6869
- const handler = chunkIEO3XDKI_cjs.contractHandlers.get(contract.type);
6966
+ const handler = chunkGUTKJMSF_cjs.contractHandlers.get(contract.type);
6870
6967
  if (!handler) return [];
6871
6968
  const script = handler.createScript(contract.params);
6872
6969
  const context = {
@@ -7100,7 +7197,7 @@ var ContractManager = class _ContractManager {
7100
7197
  }
7101
7198
  return result;
7102
7199
  }
7103
- async fetchContractVtxosBulk(contracts, pageSize = DEFAULT_PAGE_SIZE, syncWindow) {
7200
+ async fetchContractVtxosBulk(contracts, pageSize = chunkGUTKJMSF_cjs.DEFAULT_PAGE_SIZE, syncWindow) {
7104
7201
  if (contracts.length === 0) {
7105
7202
  return /* @__PURE__ */ new Map();
7106
7203
  }
@@ -7276,7 +7373,7 @@ var HDDescriptorProvider = class _HDDescriptorProvider {
7276
7373
  */
7277
7374
  materializeDescriptorAt(index) {
7278
7375
  const descriptor = this.identity.descriptor;
7279
- const network = chunkIEO3XDKI_cjs.isMainnetDescriptor(descriptor) ? descriptorsScure.networks.bitcoin : descriptorsScure.networks.testnet;
7376
+ const network = chunkGUTKJMSF_cjs.isMainnetDescriptor(descriptor) ? descriptorsScure.networks.bitcoin : descriptorsScure.networks.testnet;
7280
7377
  const expansion = descriptorsScure.expand({ descriptor, network, index });
7281
7378
  const keyInfo = expansion.expansionMap?.["@0"];
7282
7379
  if (!keyInfo?.keyExpression) {
@@ -7419,12 +7516,13 @@ var WalletReceiveRotator = class _WalletReceiveRotator {
7419
7516
  const provider = await resolveDescriptorProvider(config, setup.walletRepository);
7420
7517
  if (!provider) return void 0;
7421
7518
  const allowSilentFallback = (config.walletMode ?? "auto") === "auto";
7422
- const expectedContractType = setup.offchainTapscript instanceof chunkIEO3XDKI_cjs.DelegateVtxo.Script ? "delegate" : "default";
7519
+ const expectedContractType = setup.offchainTapscript instanceof chunkGUTKJMSF_cjs.DelegateVtxo.Script ? "delegate" : "default";
7423
7520
  const factoryOpts = {
7424
7521
  walletRepository: setup.walletRepository,
7425
7522
  contractRepository: setup.contractRepository,
7426
7523
  serverPubKey: setup.serverPubKey,
7427
- expectedContractType
7524
+ expectedContractType,
7525
+ baselineReceivePubKey: setup.offchainTapscript.options.pubKey
7428
7526
  };
7429
7527
  let boot;
7430
7528
  try {
@@ -7469,14 +7567,17 @@ var WalletReceiveRotator = class _WalletReceiveRotator {
7469
7567
  receivePubkey: existing.pubKey
7470
7568
  };
7471
7569
  }
7472
- let descriptor;
7473
- if (hasPeekableDescriptor(provider)) {
7474
- descriptor = await provider.getCurrentSigningDescriptor();
7570
+ const current = hasPeekableDescriptor(provider) ? await provider.getCurrentSigningDescriptor() : void 0;
7571
+ if (current === void 0) {
7572
+ const descriptor = await provider.getNextSigningDescriptor();
7573
+ return {
7574
+ rotator: new _WalletReceiveRotator(provider, void 0, opts.logger),
7575
+ receivePubkey: deriveLeafPubkey(descriptor)
7576
+ };
7475
7577
  }
7476
- descriptor ??= await provider.getNextSigningDescriptor();
7477
7578
  return {
7478
7579
  rotator: new _WalletReceiveRotator(provider, void 0, opts.logger),
7479
- receivePubkey: deriveLeafPubkey(descriptor)
7580
+ receivePubkey: opts.baselineReceivePubKey ?? deriveLeafPubkey(current)
7480
7581
  };
7481
7582
  }
7482
7583
  /**
@@ -7581,8 +7682,8 @@ var WalletReceiveRotator = class _WalletReceiveRotator {
7581
7682
  const newScript = base.hex.encode(newTapscript.pkScript);
7582
7683
  const newAddress = newTapscript.address(wallet.network.hrp, wallet.arkServerPublicKey).encode();
7583
7684
  const manager = await wallet.getContractManager();
7584
- const csvTimelock = newTapscript.options.csvTimelock ?? chunkIEO3XDKI_cjs.DefaultVtxo.Script.DEFAULT_TIMELOCK;
7585
- const csvTimelockStr = chunkWMIPYZSB_cjs.timelockToSequence(csvTimelock).toString();
7685
+ const csvTimelock = newTapscript.options.csvTimelock;
7686
+ const csvTimelockStr = chunkCMPJR3HS_cjs.timelockToSequence(csvTimelock).toString();
7586
7687
  const serverPubKeyHex = base.hex.encode(newTapscript.options.serverPubKey);
7587
7688
  const baseParams = {
7588
7689
  script: newScript,
@@ -7596,11 +7697,11 @@ var WalletReceiveRotator = class _WalletReceiveRotator {
7596
7697
  // produce unsigned PSBTs that the server rejects with
7597
7698
  // `INVALID_PSBT_INPUT (5): missing tapscript spend sig`.
7598
7699
  metadata: {
7599
- source: chunkIEO3XDKI_cjs.WALLET_RECEIVE_SOURCE,
7700
+ source: chunkGUTKJMSF_cjs.WALLET_RECEIVE_SOURCE,
7600
7701
  signingDescriptor: descriptor
7601
7702
  }
7602
7703
  };
7603
- if (newTapscript instanceof chunkIEO3XDKI_cjs.DelegateVtxo.Script) {
7704
+ if (newTapscript instanceof chunkGUTKJMSF_cjs.DelegateVtxo.Script) {
7604
7705
  await manager.createContract({
7605
7706
  ...baseParams,
7606
7707
  type: "delegate",
@@ -7632,7 +7733,7 @@ var WalletReceiveRotator = class _WalletReceiveRotator {
7632
7733
  };
7633
7734
  function deriveLeafPubkey(descriptor) {
7634
7735
  try {
7635
- return chunkIEO3XDKI_cjs.deriveDescriptorLeafPubKey(descriptor);
7736
+ return chunkGUTKJMSF_cjs.deriveDescriptorLeafPubKey(descriptor);
7636
7737
  } catch (e) {
7637
7738
  throw new NonRangeableDescriptorError(
7638
7739
  "Cannot derive leaf pubkey: descriptor is not a materialized, parsable tr(...) shape.",
@@ -7641,10 +7742,10 @@ function deriveLeafPubkey(descriptor) {
7641
7742
  }
7642
7743
  }
7643
7744
  function rebuildTapscript(current, pubKey) {
7644
- if (current instanceof chunkIEO3XDKI_cjs.DelegateVtxo.Script) {
7645
- return new chunkIEO3XDKI_cjs.DelegateVtxo.Script({ ...current.options, pubKey });
7745
+ if (current instanceof chunkGUTKJMSF_cjs.DelegateVtxo.Script) {
7746
+ return new chunkGUTKJMSF_cjs.DelegateVtxo.Script({ ...current.options, pubKey });
7646
7747
  }
7647
- return new chunkIEO3XDKI_cjs.DefaultVtxo.Script({ ...current.options, pubKey });
7748
+ return new chunkGUTKJMSF_cjs.DefaultVtxo.Script({ ...current.options, pubKey });
7648
7749
  }
7649
7750
  async function pickActiveReceive(contractRepository, serverPubKey, expectedType) {
7650
7751
  const candidates = await contractRepository.getContracts({
@@ -7653,7 +7754,7 @@ async function pickActiveReceive(contractRepository, serverPubKey, expectedType)
7653
7754
  });
7654
7755
  const serverPubKeyHex = base.hex.encode(serverPubKey);
7655
7756
  const matching = candidates.filter(
7656
- (c) => c.params.serverPubKey === serverPubKeyHex && c.metadata?.source === chunkIEO3XDKI_cjs.WALLET_RECEIVE_SOURCE
7757
+ (c) => c.params.serverPubKey === serverPubKeyHex && c.metadata?.source === chunkGUTKJMSF_cjs.WALLET_RECEIVE_SOURCE
7657
7758
  ).sort((a, b) => {
7658
7759
  if (b.createdAt !== a.createdAt) return b.createdAt - a.createdAt;
7659
7760
  return signingDescriptorIndex(b.metadata?.signingDescriptor) - signingDescriptorIndex(a.metadata?.signingDescriptor);
@@ -7709,13 +7810,29 @@ var DescriptorSigningProviderMissingError = class extends Error {
7709
7810
  };
7710
7811
 
7711
7812
  // src/wallet/inputSignerRouter.ts
7712
- var DESCRIPTOR_CAPABLE_CONTRACT_TYPES = /* @__PURE__ */ new Set(["default", "delegate"]);
7813
+ var DESCRIPTOR_CAPABLE_CONTRACT_TYPES = /* @__PURE__ */ new Set(["default", "delegate", "boarding"]);
7713
7814
  var InputSignerRouter = class {
7714
7815
  constructor(deps) {
7715
7816
  this.deps = deps;
7716
7817
  }
7717
- async sign(tx, jobs) {
7718
- if (jobs.length === 0) return tx;
7818
+ /**
7819
+ * Resolve each job to its target signer without invoking signing. The
7820
+ * returned plan is the single source of truth for both {@link sign} and
7821
+ * the batch-eligibility predicate {@link canBatch} — callers that want
7822
+ * to pre-flight a batch path call {@link canBatch} (which delegates
7823
+ * here) so the routing rules never live in two places.
7824
+ *
7825
+ * Throws {@link MissingSigningDescriptorError} for a non-baseline
7826
+ * default/delegate contract whose `metadata.signingDescriptor` is
7827
+ * missing — the same condition that would later abort signing. Failing
7828
+ * here moves the failure earlier, before any PSBT is mutated.
7829
+ */
7830
+ async classify(jobs) {
7831
+ const identityIndexes = [];
7832
+ const descriptorGroups = /* @__PURE__ */ new Map();
7833
+ if (jobs.length === 0) {
7834
+ return { identityIndexes, descriptorGroups };
7835
+ }
7719
7836
  const distinctScripts = Array.from(new Set(jobs.map((j) => base.hex.encode(j.lookupScript))));
7720
7837
  const contracts = await this.deps.contractRepository.getContracts({
7721
7838
  script: distinctScripts
@@ -7728,8 +7845,6 @@ var InputSignerRouter = class {
7728
7845
  }
7729
7846
  const baselinePubKeyHex = base.hex.encode(await this.deps.identity.xOnlyPublicKey());
7730
7847
  const boardingScriptHex = base.hex.encode(this.deps.boardingPkScript);
7731
- const identityIndexes = [];
7732
- const descriptorGroups = /* @__PURE__ */ new Map();
7733
7848
  for (const job of jobs) {
7734
7849
  const scriptHex = base.hex.encode(job.lookupScript);
7735
7850
  const contract = scriptToContract.get(scriptHex);
@@ -7762,6 +7877,31 @@ var InputSignerRouter = class {
7762
7877
  descriptorGroups.set(descriptor, [job.index]);
7763
7878
  }
7764
7879
  }
7880
+ return { identityIndexes, descriptorGroups };
7881
+ }
7882
+ /**
7883
+ * Returns `true` when every signable input across all `jobSets` resolves
7884
+ * to the baseline {@link Identity} key — i.e. the descriptor provider
7885
+ * would not be invoked. Used by the wallet's send/recovery paths to
7886
+ * pre-flight the {@link BatchSignableIdentity.signMultiple} fast path,
7887
+ * which can only fold work a single identity key can sign.
7888
+ *
7889
+ * Accepts several job sets (e.g. an arkTx's jobs plus one set per
7890
+ * checkpoint) and classifies their union in a single pass. Eligibility
7891
+ * is monotonic — the union routes entirely to the baseline key iff every
7892
+ * set does — so this returns the same answer as ANDing the per-set
7893
+ * results, but with one {@link classify} (one repo round-trip + one
7894
+ * `xOnlyPublicKey` call) instead of one per set. Only the routing buckets
7895
+ * matter here, so the input-index collisions produced by flattening jobs
7896
+ * from different transactions are irrelevant.
7897
+ */
7898
+ async canBatch(...jobSets) {
7899
+ const plan = await this.classify(jobSets.flat());
7900
+ return plan.descriptorGroups.size === 0;
7901
+ }
7902
+ async sign(tx, jobs) {
7903
+ if (jobs.length === 0) return tx;
7904
+ const { identityIndexes, descriptorGroups } = await this.classify(jobs);
7765
7905
  let signed = tx;
7766
7906
  if (identityIndexes.length > 0) {
7767
7907
  signed = await this.deps.identity.sign(signed, identityIndexes);
@@ -7788,12 +7928,12 @@ var InputSignerRouter = class {
7788
7928
  };
7789
7929
 
7790
7930
  // src/wallet/wallet.ts
7791
- var getArkadeServerUrl = ({ arkServerUrl }) => arkServerUrl || chunkWMIPYZSB_cjs.DEFAULT_ARKADE_SERVER_URL;
7931
+ var getArkadeServerUrl = ({ arkServerUrl }) => arkServerUrl || chunkCMPJR3HS_cjs.DEFAULT_ARKADE_SERVER_URL;
7792
7932
  function intentProofJobs(coins) {
7793
7933
  if (coins.length === 0) return [];
7794
7934
  const coinJobs = coins.map((coin, i) => ({
7795
7935
  index: i + 1,
7796
- lookupScript: chunkWMIPYZSB_cjs.VtxoScript.decode(coin.tapTree).pkScript
7936
+ lookupScript: chunkCMPJR3HS_cjs.VtxoScript.decode(coin.tapTree).pkScript
7797
7937
  }));
7798
7938
  return [{ index: 0, lookupScript: coinJobs[0].lookupScript }, ...coinJobs];
7799
7939
  }
@@ -7802,6 +7942,11 @@ function extractArkProviderUrl(provider) {
7802
7942
  return typeof serverUrl === "string" && serverUrl.length > 0 ? serverUrl : void 0;
7803
7943
  }
7804
7944
  var MAINNET_UNILATERAL_EXIT_DELAY = 605184n;
7945
+ function toXOnlyPubKey(pubkey) {
7946
+ if (pubkey.length === 33) return pubkey.slice(1);
7947
+ if (pubkey.length === 32) return pubkey;
7948
+ throw new Error(`invalid signer pubkey length: expected 32 or 33, got ${pubkey.length}`);
7949
+ }
7805
7950
  function delayToTimelock(delay) {
7806
7951
  return {
7807
7952
  value: delay,
@@ -7812,13 +7957,37 @@ function dedupeTimelocks(timelocks) {
7812
7957
  const seen = /* @__PURE__ */ new Set();
7813
7958
  const deduped = [];
7814
7959
  for (const timelock of timelocks) {
7815
- const sequence = chunkWMIPYZSB_cjs.timelockToSequence(timelock).toString();
7960
+ const sequence = chunkCMPJR3HS_cjs.timelockToSequence(timelock).toString();
7816
7961
  if (seen.has(sequence)) continue;
7817
7962
  seen.add(sequence);
7818
7963
  deduped.push(timelock);
7819
7964
  }
7820
7965
  return deduped;
7821
7966
  }
7967
+ async function ensureWalletContract(manager, params) {
7968
+ await manager.createContract(params);
7969
+ }
7970
+ async function resolveBoardingBootTapscript(contractRepository, serverPubKey, baseline) {
7971
+ const serverPubKeyHex = base.hex.encode(serverPubKey);
7972
+ const candidates = await contractRepository.getContracts({
7973
+ type: ["boarding"],
7974
+ state: "active"
7975
+ });
7976
+ const newest = candidates.filter(
7977
+ (c) => c.params.serverPubKey === serverPubKeyHex && c.metadata?.source === chunkGUTKJMSF_cjs.WALLET_RECEIVE_SOURCE
7978
+ ).sort((a, b) => {
7979
+ if (b.createdAt !== a.createdAt) return b.createdAt - a.createdAt;
7980
+ return signingDescriptorIndex(b.metadata?.signingDescriptor) - signingDescriptorIndex(a.metadata?.signingDescriptor);
7981
+ })[0];
7982
+ if (!newest?.params.pubKey) return baseline;
7983
+ try {
7984
+ const pubKey = base.hex.decode(newest.params.pubKey);
7985
+ return new chunkGUTKJMSF_cjs.DefaultVtxo.Script({ ...baseline.options, pubKey });
7986
+ } catch (e) {
7987
+ console.warn("Skipping malformed boarding contract at boot", newest.script, e);
7988
+ return baseline;
7989
+ }
7990
+ }
7822
7991
  function hasToReadonly(identity) {
7823
7992
  return typeof identity === "object" && identity !== null && "toReadonly" in identity && typeof identity.toReadonly === "function";
7824
7993
  }
@@ -7829,7 +7998,6 @@ var ReadonlyWallet = class _ReadonlyWallet {
7829
7998
  this.onchainProvider = onchainProvider;
7830
7999
  this.indexerProvider = indexerProvider;
7831
8000
  this.arkServerPublicKey = arkServerPublicKey;
7832
- this.boardingTapscript = boardingTapscript;
7833
8001
  this.dustAmount = dustAmount;
7834
8002
  this.walletRepository = walletRepository;
7835
8003
  this.contractRepository = contractRepository;
@@ -7845,11 +8013,10 @@ var ReadonlyWallet = class _ReadonlyWallet {
7845
8013
  }
7846
8014
  }
7847
8015
  this._offchainTapscript = offchainTapscript;
8016
+ this._boardingTapscript = boardingTapscript;
7848
8017
  this.watcherConfig = watcherConfig;
7849
8018
  this._assetManager = new ReadonlyAssetManager(this.indexerProvider);
7850
- this.walletContractTimelocks = walletContractTimelocks && walletContractTimelocks.length > 0 ? dedupeTimelocks(walletContractTimelocks) : [
7851
- this.offchainTapscript.options.csvTimelock ?? chunkIEO3XDKI_cjs.DefaultVtxo.Script.DEFAULT_TIMELOCK
7852
- ];
8019
+ this.walletContractTimelocks = walletContractTimelocks && walletContractTimelocks.length > 0 ? dedupeTimelocks(walletContractTimelocks) : [this.offchainTapscript.options.csvTimelock];
7853
8020
  }
7854
8021
  _contractManager;
7855
8022
  _contractManagerInitializing;
@@ -7873,6 +8040,17 @@ var ReadonlyWallet = class _ReadonlyWallet {
7873
8040
  * {@link WalletReceiveRotator.rotate} is the sole intended caller of.
7874
8041
  */
7875
8042
  _offchainTapscript;
8043
+ /**
8044
+ * Backing field for the current boarding tapscript (the QR / onboarding
8045
+ * target). Read via the public `boardingTapscript` getter; written only
8046
+ * by {@link Wallet.setBoardingTapscriptForRotation}, the sanctioned
8047
+ * boarding-rotation write path (analogue of `_offchainTapscript`). It is
8048
+ * a *current value*, not a fixed setup constant, because per-derivation
8049
+ * boarding rotation (plan §6-II) swaps it when a fresh boarding address
8050
+ * is explicitly allocated. Static / `auto` wallets never rotate it, so
8051
+ * it stays the index-0 baseline for their lifetime.
8052
+ */
8053
+ _boardingTapscript;
7876
8054
  /**
7877
8055
  * Currently-active receive tapscript. Read-only from the outside;
7878
8056
  * mutated only via {@link Wallet.setOffchainTapscriptForRotation}
@@ -7881,13 +8059,59 @@ var ReadonlyWallet = class _ReadonlyWallet {
7881
8059
  get offchainTapscript() {
7882
8060
  return this._offchainTapscript;
7883
8061
  }
8062
+ /**
8063
+ * The wallet's current boarding tapscript (the on-chain onboarding
8064
+ * target). Read-only from the outside; mutated only via
8065
+ * {@link Wallet.setBoardingTapscriptForRotation} when a fresh boarding
8066
+ * address is explicitly allocated. Single-valued for static / `auto`
8067
+ * wallets.
8068
+ */
8069
+ get boardingTapscript() {
8070
+ return this._boardingTapscript;
8071
+ }
8072
+ /**
8073
+ * Listeners fired after the boarding tapscript rotates to a fresh index
8074
+ * (see {@link Wallet.setBoardingTapscriptForRotation}). A live
8075
+ * {@link notifyIncomingFunds} onchain watcher registers one so it can
8076
+ * re-subscribe to include the newly allocated boarding address within the
8077
+ * same session — without it, a deposit to the fresh address wouldn't fire
8078
+ * a notification until the watcher's next re-init. Always empty for
8079
+ * readonly / static / `auto` wallets, which never rotate boarding.
8080
+ */
8081
+ _boardingRotationListeners = /* @__PURE__ */ new Set();
8082
+ /**
8083
+ * Register a listener invoked synchronously after each boarding rotation.
8084
+ * Returns an unsubscribe function. Protected: only internal subscribers
8085
+ * (the incoming-funds watcher) participate.
8086
+ */
8087
+ onBoardingRotation(listener) {
8088
+ this._boardingRotationListeners.add(listener);
8089
+ return () => {
8090
+ this._boardingRotationListeners.delete(listener);
8091
+ };
8092
+ }
8093
+ /**
8094
+ * Notify boarding-rotation listeners. Called by the boarding-rotation
8095
+ * write path ({@link Wallet.setBoardingTapscriptForRotation}) once the new
8096
+ * tapscript is in place. A throwing listener is isolated so it can neither
8097
+ * break the rotation nor starve sibling listeners.
8098
+ */
8099
+ notifyBoardingRotation() {
8100
+ for (const listener of this._boardingRotationListeners) {
8101
+ try {
8102
+ listener();
8103
+ } catch (e) {
8104
+ console.warn("Boarding-rotation listener failed", e);
8105
+ }
8106
+ }
8107
+ }
7884
8108
  /**
7885
8109
  * Protected helper to set up shared wallet configuration.
7886
8110
  * Extracts common logic used by both ReadonlyWallet.create() and Wallet.create().
7887
8111
  */
7888
8112
  static async setupWalletConfig(config, pubKey) {
7889
8113
  const arkadeServerUrl = getArkadeServerUrl(config);
7890
- const arkProvider = config.arkProvider || new chunk6FLL2Q36_cjs.RestArkProvider(arkadeServerUrl);
8114
+ const arkProvider = config.arkProvider || new chunkFSAXPBGP_cjs.RestArkProvider(arkadeServerUrl);
7891
8115
  let indexerProvider = config.indexerProvider;
7892
8116
  if (!indexerProvider) {
7893
8117
  let indexerUrl = config.indexerUrl;
@@ -7904,10 +8128,10 @@ var ReadonlyWallet = class _ReadonlyWallet {
7904
8128
  indexerUrl = arkadeServerUrl;
7905
8129
  }
7906
8130
  }
7907
- indexerProvider = new chunk6FLL2Q36_cjs.RestIndexerProvider(indexerUrl);
8131
+ indexerProvider = new chunkFSAXPBGP_cjs.RestIndexerProvider(indexerUrl);
7908
8132
  }
7909
8133
  const info = await arkProvider.getInfo();
7910
- const network = chunkWMIPYZSB_cjs.getNetwork(info.network);
8134
+ const network = chunkCMPJR3HS_cjs.getNetwork(info.network);
7911
8135
  if ("descriptor" in config.identity) {
7912
8136
  const descriptor = config.identity.descriptor;
7913
8137
  const identityIsMainnet = !descriptor.includes("tpub");
@@ -7954,10 +8178,11 @@ var ReadonlyWallet = class _ReadonlyWallet {
7954
8178
  serverPubKey,
7955
8179
  csvTimelock: exitTimelock
7956
8180
  };
7957
- const offchainTapscript = !delegatePubKey ? new chunkIEO3XDKI_cjs.DefaultVtxo.Script(offchainOptions) : new chunkIEO3XDKI_cjs.DelegateVtxo.Script({ ...offchainOptions, delegatePubKey });
7958
- const boardingTapscript = new chunkIEO3XDKI_cjs.DefaultVtxo.Script({
7959
- ...offchainOptions,
7960
- csvTimelock: boardingTimelock
8181
+ const offchainTapscript = !delegatePubKey ? new chunkGUTKJMSF_cjs.DefaultVtxo.Script(offchainOptions) : new chunkGUTKJMSF_cjs.DelegateVtxo.Script({ ...offchainOptions, delegatePubKey });
8182
+ const boardingTapscript = chunkGUTKJMSF_cjs.BoardingContractHandler.createScript({
8183
+ pubKey: base.hex.encode(pubKey),
8184
+ serverPubKey: base.hex.encode(serverPubKey),
8185
+ csvTimelock: chunkCMPJR3HS_cjs.timelockToSequence(boardingTimelock).toString()
7961
8186
  });
7962
8187
  const walletRepository = config.storage?.walletRepository ?? new IndexedDBWalletRepository();
7963
8188
  const contractRepository = config.storage?.contractRepository ?? new IndexedDBContractRepository();
@@ -8120,43 +8345,59 @@ var ReadonlyWallet = class _ReadonlyWallet {
8120
8345
  await clearSyncCursor(this.walletRepository);
8121
8346
  }
8122
8347
  /**
8123
- * Build a transaction history view for the wallet's boarding address.
8348
+ * The on-chain (P2TR) addresses of every boarding tapscript this wallet
8349
+ * uses — the current address plus any historical rotated boarding
8350
+ * addresses. The aggregating boarding readers (history, notifications) fan
8351
+ * out over this set so deposits at previous boarding addresses are still
8352
+ * surfaced (plan §6-IV); {@link getBoardingAddress} stays single-valued.
8353
+ */
8354
+ async getBoardingAddresses() {
8355
+ const tapscripts = await this.getBoardingTapscripts();
8356
+ return tapscripts.map((t) => t.onchainAddress(this.network));
8357
+ }
8358
+ /**
8359
+ * Build a transaction history view across the wallet's boarding addresses
8360
+ * (current + historical rotated; plan §6-IV.1).
8124
8361
  */
8125
8362
  async getBoardingTxs() {
8126
8363
  const utxos = [];
8127
8364
  const commitmentsToIgnore = /* @__PURE__ */ new Set();
8128
- const boardingAddress = await this.getBoardingAddress();
8129
- const txs = await this.onchainProvider.getTransactions(boardingAddress);
8365
+ const tapscripts = await this.getBoardingTapscripts();
8130
8366
  const outspendCache = /* @__PURE__ */ new Map();
8131
- for (const tx of txs) {
8132
- for (let i = 0; i < tx.vout.length; i++) {
8133
- const vout = tx.vout[i];
8134
- if (vout.scriptpubkey_address === boardingAddress) {
8135
- let spentStatuses = outspendCache.get(tx.txid);
8136
- if (!spentStatuses) {
8137
- spentStatuses = await this.onchainProvider.getTxOutspends(tx.txid);
8138
- outspendCache.set(tx.txid, spentStatuses);
8139
- }
8140
- const spentStatus = spentStatuses[i];
8141
- if (spentStatus?.spent) {
8142
- commitmentsToIgnore.add(spentStatus.txid);
8367
+ for (const tapscript of tapscripts) {
8368
+ const boardingAddress = tapscript.onchainAddress(this.network);
8369
+ const scriptHex = base.hex.encode(tapscript.pkScript);
8370
+ const txs = await this.onchainProvider.getTransactions(boardingAddress);
8371
+ for (const tx of txs) {
8372
+ for (let i = 0; i < tx.vout.length; i++) {
8373
+ const vout = tx.vout[i];
8374
+ if (vout.scriptpubkey_address === boardingAddress) {
8375
+ let spentStatuses = outspendCache.get(tx.txid);
8376
+ if (!spentStatuses) {
8377
+ spentStatuses = await this.onchainProvider.getTxOutspends(tx.txid);
8378
+ outspendCache.set(tx.txid, spentStatuses);
8379
+ }
8380
+ const spentStatus = spentStatuses[i];
8381
+ if (spentStatus?.spent) {
8382
+ commitmentsToIgnore.add(spentStatus.txid);
8383
+ }
8384
+ utxos.push({
8385
+ txid: tx.txid,
8386
+ vout: i,
8387
+ value: Number(vout.value),
8388
+ status: {
8389
+ confirmed: tx.status.confirmed,
8390
+ block_time: tx.status.block_time
8391
+ },
8392
+ isUnrolled: true,
8393
+ virtualStatus: {
8394
+ state: spentStatus?.spent ? "spent" : "settled",
8395
+ commitmentTxIds: spentStatus?.spent ? [spentStatus.txid] : void 0
8396
+ },
8397
+ createdAt: tx.status.confirmed ? new Date(tx.status.block_time * 1e3) : /* @__PURE__ */ new Date(0),
8398
+ script: scriptHex
8399
+ });
8143
8400
  }
8144
- utxos.push({
8145
- txid: tx.txid,
8146
- vout: i,
8147
- value: Number(vout.value),
8148
- status: {
8149
- confirmed: tx.status.confirmed,
8150
- block_time: tx.status.block_time
8151
- },
8152
- isUnrolled: true,
8153
- virtualStatus: {
8154
- state: spentStatus?.spent ? "spent" : "settled",
8155
- commitmentTxIds: spentStatus?.spent ? [spentStatus.txid] : void 0
8156
- },
8157
- createdAt: tx.status.confirmed ? new Date(tx.status.block_time * 1e3) : /* @__PURE__ */ new Date(0),
8158
- script: base.hex.encode(this.boardingTapscript.pkScript)
8159
- });
8160
8401
  }
8161
8402
  }
8162
8403
  }
@@ -8186,48 +8427,130 @@ var ReadonlyWallet = class _ReadonlyWallet {
8186
8427
  };
8187
8428
  }
8188
8429
  /**
8189
- * Fetch and cache onchain inputs (UTXOs) received at the boarding address.
8430
+ * The set of boarding tapscripts whose on-chain UTXOs belong to this
8431
+ * wallet — the current display tapscript plus every historical boarding
8432
+ * address it has used. Under per-derivation rotation (plan §6-II) a wallet
8433
+ * can hold unspent boarding UTXOs at several addresses at once, so fund
8434
+ * discovery / spending must enumerate them all, not just the current one
8435
+ * (plan §6-III.1). Deduplicated by scriptPubKey.
8436
+ *
8437
+ * Always includes the index-0 baseline (identity x-only key), which covers
8438
+ * the degenerate equal-delay case where the index-0 boarding row is
8439
+ * coalesced onto a `default` row and so isn't a `boarding`-typed contract.
8190
8440
  */
8191
- async getBoardingUtxos() {
8192
- const boardingAddress = await this.getBoardingAddress();
8193
- const boardingUtxos = await this.onchainProvider.getCoins(boardingAddress);
8194
- const utxos = boardingUtxos.map((utxo) => {
8195
- return extendCoin(this, utxo);
8441
+ async getBoardingTapscripts() {
8442
+ const byScript = /* @__PURE__ */ new Map();
8443
+ const add = (s) => byScript.set(base.hex.encode(s.pkScript), s);
8444
+ const boardingCsv = this.boardingTapscript.options.csvTimelock ?? chunkGUTKJMSF_cjs.DefaultVtxo.Script.DEFAULT_TIMELOCK;
8445
+ add(
8446
+ new chunkGUTKJMSF_cjs.DefaultVtxo.Script({
8447
+ pubKey: await this.identity.xOnlyPublicKey(),
8448
+ serverPubKey: this.boardingTapscript.options.serverPubKey,
8449
+ csvTimelock: boardingCsv
8450
+ })
8451
+ );
8452
+ add(this.boardingTapscript);
8453
+ const serverPubKeyHex = base.hex.encode(this.boardingTapscript.options.serverPubKey);
8454
+ const boardingContracts = await this.contractRepository.getContracts({
8455
+ type: ["boarding"]
8196
8456
  });
8197
- await this.walletRepository.saveUtxos(boardingAddress, utxos);
8198
- return utxos;
8457
+ for (const c of boardingContracts) {
8458
+ if (c.params.serverPubKey !== serverPubKeyHex) continue;
8459
+ try {
8460
+ add(chunkGUTKJMSF_cjs.BoardingContractHandler.createScript(c.params));
8461
+ } catch (e) {
8462
+ console.warn("Skipping malformed boarding contract", c.script, e);
8463
+ }
8464
+ }
8465
+ return [...byScript.values()];
8466
+ }
8467
+ /**
8468
+ * Fetch and cache onchain inputs (UTXOs) received at the wallet's boarding
8469
+ * addresses — the current address plus any historical rotated boarding
8470
+ * addresses that still hold unspent UTXOs (plan §6-III.1). Each UTXO is
8471
+ * annotated with the tapscript of the address it actually sits on, so the
8472
+ * spending path forfeits / exits it with the correct per-index leaves.
8473
+ */
8474
+ async getBoardingUtxos() {
8475
+ const tapscripts = await this.getBoardingTapscripts();
8476
+ const all = [];
8477
+ for (const tapscript of tapscripts) {
8478
+ const address = tapscript.onchainAddress(this.network);
8479
+ const coins = await this.onchainProvider.getCoins(address);
8480
+ const utxos = coins.map((utxo) => extendCoinWithTapscript(tapscript, utxo));
8481
+ await this.walletRepository.saveUtxos(address, utxos);
8482
+ all.push(...utxos);
8483
+ }
8484
+ return all;
8199
8485
  }
8200
8486
  /**
8201
8487
  * Subscribe to onchain and offchain notifications for newly received funds.
8202
8488
  *
8489
+ * The onchain watcher tracks the full boarding-address set (current +
8490
+ * historical rotated). When boarding rotates *after* subscribing — e.g.
8491
+ * rotate-on-board allocates a fresh address via
8492
+ * {@link getNewBoardingAddress} — the watcher automatically re-subscribes
8493
+ * to widen its set, so a deposit to the new address fires a notification
8494
+ * within the same session (no watcher re-init required). The re-subscribe
8495
+ * is driven by {@link onBoardingRotation}; static / `auto` / readonly
8496
+ * wallets never rotate boarding, so it never fires for them.
8497
+ *
8203
8498
  * @param eventCallback - Callback invoked when matching funds are detected
8204
8499
  * @returns A function that stops the subscriptions
8205
8500
  */
8206
8501
  async notifyIncomingFunds(eventCallback) {
8207
8502
  const arkAddress = await this.getAddress();
8208
- const boardingAddress = await this.getBoardingAddress();
8209
8503
  let onchainStopFunc;
8210
8504
  let indexerStopFunc;
8211
- if (this.onchainProvider && boardingAddress) {
8212
- const findVoutOnTx = (tx) => {
8213
- return tx.vout.findIndex((v) => v.scriptpubkey_address === boardingAddress);
8214
- };
8215
- onchainStopFunc = await this.onchainProvider.watchAddresses(
8216
- [boardingAddress],
8217
- (txs) => {
8218
- const coins = txs.filter((tx) => findVoutOnTx(tx) !== -1).map((tx) => {
8219
- const { txid, status } = tx;
8220
- const vout = findVoutOnTx(tx);
8221
- const value = Number(tx.vout[vout].value);
8222
- return { txid, vout, value, status };
8223
- });
8224
- eventCallback({
8225
- type: "utxo",
8226
- coins
8227
- });
8505
+ let boardingRotationStopFunc;
8506
+ let stopped = false;
8507
+ let onchainChain = Promise.resolve();
8508
+ const subscribeOnchain = () => {
8509
+ onchainChain = onchainChain.then(async () => {
8510
+ if (stopped || !this.onchainProvider) return;
8511
+ const boardingAddresses = await this.getBoardingAddresses();
8512
+ if (boardingAddresses.length === 0) return;
8513
+ const boardingAddressSet = new Set(boardingAddresses);
8514
+ const previousStop = onchainStopFunc;
8515
+ const stop = await this.onchainProvider.watchAddresses(
8516
+ boardingAddresses,
8517
+ (txs) => {
8518
+ const coins = txs.flatMap((tx) => {
8519
+ const { txid, status } = tx;
8520
+ const matched = [];
8521
+ tx.vout.forEach((v, vout) => {
8522
+ if (boardingAddressSet.has(v.scriptpubkey_address)) {
8523
+ matched.push({
8524
+ txid,
8525
+ vout,
8526
+ value: Number(v.value),
8527
+ status
8528
+ });
8529
+ }
8530
+ });
8531
+ return matched;
8532
+ });
8533
+ eventCallback({
8534
+ type: "utxo",
8535
+ coins
8536
+ });
8537
+ }
8538
+ );
8539
+ if (stopped) {
8540
+ stop();
8541
+ return;
8228
8542
  }
8229
- );
8230
- }
8543
+ onchainStopFunc = stop;
8544
+ previousStop?.();
8545
+ }).catch((e) => {
8546
+ console.warn("Failed to (re)subscribe boarding-funds watcher", e);
8547
+ });
8548
+ return onchainChain;
8549
+ };
8550
+ boardingRotationStopFunc = this.onBoardingRotation(() => {
8551
+ void subscribeOnchain();
8552
+ });
8553
+ await subscribeOnchain();
8231
8554
  if (this.indexerProvider && arkAddress) {
8232
8555
  const cm = await this.getContractManager();
8233
8556
  let annotationQueue = Promise.resolve();
@@ -8256,7 +8579,10 @@ var ReadonlyWallet = class _ReadonlyWallet {
8256
8579
  });
8257
8580
  }
8258
8581
  const stopFunc = () => {
8582
+ stopped = true;
8583
+ boardingRotationStopFunc?.();
8259
8584
  onchainStopFunc?.();
8585
+ onchainStopFunc = void 0;
8260
8586
  indexerStopFunc?.();
8261
8587
  };
8262
8588
  return stopFunc;
@@ -8297,7 +8623,7 @@ var ReadonlyWallet = class _ReadonlyWallet {
8297
8623
  });
8298
8624
  for (const contract of contracts) {
8299
8625
  if (map.has(contract.script)) continue;
8300
- const handler = chunkIEO3XDKI_cjs.contractHandlers.get(contract.type);
8626
+ const handler = chunkGUTKJMSF_cjs.contractHandlers.get(contract.type);
8301
8627
  if (handler) {
8302
8628
  const script = handler.createScript(contract.params);
8303
8629
  map.set(contract.script, script);
@@ -8363,14 +8689,14 @@ var ReadonlyWallet = class _ReadonlyWallet {
8363
8689
  });
8364
8690
  const baselinePubkey = await this.identity.xOnlyPublicKey();
8365
8691
  for (const csvTimelock of this.walletContractTimelocks) {
8366
- const csvTimelockStr = chunkWMIPYZSB_cjs.timelockToSequence(csvTimelock).toString();
8367
- const defaultScript = new chunkIEO3XDKI_cjs.DefaultVtxo.Script({
8692
+ const csvTimelockStr = chunkCMPJR3HS_cjs.timelockToSequence(csvTimelock).toString();
8693
+ const defaultScript = new chunkGUTKJMSF_cjs.DefaultVtxo.Script({
8368
8694
  pubKey: baselinePubkey,
8369
8695
  serverPubKey: this.offchainTapscript.options.serverPubKey,
8370
8696
  csvTimelock
8371
8697
  });
8372
8698
  const defaultScriptHex = base.hex.encode(defaultScript.pkScript);
8373
- await manager.createContract({
8699
+ await ensureWalletContract(manager, {
8374
8700
  type: "default",
8375
8701
  params: {
8376
8702
  pubKey: base.hex.encode(defaultScript.options.pubKey),
@@ -8381,8 +8707,8 @@ var ReadonlyWallet = class _ReadonlyWallet {
8381
8707
  address: defaultScript.address(this.network.hrp, this.arkServerPublicKey).encode(),
8382
8708
  state: "active"
8383
8709
  });
8384
- if (this.offchainTapscript instanceof chunkIEO3XDKI_cjs.DelegateVtxo.Script) {
8385
- const delegateScript = new chunkIEO3XDKI_cjs.DelegateVtxo.Script({
8710
+ if (this.offchainTapscript instanceof chunkGUTKJMSF_cjs.DelegateVtxo.Script) {
8711
+ const delegateScript = new chunkGUTKJMSF_cjs.DelegateVtxo.Script({
8386
8712
  pubKey: baselinePubkey,
8387
8713
  serverPubKey: this.offchainTapscript.options.serverPubKey,
8388
8714
  delegatePubKey: this.offchainTapscript.options.delegatePubKey,
@@ -8403,6 +8729,23 @@ var ReadonlyWallet = class _ReadonlyWallet {
8403
8729
  });
8404
8730
  }
8405
8731
  }
8732
+ const boardingCsvTimelock = this.boardingTapscript.options.csvTimelock ?? chunkGUTKJMSF_cjs.DefaultVtxo.Script.DEFAULT_TIMELOCK;
8733
+ const baselineBoarding = new chunkGUTKJMSF_cjs.DefaultVtxo.Script({
8734
+ pubKey: baselinePubkey,
8735
+ serverPubKey: this.boardingTapscript.options.serverPubKey,
8736
+ csvTimelock: boardingCsvTimelock
8737
+ });
8738
+ await ensureWalletContract(manager, {
8739
+ type: "boarding",
8740
+ params: {
8741
+ pubKey: base.hex.encode(baselineBoarding.options.pubKey),
8742
+ serverPubKey: base.hex.encode(baselineBoarding.options.serverPubKey),
8743
+ csvTimelock: chunkCMPJR3HS_cjs.timelockToSequence(boardingCsvTimelock).toString()
8744
+ },
8745
+ script: base.hex.encode(baselineBoarding.pkScript),
8746
+ address: baselineBoarding.address(this.network.hrp, this.arkServerPublicKey).encode(),
8747
+ state: "active"
8748
+ });
8406
8749
  return manager;
8407
8750
  }
8408
8751
  /** Dispose wallet-owned managers and release background resources. */
@@ -8500,6 +8843,72 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
8500
8843
  setOffchainTapscriptForRotation(tapscript) {
8501
8844
  this._offchainTapscript = tapscript;
8502
8845
  }
8846
+ /**
8847
+ * @internal Sole write path for `boardingTapscript` after construction.
8848
+ * Called by {@link Wallet.getNewBoardingAddress} once the rotated
8849
+ * boarding contract has been persisted. External code must treat
8850
+ * `boardingTapscript` as read-only.
8851
+ */
8852
+ setBoardingTapscriptForRotation(tapscript) {
8853
+ this._boardingTapscript = tapscript;
8854
+ this.notifyBoardingRotation();
8855
+ }
8856
+ /**
8857
+ * Allocate and return a *fresh* on-chain boarding address, rotating the
8858
+ * wallet's current boarding tapscript to a new HD index.
8859
+ *
8860
+ * This is the explicit boarding allocator — the analogue of dotnet's
8861
+ * `GetNextContract(NextContractPurpose.Boarding)`. Unlike
8862
+ * {@link getBoardingAddress} (a stable read of the current display
8863
+ * address that never burns an index), each call here:
8864
+ *
8865
+ * - allocates the next index from the shared HD stream (so boarding and
8866
+ * L2 receive interleave on one monotonic index);
8867
+ * - builds the boarding tapscript at that index with the boarding-exit
8868
+ * CSV;
8869
+ * - persists an `active` `boarding` contract tagged
8870
+ * {@link WALLET_RECEIVE_SOURCE} (with its `signingDescriptor`) so the
8871
+ * ContractWatcher monitors it, boot can restore it as the current
8872
+ * boarding address, and descriptor-aware signing can recover the
8873
+ * per-index key;
8874
+ * - swaps the wallet's current `boardingTapscript`.
8875
+ *
8876
+ * Gated by `walletMode`: a static / `auto` wallet has no descriptor
8877
+ * provider and keeps a single index-0 boarding address for its lifetime,
8878
+ * so this returns the existing {@link getBoardingAddress} unchanged
8879
+ * (no rotation, no index burned).
8880
+ */
8881
+ async getNewBoardingAddress() {
8882
+ const provider = this._descriptorProvider;
8883
+ if (!provider) {
8884
+ return this.getBoardingAddress();
8885
+ }
8886
+ const descriptor = await provider.getNextSigningDescriptor();
8887
+ const pubKey = chunkGUTKJMSF_cjs.deriveDescriptorLeafPubKey(descriptor);
8888
+ const newBoarding = new chunkGUTKJMSF_cjs.DefaultVtxo.Script({
8889
+ ...this._boardingTapscript.options,
8890
+ pubKey
8891
+ });
8892
+ const csvTimelock = newBoarding.options.csvTimelock ?? chunkGUTKJMSF_cjs.DefaultVtxo.Script.DEFAULT_TIMELOCK;
8893
+ const manager = await this.getContractManager();
8894
+ await manager.createContract({
8895
+ type: "boarding",
8896
+ params: {
8897
+ pubKey: base.hex.encode(pubKey),
8898
+ serverPubKey: base.hex.encode(newBoarding.options.serverPubKey),
8899
+ csvTimelock: chunkCMPJR3HS_cjs.timelockToSequence(csvTimelock).toString()
8900
+ },
8901
+ script: base.hex.encode(newBoarding.pkScript),
8902
+ address: newBoarding.address(this.network.hrp, this.arkServerPublicKey).encode(),
8903
+ state: "active",
8904
+ metadata: {
8905
+ source: chunkGUTKJMSF_cjs.WALLET_RECEIVE_SOURCE,
8906
+ signingDescriptor: descriptor
8907
+ }
8908
+ });
8909
+ this.setBoardingTapscriptForRotation(newBoarding);
8910
+ return newBoarding.onchainAddress(this.network);
8911
+ }
8503
8912
  /**
8504
8913
  * Async mutex that serializes all operations submitting VTXOs to the Arkade
8505
8914
  * server (`settle`, `send`, `sendBitcoin`). This prevents VtxoManager's
@@ -8583,13 +8992,26 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
8583
8992
  const hd = provider instanceof HDDescriptorProvider;
8584
8993
  const staticDescriptor = hd ? void 0 : `tr(${base.hex.encode(await this.identity.xOnlyPublicKey())})`;
8585
8994
  const materialize = (index) => hd ? provider.materializeDescriptorAt(index) : staticDescriptor;
8586
- const delegatePubKey = this.offchainTapscript instanceof chunkIEO3XDKI_cjs.DelegateVtxo.Script ? this.offchainTapscript.options.delegatePubKey : void 0;
8995
+ const delegatePubKey = this.offchainTapscript instanceof chunkGUTKJMSF_cjs.DelegateVtxo.Script ? this.offchainTapscript.options.delegatePubKey : void 0;
8996
+ const arkInfo = await this.arkProvider.getInfo();
8997
+ const currentSignerPubKey = toXOnlyPubKey(base.hex.decode(arkInfo.signerPubkey));
8998
+ const deprecatedSignerPubKeys = arkInfo.deprecatedSigners.map(
8999
+ (s) => toXOnlyPubKey(base.hex.decode(s.pubkey))
9000
+ );
8587
9001
  const deps = {
8588
9002
  indexerProvider: this.indexerProvider,
8589
9003
  onchainProvider: this.onchainProvider,
8590
9004
  network: { hrp: this.network.hrp },
8591
- serverPubKey: this.offchainTapscript.options.serverPubKey,
9005
+ // Full network for the boarding on-chain (P2TR) probe — the
9006
+ // `{ hrp }` shape above lacks the `bech32` data
9007
+ // `VtxoScript.onchainAddress` needs (plan §6-I.1).
9008
+ onchainNetwork: this.network,
9009
+ serverPubKey: currentSignerPubKey,
9010
+ deprecatedSignerPubKeys,
8592
9011
  csvTimelocks: this.walletContractTimelocks,
9012
+ // Boarding-exit CSV so the boarding handler can build its
9013
+ // candidate script (distinct from the unilateral-exit matrix).
9014
+ boardingTimelock: this.boardingTapscript.options.csvTimelock ?? chunkGUTKJMSF_cjs.DefaultVtxo.Script.DEFAULT_TIMELOCK,
8593
9015
  delegatePubKey
8594
9016
  };
8595
9017
  const result = await manager.scanContracts({
@@ -8690,7 +9112,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
8690
9112
  let serverUnrollScript;
8691
9113
  try {
8692
9114
  const raw = base.hex.decode(setup.info.checkpointTapscript);
8693
- serverUnrollScript = chunkWMIPYZSB_cjs.CSVMultisigTapscript.decode(raw);
9115
+ serverUnrollScript = chunkCMPJR3HS_cjs.CSVMultisigTapscript.decode(raw);
8694
9116
  } catch (e) {
8695
9117
  throw new Error("Invalid checkpointTapscript from server");
8696
9118
  }
@@ -8721,6 +9143,16 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
8721
9143
  boot?.rotator,
8722
9144
  boot?.provider
8723
9145
  );
9146
+ if (boot?.provider) {
9147
+ const resolvedBoarding = await resolveBoardingBootTapscript(
9148
+ setup.contractRepository,
9149
+ setup.serverPubKey,
9150
+ setup.boardingTapscript
9151
+ );
9152
+ if (resolvedBoarding !== setup.boardingTapscript) {
9153
+ wallet.setBoardingTapscriptForRotation(resolvedBoarding);
9154
+ }
9155
+ }
8724
9156
  await wallet.getVtxoManager();
8725
9157
  return wallet;
8726
9158
  }
@@ -8796,7 +9228,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
8796
9228
  inputs: params.selectedVtxos,
8797
9229
  changeAmount: BigInt(changeAmount)
8798
9230
  };
8799
- const outputAddress = chunkWMIPYZSB_cjs.ArkAddress.decode(params.address);
9231
+ const outputAddress = chunkCMPJR3HS_cjs.ArkAddress.decode(params.address);
8800
9232
  const outputScript = BigInt(params.amount) < this.dustAmount ? outputAddress.subdustPkScript : outputAddress.pkScript;
8801
9233
  const outputs = [
8802
9234
  {
@@ -8863,7 +9295,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
8863
9295
  const { fees } = await this.arkProvider.getInfo();
8864
9296
  const estimator = new Estimator(fees.intentFee);
8865
9297
  let amount = 0;
8866
- const exitScript = chunkWMIPYZSB_cjs.CSVMultisigTapscript.decode(
9298
+ const exitScript = chunkCMPJR3HS_cjs.CSVMultisigTapscript.decode(
8867
9299
  base.hex.decode(this.boardingTapscript.exitScript)
8868
9300
  );
8869
9301
  const boardingTimelock = exitScript.params.timelock;
@@ -8888,7 +9320,10 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
8888
9320
  }
8889
9321
  const vtxos = await this.getVtxos({ withRecoverable: true });
8890
9322
  const filteredVtxos = [];
8891
- for (const vtxo of vtxos) {
9323
+ for (const vtxo of byValueDescending(vtxos)) {
9324
+ if (filteredVtxos.length >= MAX_VTXOS_PER_SETTLEMENT) {
9325
+ break;
9326
+ }
8892
9327
  const inputFee = estimator.evalOffchainInput({
8893
9328
  amount: BigInt(vtxo.value),
8894
9329
  type: vtxo.virtualStatus.state === "swept" ? "recoverable" : "vtxo",
@@ -8912,7 +9347,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
8912
9347
  };
8913
9348
  const outputFee = estimator.evalOffchainOutput({
8914
9349
  amount: output.amount,
8915
- script: base.hex.encode(chunkWMIPYZSB_cjs.ArkAddress.decode(output.address).pkScript)
9350
+ script: base.hex.encode(chunkCMPJR3HS_cjs.ArkAddress.decode(output.address).pkScript)
8916
9351
  });
8917
9352
  output.amount -= BigInt(outputFee.satoshis);
8918
9353
  if (output.amount <= this.dustAmount) {
@@ -8929,7 +9364,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
8929
9364
  for (const [index, output] of params.outputs.entries()) {
8930
9365
  let script;
8931
9366
  try {
8932
- const addr = chunkWMIPYZSB_cjs.ArkAddress.decode(output.address);
9367
+ const addr = chunkCMPJR3HS_cjs.ArkAddress.decode(output.address);
8933
9368
  script = addr.pkScript;
8934
9369
  hasOffchainOutputs = true;
8935
9370
  } catch {
@@ -8952,7 +9387,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
8952
9387
  }
8953
9388
  }
8954
9389
  let outputAssets;
8955
- const destinationScript = chunkWMIPYZSB_cjs.ArkAddress.decode(await this.getAddress()).pkScript;
9390
+ const destinationScript = chunkCMPJR3HS_cjs.ArkAddress.decode(await this.getAddress()).pkScript;
8956
9391
  const assetOutputIndex = findDestinationOutputIndex(outputs, destinationScript);
8957
9392
  if (assetInputs.size > 0) {
8958
9393
  if (assetOutputIndex === -1) {
@@ -9021,6 +9456,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9021
9456
  eventCallback: eventCallback ? (event) => Promise.resolve(eventCallback(event)) : void 0
9022
9457
  });
9023
9458
  await this.updateDbAfterSettle(params.inputs, commitmentTxid);
9459
+ await this.maybeRotateBoardingAfterBoard(params.inputs);
9024
9460
  return commitmentTxid;
9025
9461
  } catch (error) {
9026
9462
  const inputIds = params.inputs.map((i) => `${i.txid}:${i.vout}`).join(",");
@@ -9038,6 +9474,41 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9038
9474
  });
9039
9475
  }
9040
9476
  }
9477
+ /**
9478
+ * Rotate the boarding address after a board (rotate-on-board trigger).
9479
+ *
9480
+ * Mirrors {@link WalletReceiveRotator}'s L2 rotation, but driven by a
9481
+ * board instead of a `vtxo_received` event: when a settle consumes at
9482
+ * least one boarding (on-chain) UTXO, the current boarding address has
9483
+ * served its purpose, so we allocate a fresh one via
9484
+ * {@link getNewBoardingAddress}. A settle that consumed only VTXOs (a
9485
+ * renewal / offboard) is not a board and leaves the boarding address
9486
+ * untouched.
9487
+ *
9488
+ * Boarding inputs are the non-VTXO coins (no `virtualStatus`), the same
9489
+ * discriminator {@link handleSettlementFinalizationEvent} uses; the
9490
+ * `typeof` guard skips arknote string inputs before the `in` test.
9491
+ *
9492
+ * No-ops for static / `auto` wallets (no descriptor provider — boarding
9493
+ * stays on its fixed index-0 address). Best-effort and non-fatal: the
9494
+ * settle has already committed and its txid must be returned, so a
9495
+ * rotation failure is logged and swallowed rather than thrown. Funds at
9496
+ * the retired boarding address remain discoverable — the old `boarding`
9497
+ * contract stays active and {@link getBoardingUtxos} fans out over the
9498
+ * full historical boarding set.
9499
+ */
9500
+ async maybeRotateBoardingAfterBoard(inputs) {
9501
+ if (!this._descriptorProvider) return;
9502
+ const consumedBoarding = inputs.some(
9503
+ (input) => typeof input !== "string" && !("virtualStatus" in input)
9504
+ );
9505
+ if (!consumedBoarding) return;
9506
+ try {
9507
+ await this.getNewBoardingAddress();
9508
+ } catch (e) {
9509
+ console.warn("Failed to rotate boarding address after board", e);
9510
+ }
9511
+ }
9041
9512
  async handleSettlementFinalizationEvent(event, inputs, forfeitOutputScript, connectorsGraph) {
9042
9513
  const signedForfeits = [];
9043
9514
  const isVtxo = (input) => "virtualStatus" in input;
@@ -9102,7 +9573,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9102
9573
  index: input.vout,
9103
9574
  witnessUtxo: {
9104
9575
  amount: BigInt(input.value),
9105
- script: chunkWMIPYZSB_cjs.VtxoScript.decode(input.tapTree).pkScript
9576
+ script: chunkCMPJR3HS_cjs.VtxoScript.decode(input.tapTree).pkScript
9106
9577
  },
9107
9578
  sighashType: btcSigner.SigHash.DEFAULT,
9108
9579
  tapLeafScript: [input.forfeitTapLeafScript]
@@ -9121,7 +9592,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9121
9592
  forfeitTx = await this._signerRouter.sign(forfeitTx, [
9122
9593
  {
9123
9594
  index: 0,
9124
- lookupScript: chunkWMIPYZSB_cjs.VtxoScript.decode(input.tapTree).pkScript
9595
+ lookupScript: chunkCMPJR3HS_cjs.VtxoScript.decode(input.tapTree).pkScript
9125
9596
  }
9126
9597
  ]);
9127
9598
  signedForfeits.push(base.base64.encode(forfeitTx.toPSBT()));
@@ -9161,7 +9632,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9161
9632
  if (skip) {
9162
9633
  return { skip };
9163
9634
  }
9164
- const sweepTapscript = chunkWMIPYZSB_cjs.CSVMultisigTapscript.encode({
9635
+ const sweepTapscript = chunkCMPJR3HS_cjs.CSVMultisigTapscript.encode({
9165
9636
  timelock: {
9166
9637
  value: event.batchExpiry,
9167
9638
  type: event.batchExpiry >= 512n ? "seconds" : "blocks"
@@ -9248,11 +9719,24 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9248
9719
  }
9249
9720
  return jobs;
9250
9721
  }
9722
+ /**
9723
+ * @internal Sign an on-chain boarding exit / sweep transaction, routing
9724
+ * each input to the correct key by its `witnessUtxo.script`: the identity
9725
+ * for index-0 / static boarding, the per-index descriptor for a rotated
9726
+ * boarding UTXO (plan §6-III.3). Used by
9727
+ * {@link VtxoManager.sweepExpiredBoardingUtxos}; without it, the
9728
+ * unilateral exit of a rotated boarding UTXO would be signed with the
9729
+ * wrong (index-0) key and rejected.
9730
+ */
9731
+ async signOnchainBoardingTx(tx) {
9732
+ const signed = await this._signerRouter.sign(tx, this.inputSigningJobsFromWitnessUtxos(tx));
9733
+ return signed;
9734
+ }
9251
9735
  async safeRegisterIntent(intent, inputs) {
9252
9736
  try {
9253
9737
  return await this.arkProvider.registerIntent(intent);
9254
9738
  } catch (error) {
9255
- if (error instanceof chunk6FLL2Q36_cjs.ArkError && error.code === 0 && error.message.includes("duplicated input")) {
9739
+ if (error instanceof chunkFSAXPBGP_cjs.ArkError && error.code === 0 && error.message.includes("duplicated input")) {
9256
9740
  const deleteIntent = await this.makeDeleteIntentSignature(inputs);
9257
9741
  await this.arkProvider.deleteIntent(deleteIntent);
9258
9742
  return this.arkProvider.registerIntent(intent);
@@ -9268,7 +9752,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9268
9752
  expire_at: 0,
9269
9753
  cosigners_public_keys: cosignerPubKeys
9270
9754
  };
9271
- const proof = chunk6FLL2Q36_cjs.Intent.create(message, coins, outputs);
9755
+ const proof = chunkFSAXPBGP_cjs.Intent.create(message, coins, outputs);
9272
9756
  const signedProof = await this._signerRouter.sign(proof, intentProofJobs(coins));
9273
9757
  return {
9274
9758
  proof: base.base64.encode(signedProof.toPSBT()),
@@ -9280,7 +9764,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9280
9764
  type: "delete",
9281
9765
  expire_at: 0
9282
9766
  };
9283
- const proof = chunk6FLL2Q36_cjs.Intent.create(message, coins, []);
9767
+ const proof = chunkFSAXPBGP_cjs.Intent.create(message, coins, []);
9284
9768
  const signedProof = await this._signerRouter.sign(proof, intentProofJobs(coins));
9285
9769
  return {
9286
9770
  proof: base.base64.encode(signedProof.toPSBT()),
@@ -9292,7 +9776,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9292
9776
  type: "get-pending-tx",
9293
9777
  expire_at: 0
9294
9778
  };
9295
- const proof = chunk6FLL2Q36_cjs.Intent.create(message, coins, []);
9779
+ const proof = chunkFSAXPBGP_cjs.Intent.create(message, coins, []);
9296
9780
  const signedProof = await this._signerRouter.sign(proof, intentProofJobs(coins));
9297
9781
  return {
9298
9782
  proof: base.base64.encode(signedProof.toPSBT()),
@@ -9352,16 +9836,38 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9352
9836
  seen.add(pendingTx.arkTxid);
9353
9837
  batchPending.push(pendingTx.arkTxid);
9354
9838
  try {
9355
- const finalCheckpoints = await Promise.all(
9356
- pendingTx.signedCheckpointTxs.map(async (c) => {
9357
- const tx = btcSigner.Transaction.fromPSBT(base.base64.decode(c));
9358
- const signedCheckpoint = await this._signerRouter.sign(
9359
- tx,
9360
- this.inputSigningJobsFromWitnessUtxos(tx)
9361
- );
9362
- return base.base64.encode(signedCheckpoint.toPSBT());
9363
- })
9839
+ const checkpointTxs = pendingTx.signedCheckpointTxs.map(
9840
+ (c) => btcSigner.Transaction.fromPSBT(base.base64.decode(c))
9364
9841
  );
9842
+ const checkpointJobs = checkpointTxs.map(
9843
+ (tx) => this.inputSigningJobsFromWitnessUtxos(tx)
9844
+ );
9845
+ const identity = this.identity;
9846
+ const batchEligible = isBatchSignable(identity) && await this._signerRouter.canBatch(...checkpointJobs);
9847
+ let finalCheckpoints;
9848
+ if (batchEligible) {
9849
+ const requests = checkpointTxs.map((tx, i) => ({
9850
+ tx,
9851
+ inputIndexes: checkpointJobs[i].map((j) => j.index)
9852
+ }));
9853
+ const signed = await identity.signMultiple(requests);
9854
+ if (signed.length !== requests.length) {
9855
+ throw new Error(
9856
+ `signMultiple returned ${signed.length} transactions, expected ${requests.length}`
9857
+ );
9858
+ }
9859
+ finalCheckpoints = signed.map((tx) => base.base64.encode(tx.toPSBT()));
9860
+ } else {
9861
+ finalCheckpoints = await Promise.all(
9862
+ checkpointTxs.map(async (tx, i) => {
9863
+ const signedCheckpoint = await this._signerRouter.sign(
9864
+ tx,
9865
+ checkpointJobs[i]
9866
+ );
9867
+ return base.base64.encode(signedCheckpoint.toPSBT());
9868
+ })
9869
+ );
9870
+ }
9365
9871
  await this.arkProvider.finalizeTx(pendingTx.arkTxid, finalCheckpoints);
9366
9872
  batchFinalized.push(pendingTx.arkTxid);
9367
9873
  } catch (error) {
@@ -9587,24 +10093,67 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9587
10093
  );
9588
10094
  const arkTxJobs = inputs.map((input, index) => ({
9589
10095
  index,
9590
- lookupScript: chunkWMIPYZSB_cjs.VtxoScript.decode(input.tapTree).pkScript
10096
+ lookupScript: chunkCMPJR3HS_cjs.VtxoScript.decode(input.tapTree).pkScript
9591
10097
  }));
9592
- const signedVirtualTx = await this._signerRouter.sign(offchainTx.arkTx, arkTxJobs);
10098
+ const checkpointJobs = offchainTx.checkpoints.map(
10099
+ (c) => this.inputSigningJobsFromWitnessUtxos(c)
10100
+ );
10101
+ let signedVirtualTx;
10102
+ let userSignedCheckpoints;
10103
+ const identity = this.identity;
10104
+ const batchEligible = isBatchSignable(identity) && await this._signerRouter.canBatch(arkTxJobs, ...checkpointJobs);
10105
+ if (batchEligible) {
10106
+ const requests = [
10107
+ {
10108
+ tx: offchainTx.arkTx.clone(),
10109
+ inputIndexes: arkTxJobs.map((j) => j.index)
10110
+ },
10111
+ ...offchainTx.checkpoints.map((c, i) => ({
10112
+ tx: c.clone(),
10113
+ inputIndexes: checkpointJobs[i].map((j) => j.index)
10114
+ }))
10115
+ ];
10116
+ const signed = await identity.signMultiple(requests);
10117
+ if (signed.length !== requests.length) {
10118
+ throw new Error(
10119
+ `signMultiple returned ${signed.length} transactions, expected ${requests.length}`
10120
+ );
10121
+ }
10122
+ const [firstSignedTx, ...signedCheckpoints] = signed;
10123
+ signedVirtualTx = firstSignedTx;
10124
+ userSignedCheckpoints = signedCheckpoints;
10125
+ } else {
10126
+ signedVirtualTx = await this._signerRouter.sign(offchainTx.arkTx, arkTxJobs);
10127
+ }
9593
10128
  await this.setPendingTxFlag(true);
9594
10129
  const { arkTxid, signedCheckpointTxs } = await this.arkProvider.submitTx(
9595
10130
  base.base64.encode(signedVirtualTx.toPSBT()),
9596
10131
  offchainTx.checkpoints.map((c) => base.base64.encode(c.toPSBT()))
9597
10132
  );
9598
- const finalCheckpoints = await Promise.all(
9599
- signedCheckpointTxs.map(async (c) => {
9600
- const tx = btcSigner.Transaction.fromPSBT(base.base64.decode(c));
9601
- const signedCheckpoint = await this._signerRouter.sign(
9602
- tx,
9603
- this.inputSigningJobsFromWitnessUtxos(tx)
10133
+ let finalCheckpoints;
10134
+ if (userSignedCheckpoints) {
10135
+ if (signedCheckpointTxs.length !== userSignedCheckpoints.length) {
10136
+ throw new Error(
10137
+ `submitTx returned ${signedCheckpointTxs.length} checkpoints, expected ${userSignedCheckpoints.length}`
9604
10138
  );
9605
- return base.base64.encode(signedCheckpoint.toPSBT());
9606
- })
9607
- );
10139
+ }
10140
+ finalCheckpoints = signedCheckpointTxs.map((c, i) => {
10141
+ const serverSigned = btcSigner.Transaction.fromPSBT(base.base64.decode(c));
10142
+ combineTapscriptSigs(userSignedCheckpoints[i], serverSigned);
10143
+ return base.base64.encode(serverSigned.toPSBT());
10144
+ });
10145
+ } else {
10146
+ finalCheckpoints = await Promise.all(
10147
+ signedCheckpointTxs.map(async (c) => {
10148
+ const tx = btcSigner.Transaction.fromPSBT(base.base64.decode(c));
10149
+ const signedCheckpoint = await this._signerRouter.sign(
10150
+ tx,
10151
+ this.inputSigningJobsFromWitnessUtxos(tx)
10152
+ );
10153
+ return base.base64.encode(signedCheckpoint.toPSBT());
10154
+ })
10155
+ );
10156
+ }
9608
10157
  await this.arkProvider.finalizeTx(arkTxid, finalCheckpoints);
9609
10158
  try {
9610
10159
  await this.setPendingTxFlag(false);
@@ -9749,10 +10298,9 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9749
10298
  // mark virtual outputs as spent/settled, remove boarding inputs
9750
10299
  async updateDbAfterSettle(inputs, commitmentTxid) {
9751
10300
  try {
9752
- const boardingAddress = await this.getBoardingAddress();
9753
10301
  const spentVtxos = [];
9754
10302
  const inputArkTxIds = /* @__PURE__ */ new Set();
9755
- const boardingUtxoToRemove = /* @__PURE__ */ new Set();
10303
+ const boardingRemovalsByAddress = /* @__PURE__ */ new Map();
9756
10304
  const isVtxo = (input) => "virtualStatus" in input;
9757
10305
  const vtxoInputs = inputs.filter(isVtxo);
9758
10306
  const cm = await this.getContractManager();
@@ -9774,7 +10322,20 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9774
10322
  isSpent: true
9775
10323
  });
9776
10324
  } else {
9777
- boardingUtxoToRemove.add(`${input.txid}:${input.vout}`);
10325
+ let sourceAddress;
10326
+ try {
10327
+ sourceAddress = chunkCMPJR3HS_cjs.VtxoScript.decode(input.tapTree).onchainAddress(
10328
+ this.network
10329
+ );
10330
+ } catch {
10331
+ sourceAddress = this.boardingTapscript.onchainAddress(this.network);
10332
+ }
10333
+ let set = boardingRemovalsByAddress.get(sourceAddress);
10334
+ if (!set) {
10335
+ set = /* @__PURE__ */ new Set();
10336
+ boardingRemovalsByAddress.set(sourceAddress, set);
10337
+ }
10338
+ set.add(`${input.txid}:${input.vout}`);
9778
10339
  }
9779
10340
  }
9780
10341
  if (spentVtxos.length > 0) {
@@ -9806,14 +10367,12 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9806
10367
  );
9807
10368
  }
9808
10369
  }
9809
- if (boardingUtxoToRemove.size > 0) {
9810
- const currentUtxos = await this.walletRepository.getUtxos(boardingAddress);
9811
- const filtered = currentUtxos.filter(
9812
- (u) => !boardingUtxoToRemove.has(`${u.txid}:${u.vout}`)
9813
- );
9814
- await this.walletRepository.deleteUtxos(boardingAddress);
10370
+ for (const [address, toRemove] of boardingRemovalsByAddress) {
10371
+ const currentUtxos = await this.walletRepository.getUtxos(address);
10372
+ const filtered = currentUtxos.filter((u) => !toRemove.has(`${u.txid}:${u.vout}`));
10373
+ await this.walletRepository.deleteUtxos(address);
9815
10374
  if (filtered.length > 0) {
9816
- await this.walletRepository.saveUtxos(boardingAddress, filtered);
10375
+ await this.walletRepository.saveUtxos(address, filtered);
9817
10376
  }
9818
10377
  }
9819
10378
  } catch (e) {
@@ -9854,12 +10413,17 @@ function selectVirtualCoins(coins, targetAmount) {
9854
10413
  }
9855
10414
  async function waitForIncomingFunds(wallet) {
9856
10415
  let stopFunc;
10416
+ let settled = false;
9857
10417
  return new Promise((resolve) => {
9858
- wallet.notifyIncomingFunds((coins) => {
9859
- resolve(coins);
9860
- if (stopFunc) stopFunc();
10418
+ wallet.notifyIncomingFunds((funds) => {
10419
+ const hasFunds = funds.type === "utxo" ? funds.coins.length > 0 : funds.newVtxos.length > 0;
10420
+ if (settled || !hasFunds) return;
10421
+ settled = true;
10422
+ resolve(funds);
10423
+ stopFunc?.();
9861
10424
  }).then((stop) => {
9862
10425
  stopFunc = stop;
10426
+ if (settled) stop();
9863
10427
  });
9864
10428
  });
9865
10429
  }
@@ -10016,7 +10580,7 @@ var MessageBus = class {
10016
10580
  this.initialized = true;
10017
10581
  }
10018
10582
  async buildServices(config) {
10019
- const arkProvider = new chunk6FLL2Q36_cjs.RestArkProvider(config.arkServer.url);
10583
+ const arkProvider = new chunkFSAXPBGP_cjs.RestArkProvider(config.arkServer.url);
10020
10584
  const storage = {
10021
10585
  walletRepository: this.walletRepository,
10022
10586
  contractRepository: this.contractRepository
@@ -10392,7 +10956,7 @@ var Ramps = class {
10392
10956
  }
10393
10957
  amount = amount ?? totalAmount;
10394
10958
  const offchainAddress = await this.wallet.getAddress();
10395
- const offchainAddr = chunkWMIPYZSB_cjs.ArkAddress.decode(offchainAddress);
10959
+ const offchainAddr = chunkCMPJR3HS_cjs.ArkAddress.decode(offchainAddress);
10396
10960
  const offchainScript = base.hex.encode(offchainAddr.pkScript);
10397
10961
  const outputFee = estimator.evalOffchainOutput({
10398
10962
  amount,
@@ -10490,7 +11054,7 @@ var Ramps = class {
10490
11054
  let destinationScript;
10491
11055
  for (const networkName of networkNames) {
10492
11056
  try {
10493
- const network = chunkWMIPYZSB_cjs.networks[networkName];
11057
+ const network = chunkCMPJR3HS_cjs.networks[networkName];
10494
11058
  const addr = btcSigner.Address(network).decode(destinationAddress);
10495
11059
  destinationScript = btcSigner.OutScript.encode(addr);
10496
11060
  break;
@@ -11059,7 +11623,7 @@ var WalletMessageHandler = class {
11059
11623
  // Wallet methods
11060
11624
  async handleInitWallet({ payload }) {
11061
11625
  const { arkServerUrl } = payload;
11062
- this.indexerProvider = new chunk6FLL2Q36_cjs.RestIndexerProvider(arkServerUrl);
11626
+ this.indexerProvider = new chunkFSAXPBGP_cjs.RestIndexerProvider(arkServerUrl);
11063
11627
  await this.onWalletInitialized();
11064
11628
  }
11065
11629
  async handleGetBalance() {
@@ -11208,9 +11772,7 @@ var WalletMessageHandler = class {
11208
11772
  );
11209
11773
  }
11210
11774
  if (funds.type === "utxo") {
11211
- const utxos = funds.coins.map((utxo) => extendCoin(this.readonlyWallet, utxo));
11212
- const boardingAddress = await this.readonlyWallet.getBoardingAddress();
11213
- await this.walletRepository?.saveUtxos(boardingAddress, utxos);
11775
+ const utxos = await this.readonlyWallet.getBoardingUtxos();
11214
11776
  this.scheduleForNextTick(
11215
11777
  () => this.tagged({
11216
11778
  type: "UTXO_UPDATE",
@@ -11239,13 +11801,16 @@ var WalletMessageHandler = class {
11239
11801
  return;
11240
11802
  }
11241
11803
  const vtxos = await this.getVtxosFromRepo();
11242
- const boardingAddress = await this.readonlyWallet.getBoardingAddress();
11243
- const coins = await this.readonlyWallet.onchainProvider.getCoins(boardingAddress);
11244
- await this.walletRepository.deleteUtxos(boardingAddress);
11245
- await this.walletRepository.saveUtxos(
11246
- boardingAddress,
11247
- coins.map((utxo) => extendCoin(this.readonlyWallet, utxo))
11248
- );
11804
+ const boardingAddresses = await this.readonlyWallet.getBoardingAddresses();
11805
+ const fresh = await this.readonlyWallet.getBoardingUtxos();
11806
+ const freshKeys = new Set(fresh.map((u) => `${u.txid}:${u.vout}`));
11807
+ for (const addr of boardingAddresses) {
11808
+ const cached = await this.walletRepository.getUtxos(addr);
11809
+ const kept = cached.filter((u) => freshKeys.has(`${u.txid}:${u.vout}`));
11810
+ if (kept.length === cached.length) continue;
11811
+ await this.walletRepository.deleteUtxos(addr);
11812
+ if (kept.length > 0) await this.walletRepository.saveUtxos(addr, kept);
11813
+ }
11249
11814
  const address = await this.readonlyWallet.getAddress();
11250
11815
  const txs = await this.buildTransactionHistoryFromCache(vtxos);
11251
11816
  if (txs) await this.walletRepository.saveTransactions(address, txs);
@@ -12692,12 +13257,12 @@ var OnchainWallet = class _OnchainWallet {
12692
13257
  * @returns Configured onchain wallet
12693
13258
  * @throws Error if the configured identity cannot produce a valid x-only public key
12694
13259
  */
12695
- static async create(identity, networkName = chunkWMIPYZSB_cjs.DEFAULT_NETWORK_NAME, provider) {
13260
+ static async create(identity, networkName = chunkCMPJR3HS_cjs.DEFAULT_NETWORK_NAME, provider) {
12696
13261
  const pubkey = await identity.xOnlyPublicKey();
12697
13262
  if (!pubkey) {
12698
13263
  throw new Error("Invalid configured public key");
12699
13264
  }
12700
- const network = chunkWMIPYZSB_cjs.getNetwork(networkName);
13265
+ const network = chunkCMPJR3HS_cjs.getNetwork(networkName);
12701
13266
  const onchainProvider = provider || new EsploraProvider(ESPLORA_URL[networkName]);
12702
13267
  const onchainP2TR = btcSigner.p2tr(pubkey, void 0, network);
12703
13268
  return new _OnchainWallet(identity, network, onchainP2TR, onchainProvider);
@@ -12803,7 +13368,7 @@ var OnchainWallet = class _OnchainWallet {
12803
13368
  if (!inputs) {
12804
13369
  throw new Error("Fee estimation failed");
12805
13370
  }
12806
- let tx = new chunk6FLL2Q36_cjs.Transaction();
13371
+ let tx = new chunkFSAXPBGP_cjs.Transaction();
12807
13372
  for (const input of inputs) {
12808
13373
  tx.addInput({
12809
13374
  txid: input.txid,
@@ -12834,7 +13399,7 @@ var OnchainWallet = class _OnchainWallet {
12834
13399
  */
12835
13400
  async bumpP2A(parent) {
12836
13401
  const parentVsize = parent.vsize;
12837
- let child = new chunk6FLL2Q36_cjs.Transaction({
13402
+ let child = new chunkFSAXPBGP_cjs.Transaction({
12838
13403
  version: 3,
12839
13404
  allowLegacyWitnessUtxo: true
12840
13405
  });
@@ -13591,7 +14156,7 @@ exports.BIP322 = void 0;
13591
14156
  async function sign2(message, identity, network) {
13592
14157
  const xOnlyPubKey = await identity.xOnlyPublicKey();
13593
14158
  const payment = btcSigner.p2tr(xOnlyPubKey, void 0, network);
13594
- const toSpend = chunk6FLL2Q36_cjs.craftToSpendTx(message, payment.script, TAG_BIP322);
14159
+ const toSpend = chunkFSAXPBGP_cjs.craftToSpendTx(message, payment.script, TAG_BIP322);
13595
14160
  const toSign = craftBIP322ToSignP2TR(toSpend, payment.script, xOnlyPubKey);
13596
14161
  const signed = await identity.sign(toSign, [0]);
13597
14162
  signed.finalizeIdx(0);
@@ -13649,7 +14214,7 @@ function verifyP2TR(message, witnessItems, pkScript, pubkey) {
13649
14214
  if (sighashType !== btcSigner.SigHash.DEFAULT && sighashType !== btcSigner.SigHash.ALL) {
13650
14215
  return false;
13651
14216
  }
13652
- const toSpend = chunk6FLL2Q36_cjs.craftToSpendTx(message, pkScript, TAG_BIP322);
14217
+ const toSpend = chunkFSAXPBGP_cjs.craftToSpendTx(message, pkScript, TAG_BIP322);
13653
14218
  const toSign = craftBIP322ToSignP2TR(toSpend, pkScript, pubkey);
13654
14219
  const sighash = toSign.preimageWitnessV1(0, [pkScript], sighashType, [0n]);
13655
14220
  const rawSig = sig.length === 65 ? sig.subarray(0, 64) : sig;
@@ -13670,7 +14235,7 @@ function verifyP2WPKH(message, witnessItems, pkScript, addressHash) {
13670
14235
  }
13671
14236
  const sighashType = sigWithHash[sigWithHash.length - 1];
13672
14237
  const derSig = sigWithHash.subarray(0, sigWithHash.length - 1);
13673
- const toSpend = chunk6FLL2Q36_cjs.craftToSpendTx(message, pkScript, TAG_BIP322);
14238
+ const toSpend = chunkFSAXPBGP_cjs.craftToSpendTx(message, pkScript, TAG_BIP322);
13674
14239
  const toSign = craftBIP322ToSignSimple(toSpend, pkScript);
13675
14240
  const scriptCode = btcSigner.OutScript.encode({ type: "pkh", hash: addressHash });
13676
14241
  const sighash = toSign.preimageWitnessV0(0, scriptCode, sighashType, 0n);
@@ -13723,7 +14288,7 @@ function encodeCompactSize(n) {
13723
14288
  return buf;
13724
14289
  }
13725
14290
  function craftBIP322ToSignP2TR(toSpend, pkScript, tapInternalKey) {
13726
- const tx = new chunk6FLL2Q36_cjs.Transaction({ version: 0 });
14291
+ const tx = new chunkFSAXPBGP_cjs.Transaction({ version: 0 });
13727
14292
  tx.addInput({
13728
14293
  txid: toSpend.id,
13729
14294
  index: 0,
@@ -13737,12 +14302,12 @@ function craftBIP322ToSignP2TR(toSpend, pkScript, tapInternalKey) {
13737
14302
  });
13738
14303
  tx.addOutput({
13739
14304
  amount: 0n,
13740
- script: chunk6FLL2Q36_cjs.OP_RETURN_EMPTY_PKSCRIPT
14305
+ script: chunkFSAXPBGP_cjs.OP_RETURN_EMPTY_PKSCRIPT
13741
14306
  });
13742
14307
  return tx;
13743
14308
  }
13744
14309
  function craftBIP322ToSignSimple(toSpend, pkScript) {
13745
- const tx = new chunk6FLL2Q36_cjs.Transaction({ version: 0 });
14310
+ const tx = new chunkFSAXPBGP_cjs.Transaction({ version: 0 });
13746
14311
  tx.addInput({
13747
14312
  txid: toSpend.id,
13748
14313
  index: 0,
@@ -13754,7 +14319,7 @@ function craftBIP322ToSignSimple(toSpend, pkScript) {
13754
14319
  });
13755
14320
  tx.addOutput({
13756
14321
  amount: 0n,
13757
- script: chunk6FLL2Q36_cjs.OP_RETURN_EMPTY_PKSCRIPT
14322
+ script: chunkFSAXPBGP_cjs.OP_RETURN_EMPTY_PKSCRIPT
13758
14323
  });
13759
14324
  return tx;
13760
14325
  }
@@ -13815,7 +14380,7 @@ exports.Unroll = void 0;
13815
14380
  if (virtualTxs.txs.length === 0) {
13816
14381
  throw new Error(`Tx ${nextTxToBroadcast.txid} not found`);
13817
14382
  }
13818
- const tx = chunk6FLL2Q36_cjs.Transaction.fromPSBT(base.base64.decode(virtualTxs.txs[0]));
14383
+ const tx = chunkFSAXPBGP_cjs.Transaction.fromPSBT(base.base64.decode(virtualTxs.txs[0]));
13819
14384
  if (nextTxToBroadcast.type === "INDEXER_CHAINED_TX_TYPE_TREE" /* TREE */) {
13820
14385
  const input = tx.getInput(0);
13821
14386
  if (!input) {
@@ -13892,12 +14457,12 @@ async function prepareUnrollTransaction(wallet, vtxoTxIds, outputAddress) {
13892
14457
  if (!exit) {
13893
14458
  throw new Error(`no available exit path found for vtxo ${vtxo.txid}:${vtxo.vout}`);
13894
14459
  }
13895
- const spendingLeaf = chunkWMIPYZSB_cjs.VtxoScript.decode(vtxo.tapTree).findLeaf(base.hex.encode(exit.script));
14460
+ const spendingLeaf = chunkCMPJR3HS_cjs.VtxoScript.decode(vtxo.tapTree).findLeaf(base.hex.encode(exit.script));
13896
14461
  if (!spendingLeaf) {
13897
14462
  throw new Error(`spending leaf not found for vtxo ${vtxo.txid}:${vtxo.vout}`);
13898
14463
  }
13899
14464
  totalAmount += BigInt(vtxo.value);
13900
- const sequence = chunkWMIPYZSB_cjs.timelockToSequence(exit.params.timelock);
14465
+ const sequence = chunkCMPJR3HS_cjs.timelockToSequence(exit.params.timelock);
13901
14466
  inputs.push({
13902
14467
  txid: vtxo.txid,
13903
14468
  index: vtxo.vout,
@@ -13905,7 +14470,7 @@ async function prepareUnrollTransaction(wallet, vtxoTxIds, outputAddress) {
13905
14470
  sequence,
13906
14471
  witnessUtxo: {
13907
14472
  amount: BigInt(vtxo.value),
13908
- script: chunkWMIPYZSB_cjs.VtxoScript.decode(vtxo.tapTree).pkScript
14473
+ script: chunkCMPJR3HS_cjs.VtxoScript.decode(vtxo.tapTree).pkScript
13909
14474
  },
13910
14475
  sighashType: btcSigner.SigHash.DEFAULT
13911
14476
  });
@@ -13915,7 +14480,7 @@ async function prepareUnrollTransaction(wallet, vtxoTxIds, outputAddress) {
13915
14480
  btcSigner.TaprootControlBlock.encode(spendingLeaf[0]).length
13916
14481
  );
13917
14482
  }
13918
- const tx = new chunk6FLL2Q36_cjs.Transaction({ version: 2 });
14483
+ const tx = new chunkFSAXPBGP_cjs.Transaction({ version: 2 });
13919
14484
  for (const input of inputs) {
13920
14485
  tx.addInput(input);
13921
14486
  }
@@ -13962,7 +14527,7 @@ function doWait(onchainProvider, txid) {
13962
14527
  };
13963
14528
  }
13964
14529
  function availableExitPath(confirmedAt, current, vtxo) {
13965
- const exits = chunkWMIPYZSB_cjs.VtxoScript.decode(vtxo.tapTree).exitPaths();
14530
+ const exits = chunkCMPJR3HS_cjs.VtxoScript.decode(vtxo.tapTree).exitPaths();
13966
14531
  for (const exit of exits) {
13967
14532
  if (exit.params.timelock.type === "blocks") {
13968
14533
  if (current.height >= confirmedAt.height + Number(exit.params.timelock.value)) {
@@ -14001,7 +14566,7 @@ function decodeArkContract(encoded) {
14001
14566
  }
14002
14567
  function contractFromArkContract(encoded, options = {}) {
14003
14568
  const parsed = decodeArkContract(encoded);
14004
- const handler = chunkIEO3XDKI_cjs.contractHandlers.get(parsed.type);
14569
+ const handler = chunkGUTKJMSF_cjs.contractHandlers.get(parsed.type);
14005
14570
  if (!handler) {
14006
14571
  throw new Error(`No handler registered for contract type '${parsed.type}'`);
14007
14572
  }
@@ -14015,9 +14580,9 @@ function contractFromArkContract(encoded, options = {}) {
14015
14580
  metadata: options.metadata
14016
14581
  };
14017
14582
  }
14018
- function contractFromArkContractWithAddress(encoded, serverPubKey, addressPrefix = chunkWMIPYZSB_cjs.DEFAULT_NETWORK.hrp, options = {}) {
14583
+ function contractFromArkContractWithAddress(encoded, serverPubKey, addressPrefix = chunkCMPJR3HS_cjs.DEFAULT_NETWORK.hrp, options = {}) {
14019
14584
  const parsed = decodeArkContract(encoded);
14020
- const handler = chunkIEO3XDKI_cjs.contractHandlers.getOrThrow(parsed.type);
14585
+ const handler = chunkGUTKJMSF_cjs.contractHandlers.getOrThrow(parsed.type);
14021
14586
  const params = parsed.data;
14022
14587
  const vtxoScript = handler.createScript(params);
14023
14588
  return {
@@ -14129,5 +14694,5 @@ exports.validateVtxoTxGraph = validateVtxoTxGraph;
14129
14694
  exports.verifyTapscriptSignatures = verifyTapscriptSignatures;
14130
14695
  exports.waitForIncomingFunds = waitForIncomingFunds;
14131
14696
  exports.warnAndFilterVtxosForScript = warnAndFilterVtxosForScript;
14132
- //# sourceMappingURL=chunk-KQK4PP6L.cjs.map
14133
- //# sourceMappingURL=chunk-KQK4PP6L.cjs.map
14697
+ //# sourceMappingURL=chunk-XCHBQVMK.cjs.map
14698
+ //# sourceMappingURL=chunk-XCHBQVMK.cjs.map