@arkade-os/sdk 0.4.33 → 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 (78) 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-DEsDMYGv.d.cts → ark-Dsv5Jq4E.d.cts} +65 -7
  9. package/dist/{ark-DEsDMYGv.d.ts → ark-Dsv5Jq4E.d.ts} +65 -7
  10. package/dist/{asyncStorageTaskQueue-CMrTYlKG.d.ts → asyncStorageTaskQueue-BH-zuth5.d.ts} +1 -1
  11. package/dist/{asyncStorageTaskQueue-D8T1VXEx.d.cts → asyncStorageTaskQueue-D92ch8yI.d.cts} +1 -1
  12. package/dist/{chunk-L6ZETTX3.js → chunk-5WDBHWX3.js} +4 -4
  13. package/dist/{chunk-L6ZETTX3.js.map → chunk-5WDBHWX3.js.map} +1 -1
  14. package/dist/{chunk-5CCRRL5S.cjs → chunk-CCLNFHJ5.cjs} +11 -11
  15. package/dist/{chunk-5CCRRL5S.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-AOJUURHM.js → chunk-CUSABEUQ.js} +141 -37
  19. package/dist/chunk-CUSABEUQ.js.map +1 -0
  20. package/dist/{chunk-SPDNHPM4.cjs → chunk-FSAXPBGP.cjs} +8 -8
  21. package/dist/{chunk-SPDNHPM4.cjs.map → chunk-FSAXPBGP.cjs.map} +1 -1
  22. package/dist/{chunk-E22HEKLN.js → chunk-FXFBPXV3.js} +3 -3
  23. package/dist/{chunk-E22HEKLN.js.map → chunk-FXFBPXV3.js.map} +1 -1
  24. package/dist/{chunk-GYSK5R57.cjs → chunk-GUTKJMSF.cjs} +164 -59
  25. package/dist/chunk-GUTKJMSF.cjs.map +1 -0
  26. package/dist/{chunk-DSS2GQUG.js → chunk-HFXEUW55.js} +575 -155
  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-BU3BU6XK.js → chunk-VVGD3JIP.js} +3 -3
  31. package/dist/{chunk-BU3BU6XK.js.map → chunk-VVGD3JIP.js.map} +1 -1
  32. package/dist/{chunk-7K3ROJF6.cjs → chunk-XCHBQVMK.cjs} +718 -298
  33. package/dist/chunk-XCHBQVMK.cjs.map +1 -0
  34. package/dist/{chunk-HAVA4XB7.cjs → chunk-ZS3OZHC7.cjs} +7 -7
  35. package/dist/{chunk-HAVA4XB7.cjs.map → chunk-ZS3OZHC7.cjs.map} +1 -1
  36. package/dist/contracts/handlers/index.cjs +7 -7
  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-BJeBNP5a.d.cts → delegate-BaS5SCIW.d.cts} +1 -1
  41. package/dist/{delegate-EXN2mfkb.d.ts → delegate-Baz_hb83.d.ts} +1 -1
  42. package/dist/{index-BG2ooYKO.d.ts → index-FwXZveaX.d.ts} +22 -16
  43. package/dist/{index-DHjEeHEp.d.cts → index-lNZ6qaO3.d.cts} +22 -16
  44. package/dist/index.cjs +134 -130
  45. package/dist/index.d.cts +63 -14
  46. package/dist/index.d.ts +63 -14
  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-B7lBU45X.d.ts → taskRunner-B1NUWyWR.d.ts} +1 -1
  57. package/dist/{taskRunner-pIGyarFG.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 +13 -13
  63. package/dist/wallet/expo/index.d.cts +5 -5
  64. package/dist/wallet/expo/index.d.ts +5 -5
  65. package/dist/wallet/expo/index.js +5 -5
  66. package/dist/{wallet-C4L_X0i6.d.ts → wallet-By9HIo0Q.d.cts} +160 -5
  67. package/dist/{wallet-D4Dll5Gu.d.cts → wallet-D6uoBLmS.d.ts} +160 -5
  68. package/dist/worker/expo/index.cjs +9 -9
  69. package/dist/worker/expo/index.d.cts +4 -4
  70. package/dist/worker/expo/index.d.ts +4 -4
  71. package/dist/worker/expo/index.js +5 -5
  72. package/package.json +4 -4
  73. package/dist/chunk-7K3ROJF6.cjs.map +0 -1
  74. package/dist/chunk-AOJUURHM.js.map +0 -1
  75. package/dist/chunk-DSS2GQUG.js.map +0 -1
  76. package/dist/chunk-GYSK5R57.cjs.map +0 -1
  77. package/dist/chunk-TU3LVAPX.js.map +0 -1
  78. package/dist/chunk-WMIPYZSB.cjs.map +0 -1
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var chunkSPDNHPM4_cjs = require('./chunk-SPDNHPM4.cjs');
4
- var chunkGYSK5R57_cjs = require('./chunk-GYSK5R57.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 = chunkSPDNHPM4_cjs.getArkPsbtFields(tx.root, 0, chunkSPDNHPM4_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 = chunkSPDNHPM4_cjs.getArkPsbtFields(g.root, 0, chunkSPDNHPM4_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 = chunkGYSK5R57_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 chunkGYSK5R57_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 = chunkGYSK5R57_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 = chunkGYSK5R57_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 chunkGYSK5R57_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: chunkSPDNHPM4_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 chunkSPDNHPM4_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 = chunkSPDNHPM4_cjs.getArkPsbtFields(child.root, 0, chunkSPDNHPM4_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 chunkSPDNHPM4_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 chunkSPDNHPM4_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 === chunkSPDNHPM4_cjs.Packet.PACKET_TYPE) {
1539
- return chunkSPDNHPM4_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
- chunkSPDNHPM4_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
- chunkSPDNHPM4_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
- chunkSPDNHPM4_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 = chunkSPDNHPM4_cjs.AssetId.fromString(assetIdStr);
1763
- const group = chunkSPDNHPM4_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 chunkSPDNHPM4_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 chunkSPDNHPM4_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
- chunkSPDNHPM4_cjs.setArkPsbtField(tx, i, chunkSPDNHPM4_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
  ]);
@@ -2010,7 +2013,7 @@ function combineTapscriptSigs(signedTx, originalTx) {
2010
2013
  }
2011
2014
  function isValidArkAddress(address) {
2012
2015
  try {
2013
- chunkWMIPYZSB_cjs.ArkAddress.decode(address);
2016
+ chunkCMPJR3HS_cjs.ArkAddress.decode(address);
2014
2017
  return true;
2015
2018
  } catch (e) {
2016
2019
  return false;
@@ -2280,16 +2283,16 @@ var FALLBACK_WALLET_DUST_AMOUNT = 330n;
2280
2283
  function getDustAmount(wallet) {
2281
2284
  return "dustAmount" in wallet ? wallet.dustAmount : FALLBACK_WALLET_DUST_AMOUNT;
2282
2285
  }
2283
- function extendCoin(wallet, utxo) {
2286
+ function extendCoinWithTapscript(boardingTapscript, utxo) {
2284
2287
  return {
2285
2288
  ...utxo,
2286
- forfeitTapLeafScript: wallet.boardingTapscript.forfeit(),
2287
- intentTapLeafScript: wallet.boardingTapscript.forfeit(),
2288
- tapTree: wallet.boardingTapscript.encode()
2289
+ forfeitTapLeafScript: boardingTapscript.forfeit(),
2290
+ intentTapLeafScript: boardingTapscript.forfeit(),
2291
+ tapTree: boardingTapscript.encode()
2289
2292
  };
2290
2293
  }
2291
2294
  function deriveContractTapscripts(contract) {
2292
- const handler = chunkGYSK5R57_cjs.contractHandlers.get(contract.type);
2295
+ const handler = chunkGUTKJMSF_cjs.contractHandlers.get(contract.type);
2293
2296
  if (!handler) {
2294
2297
  throw new Error(`No handler for contract type '${contract.type}'`);
2295
2298
  }
@@ -2359,7 +2362,7 @@ function validateRecipients(recipients, dustAmount) {
2359
2362
  for (const recipient of recipients) {
2360
2363
  let address;
2361
2364
  try {
2362
- address = chunkWMIPYZSB_cjs.ArkAddress.decode(recipient.address);
2365
+ address = chunkCMPJR3HS_cjs.ArkAddress.decode(recipient.address);
2363
2366
  } catch (e) {
2364
2367
  throw new Error(`Invalid Arkade address: ${recipient.address}`);
2365
2368
  }
@@ -2379,12 +2382,12 @@ function validateRecipients(recipients, dustAmount) {
2379
2382
 
2380
2383
  // src/wallet/vtxo-manager.ts
2381
2384
  function isSweepCapable(wallet) {
2382
- 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;
2383
2386
  }
2384
2387
  function assertSweepCapable(wallet) {
2385
2388
  if (!isSweepCapable(wallet)) {
2386
2389
  throw new Error(
2387
- "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"
2388
2391
  );
2389
2392
  }
2390
2393
  }
@@ -2400,6 +2403,21 @@ async function runWithCrossInstanceLock(name, fn) {
2400
2403
  await fn();
2401
2404
  });
2402
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
+ }
2403
2421
  var DEFAULT_THRESHOLD_SECONDS = 259200;
2404
2422
  var DEFAULT_THRESHOLD_MS = DEFAULT_THRESHOLD_SECONDS * 1e3;
2405
2423
  var DEFAULT_RENEWAL_CONFIG = {
@@ -2559,10 +2577,20 @@ var VtxoManager = class _VtxoManager {
2559
2577
  withUnrolled: false
2560
2578
  });
2561
2579
  const dustAmount = getDustAmount(this.wallet);
2562
- const { vtxosToRecover, totalAmount } = getRecoverableWithSubdust(allVtxos, dustAmount);
2580
+ let { vtxosToRecover, totalAmount } = getRecoverableWithSubdust(allVtxos, dustAmount);
2563
2581
  if (vtxosToRecover.length === 0) {
2564
2582
  throw new Error("No recoverable VTXOs found");
2565
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
+ }
2566
2594
  const arkAddress = await this.wallet.getAddress();
2567
2595
  return this.wallet.settle(
2568
2596
  {
@@ -2712,6 +2740,9 @@ var VtxoManager = class _VtxoManager {
2712
2740
  if (vtxos.length === 0) {
2713
2741
  throw new Error("No VTXOs available to renew");
2714
2742
  }
2743
+ if (vtxos.length > MAX_VTXOS_PER_SETTLEMENT) {
2744
+ vtxos = byExpiryAscending(vtxos).slice(0, MAX_VTXOS_PER_SETTLEMENT);
2745
+ }
2715
2746
  const totalAmount = vtxos.reduce((sum, vtxo) => sum + vtxo.value, 0);
2716
2747
  const dustAmount = getDustAmount(this.wallet);
2717
2748
  if (BigInt(totalAmount) < dustAmount) {
@@ -2819,7 +2850,6 @@ var VtxoManager = class _VtxoManager {
2819
2850
  const boardingAddress = await this.wallet.getBoardingAddress();
2820
2851
  const feeRate = await this.getOnchainProvider().getFeeRate() ?? 1;
2821
2852
  const exitTapLeafScript = this.getBoardingExitLeaf();
2822
- const sequence = chunkWMIPYZSB_cjs.getSequence(exitTapLeafScript);
2823
2853
  const leafScript = exitTapLeafScript[1];
2824
2854
  const leafScriptSize = leafScript.length - 1;
2825
2855
  const controlBlockSize = exitTapLeafScript[0].merklePath.length * 32;
@@ -2838,21 +2868,30 @@ var VtxoManager = class _VtxoManager {
2838
2868
  `Sweep not economical: output ${outputAmount} sats after ${fee} sats fee is below dust (${dustAmount} sats)`
2839
2869
  );
2840
2870
  }
2841
- const tx = new chunkSPDNHPM4_cjs.Transaction();
2871
+ const tx = new chunkFSAXPBGP_cjs.Transaction();
2842
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
+ }
2843
2882
  tx.addInput({
2844
2883
  txid: utxo.txid,
2845
2884
  index: utxo.vout,
2846
2885
  witnessUtxo: {
2847
- script: this.getBoardingOutputScript(),
2886
+ script: utxoScript.pkScript,
2848
2887
  amount: BigInt(utxo.value)
2849
2888
  },
2850
- tapLeafScript: [exitTapLeafScript],
2851
- sequence
2889
+ tapLeafScript: [utxoExitLeaf],
2890
+ sequence: chunkCMPJR3HS_cjs.getSequence(utxoExitLeaf)
2852
2891
  });
2853
2892
  }
2854
2893
  tx.addOutputAddress(boardingAddress, outputAmount, this.getNetwork());
2855
- const signedTx = await this.getIdentity().sign(tx);
2894
+ const signedTx = await this.getSweepWallet().signOnchainBoardingTx(tx);
2856
2895
  signedTx.finalize();
2857
2896
  const txid = await this.getOnchainProvider().broadcastTransaction(signedTx.hex);
2858
2897
  for (const u of expiredUtxos) {
@@ -2870,7 +2909,7 @@ var VtxoManager = class _VtxoManager {
2870
2909
  /** Decodes the boarding tapscript exit path to extract the CSV timelock. */
2871
2910
  getBoardingTimelock() {
2872
2911
  const wallet = this.getSweepWallet();
2873
- const exitScript = chunkWMIPYZSB_cjs.CSVMultisigTapscript.decode(
2912
+ const exitScript = chunkCMPJR3HS_cjs.CSVMultisigTapscript.decode(
2874
2913
  base.hex.decode(wallet.boardingTapscript.exitScript)
2875
2914
  );
2876
2915
  return exitScript.params.timelock;
@@ -2879,10 +2918,6 @@ var VtxoManager = class _VtxoManager {
2879
2918
  getBoardingExitLeaf() {
2880
2919
  return this.getSweepWallet().boardingTapscript.exit();
2881
2920
  }
2882
- /** Returns the pkScript (output script) of the boarding tapscript. */
2883
- getBoardingOutputScript() {
2884
- return this.getSweepWallet().boardingTapscript.pkScript;
2885
- }
2886
2921
  /** Returns the onchain provider for fee estimation and broadcasting. */
2887
2922
  getOnchainProvider() {
2888
2923
  return this.getSweepWallet().onchainProvider;
@@ -2895,10 +2930,6 @@ var VtxoManager = class _VtxoManager {
2895
2930
  getNetwork() {
2896
2931
  return this.getSweepWallet().network;
2897
2932
  }
2898
- /** Returns the wallet's identity for transaction signing. */
2899
- getIdentity() {
2900
- return this.wallet.identity;
2901
- }
2902
2933
  async initializeSubscription() {
2903
2934
  if (this.settlementConfig === false) {
2904
2935
  return void 0;
@@ -2999,7 +3030,7 @@ var VtxoManager = class _VtxoManager {
2999
3030
  * or doesn't carry the metadata.
3000
3031
  */
3001
3032
  extractSpentOutpoint(error) {
3002
- const ark = chunkSPDNHPM4_cjs.maybeArkError(error);
3033
+ const ark = chunkFSAXPBGP_cjs.maybeArkError(error);
3003
3034
  if (!ark || ark.name !== "VTXO_ALREADY_SPENT") return void 0;
3004
3035
  const raw = ark.metadata?.vtxo_outpoint;
3005
3036
  if (typeof raw !== "string") return void 0;
@@ -3179,7 +3210,10 @@ var VtxoManager = class _VtxoManager {
3179
3210
  totalAmount += BigInt(u.value) - BigInt(inputFee.satoshis);
3180
3211
  }
3181
3212
  const filteredVtxos = [];
3182
- for (const v of expiringVtxos) {
3213
+ for (const v of byExpiryAscending(expiringVtxos)) {
3214
+ if (filteredVtxos.length >= MAX_VTXOS_PER_SETTLEMENT) {
3215
+ break;
3216
+ }
3183
3217
  const inputFee = estimator.evalOffchainInput({
3184
3218
  amount: BigInt(v.value),
3185
3219
  type: v.virtualStatus.state === "swept" ? "recoverable" : "vtxo",
@@ -3199,7 +3233,7 @@ var VtxoManager = class _VtxoManager {
3199
3233
  const arkAddress = await this.wallet.getAddress();
3200
3234
  const outputFee = estimator.evalOffchainOutput({
3201
3235
  amount: totalAmount,
3202
- script: base.hex.encode(chunkWMIPYZSB_cjs.ArkAddress.decode(arkAddress).pkScript)
3236
+ script: base.hex.encode(chunkCMPJR3HS_cjs.ArkAddress.decode(arkAddress).pkScript)
3203
3237
  });
3204
3238
  totalAmount -= BigInt(outputFee.satoshis);
3205
3239
  if (totalAmount < dustAmount) return;
@@ -3280,7 +3314,7 @@ var ArkNote = class _ArkNote {
3280
3314
  this.value = value;
3281
3315
  this.HRP = HRP;
3282
3316
  const preimageHash = utils_js.sha256(this.preimage);
3283
- this.vtxoScript = new chunkWMIPYZSB_cjs.VtxoScript([noteTapscript(preimageHash)]);
3317
+ this.vtxoScript = new chunkCMPJR3HS_cjs.VtxoScript([noteTapscript(preimageHash)]);
3284
3318
  const leaf = this.vtxoScript.leaves[0];
3285
3319
  this.txid = base.hex.encode(new Uint8Array(preimageHash).reverse());
3286
3320
  this.tapTree = this.vtxoScript.encode();
@@ -3894,7 +3928,7 @@ var AssetManager = class extends ReadonlyAssetManager {
3894
3928
  const virtualCoins = await this.wallet.getVtxos({
3895
3929
  withRecoverable: false
3896
3930
  });
3897
- const controlAssetRef = params.controlAssetId ? chunkSPDNHPM4_cjs.AssetRef.fromId(chunkSPDNHPM4_cjs.AssetId.fromString(params.controlAssetId)) : null;
3931
+ const controlAssetRef = params.controlAssetId ? chunkFSAXPBGP_cjs.AssetRef.fromId(chunkFSAXPBGP_cjs.AssetId.fromString(params.controlAssetId)) : null;
3898
3932
  const coinSelection = selectVirtualCoins(virtualCoins, Number(this.wallet.dustAmount));
3899
3933
  let totalBtcSelected = 0n;
3900
3934
  const assetChanges = /* @__PURE__ */ new Map();
@@ -3907,8 +3941,8 @@ var AssetManager = class extends ReadonlyAssetManager {
3907
3941
  }
3908
3942
  }
3909
3943
  const groups = [];
3910
- const issuedAssetOutput = chunkSPDNHPM4_cjs.AssetOutput.create(0, params.amount);
3911
- const issuedAssetGroup = chunkSPDNHPM4_cjs.AssetGroup.create(
3944
+ const issuedAssetOutput = chunkFSAXPBGP_cjs.AssetOutput.create(0, params.amount);
3945
+ const issuedAssetGroup = chunkFSAXPBGP_cjs.AssetGroup.create(
3912
3946
  null,
3913
3947
  controlAssetRef,
3914
3948
  [],
@@ -3923,28 +3957,28 @@ var AssetManager = class extends ReadonlyAssetManager {
3923
3957
  for (const [inputIndex, assets] of assetInputs) {
3924
3958
  for (const asset of assets) {
3925
3959
  if (asset.assetId !== assetId) continue;
3926
- changeInputs.push(chunkSPDNHPM4_cjs.AssetInput.create(inputIndex, asset.amount));
3960
+ changeInputs.push(chunkFSAXPBGP_cjs.AssetInput.create(inputIndex, asset.amount));
3927
3961
  }
3928
3962
  }
3929
3963
  groups.push(
3930
- chunkSPDNHPM4_cjs.AssetGroup.create(
3931
- chunkSPDNHPM4_cjs.AssetId.fromString(assetId),
3964
+ chunkFSAXPBGP_cjs.AssetGroup.create(
3965
+ chunkFSAXPBGP_cjs.AssetId.fromString(assetId),
3932
3966
  null,
3933
3967
  changeInputs,
3934
- [chunkSPDNHPM4_cjs.AssetOutput.create(0, amount)],
3968
+ [chunkFSAXPBGP_cjs.AssetOutput.create(0, amount)],
3935
3969
  []
3936
3970
  )
3937
3971
  );
3938
3972
  }
3939
3973
  }
3940
3974
  const address = await this.wallet.getAddress();
3941
- const outputAddress = chunkWMIPYZSB_cjs.ArkAddress.decode(address);
3975
+ const outputAddress = chunkCMPJR3HS_cjs.ArkAddress.decode(address);
3942
3976
  const outputs = [
3943
3977
  {
3944
3978
  script: outputAddress.pkScript,
3945
3979
  amount: BigInt(totalBtcSelected)
3946
3980
  },
3947
- Extension.create([chunkSPDNHPM4_cjs.Packet.create(groups)]).txOut()
3981
+ Extension.create([chunkFSAXPBGP_cjs.Packet.create(groups)]).txOut()
3948
3982
  ];
3949
3983
  const { arkTxid } = await this.wallet.buildAndSubmitOffchainTx(
3950
3984
  coinSelection.inputs,
@@ -3952,7 +3986,7 @@ var AssetManager = class extends ReadonlyAssetManager {
3952
3986
  );
3953
3987
  return {
3954
3988
  arkTxId: arkTxid,
3955
- assetId: chunkSPDNHPM4_cjs.AssetId.create(arkTxid, 0).toString()
3989
+ assetId: chunkFSAXPBGP_cjs.AssetId.create(arkTxid, 0).toString()
3956
3990
  };
3957
3991
  }
3958
3992
  /**
@@ -4024,16 +4058,16 @@ var AssetManager = class extends ReadonlyAssetManager {
4024
4058
  for (const [inputIndex, assets] of assetInputs) {
4025
4059
  for (const asset of assets) {
4026
4060
  if (asset.assetId !== params.assetId) continue;
4027
- reissueInputs.push(chunkSPDNHPM4_cjs.AssetInput.create(inputIndex, asset.amount));
4061
+ reissueInputs.push(chunkFSAXPBGP_cjs.AssetInput.create(inputIndex, asset.amount));
4028
4062
  }
4029
4063
  }
4030
4064
  const totalAssetAmount = assetToReissueAmount + params.amount;
4031
- const reissueAssetIdObj = chunkSPDNHPM4_cjs.AssetId.fromString(params.assetId);
4032
- const reissueAssetGroup = chunkSPDNHPM4_cjs.AssetGroup.create(
4065
+ const reissueAssetIdObj = chunkFSAXPBGP_cjs.AssetId.fromString(params.assetId);
4066
+ const reissueAssetGroup = chunkFSAXPBGP_cjs.AssetGroup.create(
4033
4067
  reissueAssetIdObj,
4034
4068
  null,
4035
4069
  reissueInputs,
4036
- [chunkSPDNHPM4_cjs.AssetOutput.create(0, totalAssetAmount)],
4070
+ [chunkFSAXPBGP_cjs.AssetOutput.create(0, totalAssetAmount)],
4037
4071
  []
4038
4072
  );
4039
4073
  const groups = [reissueAssetGroup];
@@ -4042,27 +4076,27 @@ var AssetManager = class extends ReadonlyAssetManager {
4042
4076
  for (const [inputIndex, assets] of assetInputs) {
4043
4077
  for (const asset of assets) {
4044
4078
  if (asset.assetId !== assetId) continue;
4045
- changeInputs.push(chunkSPDNHPM4_cjs.AssetInput.create(inputIndex, asset.amount));
4079
+ changeInputs.push(chunkFSAXPBGP_cjs.AssetInput.create(inputIndex, asset.amount));
4046
4080
  }
4047
4081
  }
4048
4082
  groups.push(
4049
- chunkSPDNHPM4_cjs.AssetGroup.create(
4050
- chunkSPDNHPM4_cjs.AssetId.fromString(assetId),
4083
+ chunkFSAXPBGP_cjs.AssetGroup.create(
4084
+ chunkFSAXPBGP_cjs.AssetId.fromString(assetId),
4051
4085
  null,
4052
4086
  changeInputs,
4053
- [chunkSPDNHPM4_cjs.AssetOutput.create(0, amount)],
4087
+ [chunkFSAXPBGP_cjs.AssetOutput.create(0, amount)],
4054
4088
  []
4055
4089
  )
4056
4090
  );
4057
4091
  }
4058
4092
  const address = await this.wallet.getAddress();
4059
- const outputAddress = chunkWMIPYZSB_cjs.ArkAddress.decode(address);
4093
+ const outputAddress = chunkCMPJR3HS_cjs.ArkAddress.decode(address);
4060
4094
  const outputs = [
4061
4095
  {
4062
4096
  script: outputAddress.pkScript,
4063
4097
  amount: BigInt(totalBtcSelected)
4064
4098
  },
4065
- Extension.create([chunkSPDNHPM4_cjs.Packet.create(groups)]).txOut()
4099
+ Extension.create([chunkFSAXPBGP_cjs.Packet.create(groups)]).txOut()
4066
4100
  ];
4067
4101
  const { arkTxid } = await this.wallet.buildAndSubmitOffchainTx(selectedCoins, outputs);
4068
4102
  return arkTxid;
@@ -4129,27 +4163,27 @@ var AssetManager = class extends ReadonlyAssetManager {
4129
4163
  for (const [inputIndex, assets] of assetInputs) {
4130
4164
  for (const asset of assets) {
4131
4165
  if (asset.assetId !== assetId) continue;
4132
- changeInputs.push(chunkSPDNHPM4_cjs.AssetInput.create(inputIndex, asset.amount));
4166
+ changeInputs.push(chunkFSAXPBGP_cjs.AssetInput.create(inputIndex, asset.amount));
4133
4167
  }
4134
4168
  }
4135
4169
  groups.push(
4136
- chunkSPDNHPM4_cjs.AssetGroup.create(
4137
- chunkSPDNHPM4_cjs.AssetId.fromString(assetId),
4170
+ chunkFSAXPBGP_cjs.AssetGroup.create(
4171
+ chunkFSAXPBGP_cjs.AssetId.fromString(assetId),
4138
4172
  null,
4139
4173
  changeInputs,
4140
- amount > 0n ? [chunkSPDNHPM4_cjs.AssetOutput.create(0, amount)] : [],
4174
+ amount > 0n ? [chunkFSAXPBGP_cjs.AssetOutput.create(0, amount)] : [],
4141
4175
  []
4142
4176
  )
4143
4177
  );
4144
4178
  }
4145
4179
  const address = await this.wallet.getAddress();
4146
- const outputAddress = chunkWMIPYZSB_cjs.ArkAddress.decode(address);
4180
+ const outputAddress = chunkCMPJR3HS_cjs.ArkAddress.decode(address);
4147
4181
  const outputs = [
4148
4182
  {
4149
4183
  script: outputAddress.pkScript,
4150
4184
  amount: BigInt(totalBtcSelected)
4151
4185
  },
4152
- Extension.create([chunkSPDNHPM4_cjs.Packet.create(groups)]).txOut()
4186
+ Extension.create([chunkFSAXPBGP_cjs.Packet.create(groups)]).txOut()
4153
4187
  ];
4154
4188
  const { arkTxid } = await this.wallet.buildAndSubmitOffchainTx(selectedCoins, outputs);
4155
4189
  return arkTxid;
@@ -4174,7 +4208,7 @@ function castMetadata(metadata) {
4174
4208
  } else {
4175
4209
  throw new Error("Invalid metadata value type");
4176
4210
  }
4177
- md.push(chunkSPDNHPM4_cjs.Metadata.create(textEncoder.encode(key), valueBytes));
4211
+ md.push(chunkFSAXPBGP_cjs.Metadata.create(textEncoder.encode(key), valueBytes));
4178
4212
  }
4179
4213
  return md;
4180
4214
  }
@@ -4192,7 +4226,7 @@ var DelegateManagerImpl = class {
4192
4226
  if (vtxos.length === 0) {
4193
4227
  return { delegated: [], failed: [] };
4194
4228
  }
4195
- const destinationScript = chunkWMIPYZSB_cjs.ArkAddress.decode(destination).pkScript;
4229
+ const destinationScript = chunkCMPJR3HS_cjs.ArkAddress.decode(destination).pkScript;
4196
4230
  const arkInfo = await this.arkInfoProvider.getInfo();
4197
4231
  const delegateInfo = await this.delegateProvider.getDelegateInfo();
4198
4232
  const eligible = vtxos.filter(
@@ -4340,7 +4374,7 @@ async function delegate(identity, delegateProvider, arkInfo, delegateInfo, vtxos
4340
4374
  const delegateFee = BigInt(Number(fee));
4341
4375
  if (delegateFee > 0n) {
4342
4376
  outputs.push({
4343
- script: chunkWMIPYZSB_cjs.ArkAddress.decode(delegateAddress).pkScript,
4377
+ script: chunkCMPJR3HS_cjs.ArkAddress.decode(delegateAddress).pkScript,
4344
4378
  amount: delegateFee
4345
4379
  });
4346
4380
  }
@@ -4373,7 +4407,7 @@ async function delegate(identity, delegateProvider, arkInfo, delegateInfo, vtxos
4373
4407
  destinationScript
4374
4408
  );
4375
4409
  const forfeitOutputScript = btcSigner.OutScript.encode(
4376
- btcSigner.Address(chunkWMIPYZSB_cjs.getNetwork(network)).decode(forfeitAddress)
4410
+ btcSigner.Address(chunkCMPJR3HS_cjs.getNetwork(network)).decode(forfeitAddress)
4377
4411
  );
4378
4412
  const forfeits = await Promise.all(
4379
4413
  vtxos.filter((v) => !isRecoverable(v)).map(async (coin) => {
@@ -4401,7 +4435,7 @@ async function makeDelegateForfeitTx(input, connectorAmount, delegatePubkey, for
4401
4435
  index: input.vout,
4402
4436
  witnessUtxo: {
4403
4437
  amount: BigInt(input.value),
4404
- script: chunkWMIPYZSB_cjs.VtxoScript.decode(input.tapTree).pkScript
4438
+ script: chunkCMPJR3HS_cjs.VtxoScript.decode(input.tapTree).pkScript
4405
4439
  },
4406
4440
  sighashType: btcSigner.SigHash.ALL_ANYONECANPAY,
4407
4441
  tapLeafScript: [delegateTapLeaf]
@@ -4459,7 +4493,7 @@ async function makeSignedDelegateIntent(identity, coins, outputs, onchainOutputs
4459
4493
  expire_at: 0,
4460
4494
  cosigners_public_keys: cosignerPubKeys
4461
4495
  };
4462
- const proof = chunkSPDNHPM4_cjs.Intent.create(message, coins, outputs);
4496
+ const proof = chunkFSAXPBGP_cjs.Intent.create(message, coins, outputs);
4463
4497
  const signedProof = await identity.sign(proof);
4464
4498
  return {
4465
4499
  proof: base.base64.encode(signedProof.toPSBT()),
@@ -4477,10 +4511,10 @@ function getDayTimestamp(timestamp) {
4477
4511
  function findDelegateTapLeaf(vtxo, delegatePubkey) {
4478
4512
  if (!vtxo.tapTree) return void 0;
4479
4513
  const pk = delegatePubkey.length === 66 ? delegatePubkey.slice(2) : delegatePubkey;
4480
- const vtxoScript = chunkWMIPYZSB_cjs.VtxoScript.decode(vtxo.tapTree);
4514
+ const vtxoScript = chunkCMPJR3HS_cjs.VtxoScript.decode(vtxo.tapTree);
4481
4515
  return vtxoScript.leaves.find((tapLeaf) => {
4482
- const arkTapscript = chunkWMIPYZSB_cjs.decodeTapscript(chunkWMIPYZSB_cjs.scriptFromTapLeafScript(tapLeaf));
4483
- 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;
4484
4518
  return arkTapscript.params.pubkeys.map(base.hex.encode).includes(pk);
4485
4519
  });
4486
4520
  }
@@ -4684,7 +4718,7 @@ var InMemoryContractRepository = class {
4684
4718
  }
4685
4719
  };
4686
4720
  function scriptFromArkAddress(address) {
4687
- return base.hex.encode(chunkWMIPYZSB_cjs.ArkAddress.decode(address).pkScript);
4721
+ return base.hex.encode(chunkCMPJR3HS_cjs.ArkAddress.decode(address).pkScript);
4688
4722
  }
4689
4723
 
4690
4724
  // src/repositories/indexedDB/schema.ts
@@ -6199,7 +6233,7 @@ var ContractWatcher = class {
6199
6233
  this.connectionState = "connected";
6200
6234
  this.reconnectAttempts = 0;
6201
6235
  this.listenLoop().catch((e) => {
6202
- if (chunkSPDNHPM4_cjs.isEventSourceError(e)) {
6236
+ if (chunkFSAXPBGP_cjs.isEventSourceError(e)) {
6203
6237
  console.debug("ContractWatcher subscription disconnected; reconnecting");
6204
6238
  } else {
6205
6239
  console.error(e);
@@ -6537,8 +6571,11 @@ function cursorCutoff(requestStartedAt) {
6537
6571
  }
6538
6572
 
6539
6573
  // src/contracts/contractManager.ts
6540
- var DEFAULT_PAGE_SIZE = 500;
6574
+ function areCoalescibleContractTypes(a, b) {
6575
+ return a === "default" && b === "boarding" || a === "boarding" && b === "default";
6576
+ }
6541
6577
  var SCAN_MAX_INDEX = 1e4;
6578
+ var DEFAULT_SCAN_BATCH = 10;
6542
6579
  var ContractManager = class _ContractManager {
6543
6580
  config;
6544
6581
  watcher;
@@ -6639,7 +6676,7 @@ var ContractManager = class _ContractManager {
6639
6676
  * `persisted` is `true`.
6640
6677
  */
6641
6678
  async upsertContract(params) {
6642
- const handler = chunkGYSK5R57_cjs.contractHandlers.get(params.type);
6679
+ const handler = chunkGUTKJMSF_cjs.contractHandlers.get(params.type);
6643
6680
  if (!handler) {
6644
6681
  throw new Error(`No handler registered for contract type '${params.type}'`);
6645
6682
  }
@@ -6662,8 +6699,11 @@ var ContractManager = class _ContractManager {
6662
6699
  const [existing] = await this.getContracts({ script: params.script });
6663
6700
  if (existing) {
6664
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
+ }
6665
6705
  throw new Error(
6666
- `Contract with script ${params.script} already exists with with type ${existing.type}.`
6706
+ `Contract with script ${params.script} already exists with type ${existing.type}.`
6667
6707
  );
6668
6708
  }
6669
6709
  const contract = {
@@ -6692,6 +6732,19 @@ var ContractManager = class _ContractManager {
6692
6732
  * other handler hit it).
6693
6733
  * - `persistAndWatchContract` rejecting is operational/fatal and
6694
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.
6695
6748
  */
6696
6749
  async scanContracts(opts) {
6697
6750
  const gapLimit = opts.gapLimit ?? 20;
@@ -6700,35 +6753,69 @@ var ContractManager = class _ContractManager {
6700
6753
  `scanContracts: gapLimit must be a positive integer (got ${String(opts.gapLimit)})`
6701
6754
  );
6702
6755
  }
6703
- const discoverables = chunkGYSK5R57_cjs.contractHandlers.getRegisteredTypes().map((t) => chunkGYSK5R57_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
+ ];
6704
6767
  const maxIdx = opts.hd ? SCAN_MAX_INDEX : 0;
6705
6768
  const handlerErrors = [];
6706
6769
  let lastIndexUsed = -1;
6707
6770
  let unused = 0;
6708
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
+ };
6709
6787
  while (i <= maxIdx && unused < gapLimit) {
6710
- const descriptor = opts.materialize(i);
6711
- let hitAtThisIndex = false;
6712
- for (const h of discoverables) {
6713
- let found;
6714
- try {
6715
- found = await h.discoverAt(i, descriptor, opts.deps);
6716
- } catch (error) {
6717
- handlerErrors.push({ handler: h.type, index: i, error });
6718
- 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
+ }
6719
6810
  }
6720
- for (const c of found) {
6721
- await this.persistAndWatchContract(c);
6722
- hitAtThisIndex = true;
6811
+ if (hitAtThisIndex) {
6812
+ lastIndexUsed = index;
6813
+ unused = 0;
6814
+ } else {
6815
+ unused += 1;
6723
6816
  }
6724
6817
  }
6725
- if (hitAtThisIndex) {
6726
- lastIndexUsed = i;
6727
- unused = 0;
6728
- } else {
6729
- unused += 1;
6730
- }
6731
- i += 1;
6818
+ i = windowEnd + 1;
6732
6819
  }
6733
6820
  if (opts.hd && i > maxIdx && unused < gapLimit) {
6734
6821
  throw new Error(
@@ -6856,7 +6943,7 @@ var ContractManager = class _ContractManager {
6856
6943
  const { contractScript, collaborative = true, walletPubKey, vtxo } = options;
6857
6944
  const [contract] = await this.getContracts({ script: contractScript });
6858
6945
  if (!contract) return [];
6859
- const handler = chunkGYSK5R57_cjs.contractHandlers.get(contract.type);
6946
+ const handler = chunkGUTKJMSF_cjs.contractHandlers.get(contract.type);
6860
6947
  if (!handler) return [];
6861
6948
  const script = handler.createScript(contract.params);
6862
6949
  const context = {
@@ -6876,7 +6963,7 @@ var ContractManager = class _ContractManager {
6876
6963
  const { contractScript, collaborative = true, walletPubKey } = options;
6877
6964
  const [contract] = await this.getContracts({ script: contractScript });
6878
6965
  if (!contract) return [];
6879
- const handler = chunkGYSK5R57_cjs.contractHandlers.get(contract.type);
6966
+ const handler = chunkGUTKJMSF_cjs.contractHandlers.get(contract.type);
6880
6967
  if (!handler) return [];
6881
6968
  const script = handler.createScript(contract.params);
6882
6969
  const context = {
@@ -7110,7 +7197,7 @@ var ContractManager = class _ContractManager {
7110
7197
  }
7111
7198
  return result;
7112
7199
  }
7113
- async fetchContractVtxosBulk(contracts, pageSize = DEFAULT_PAGE_SIZE, syncWindow) {
7200
+ async fetchContractVtxosBulk(contracts, pageSize = chunkGUTKJMSF_cjs.DEFAULT_PAGE_SIZE, syncWindow) {
7114
7201
  if (contracts.length === 0) {
7115
7202
  return /* @__PURE__ */ new Map();
7116
7203
  }
@@ -7286,7 +7373,7 @@ var HDDescriptorProvider = class _HDDescriptorProvider {
7286
7373
  */
7287
7374
  materializeDescriptorAt(index) {
7288
7375
  const descriptor = this.identity.descriptor;
7289
- const network = chunkGYSK5R57_cjs.isMainnetDescriptor(descriptor) ? descriptorsScure.networks.bitcoin : descriptorsScure.networks.testnet;
7376
+ const network = chunkGUTKJMSF_cjs.isMainnetDescriptor(descriptor) ? descriptorsScure.networks.bitcoin : descriptorsScure.networks.testnet;
7290
7377
  const expansion = descriptorsScure.expand({ descriptor, network, index });
7291
7378
  const keyInfo = expansion.expansionMap?.["@0"];
7292
7379
  if (!keyInfo?.keyExpression) {
@@ -7429,12 +7516,13 @@ var WalletReceiveRotator = class _WalletReceiveRotator {
7429
7516
  const provider = await resolveDescriptorProvider(config, setup.walletRepository);
7430
7517
  if (!provider) return void 0;
7431
7518
  const allowSilentFallback = (config.walletMode ?? "auto") === "auto";
7432
- const expectedContractType = setup.offchainTapscript instanceof chunkGYSK5R57_cjs.DelegateVtxo.Script ? "delegate" : "default";
7519
+ const expectedContractType = setup.offchainTapscript instanceof chunkGUTKJMSF_cjs.DelegateVtxo.Script ? "delegate" : "default";
7433
7520
  const factoryOpts = {
7434
7521
  walletRepository: setup.walletRepository,
7435
7522
  contractRepository: setup.contractRepository,
7436
7523
  serverPubKey: setup.serverPubKey,
7437
- expectedContractType
7524
+ expectedContractType,
7525
+ baselineReceivePubKey: setup.offchainTapscript.options.pubKey
7438
7526
  };
7439
7527
  let boot;
7440
7528
  try {
@@ -7479,14 +7567,17 @@ var WalletReceiveRotator = class _WalletReceiveRotator {
7479
7567
  receivePubkey: existing.pubKey
7480
7568
  };
7481
7569
  }
7482
- let descriptor;
7483
- if (hasPeekableDescriptor(provider)) {
7484
- 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
+ };
7485
7577
  }
7486
- descriptor ??= await provider.getNextSigningDescriptor();
7487
7578
  return {
7488
7579
  rotator: new _WalletReceiveRotator(provider, void 0, opts.logger),
7489
- receivePubkey: deriveLeafPubkey(descriptor)
7580
+ receivePubkey: opts.baselineReceivePubKey ?? deriveLeafPubkey(current)
7490
7581
  };
7491
7582
  }
7492
7583
  /**
@@ -7592,7 +7683,7 @@ var WalletReceiveRotator = class _WalletReceiveRotator {
7592
7683
  const newAddress = newTapscript.address(wallet.network.hrp, wallet.arkServerPublicKey).encode();
7593
7684
  const manager = await wallet.getContractManager();
7594
7685
  const csvTimelock = newTapscript.options.csvTimelock;
7595
- const csvTimelockStr = chunkWMIPYZSB_cjs.timelockToSequence(csvTimelock).toString();
7686
+ const csvTimelockStr = chunkCMPJR3HS_cjs.timelockToSequence(csvTimelock).toString();
7596
7687
  const serverPubKeyHex = base.hex.encode(newTapscript.options.serverPubKey);
7597
7688
  const baseParams = {
7598
7689
  script: newScript,
@@ -7606,11 +7697,11 @@ var WalletReceiveRotator = class _WalletReceiveRotator {
7606
7697
  // produce unsigned PSBTs that the server rejects with
7607
7698
  // `INVALID_PSBT_INPUT (5): missing tapscript spend sig`.
7608
7699
  metadata: {
7609
- source: chunkGYSK5R57_cjs.WALLET_RECEIVE_SOURCE,
7700
+ source: chunkGUTKJMSF_cjs.WALLET_RECEIVE_SOURCE,
7610
7701
  signingDescriptor: descriptor
7611
7702
  }
7612
7703
  };
7613
- if (newTapscript instanceof chunkGYSK5R57_cjs.DelegateVtxo.Script) {
7704
+ if (newTapscript instanceof chunkGUTKJMSF_cjs.DelegateVtxo.Script) {
7614
7705
  await manager.createContract({
7615
7706
  ...baseParams,
7616
7707
  type: "delegate",
@@ -7642,7 +7733,7 @@ var WalletReceiveRotator = class _WalletReceiveRotator {
7642
7733
  };
7643
7734
  function deriveLeafPubkey(descriptor) {
7644
7735
  try {
7645
- return chunkGYSK5R57_cjs.deriveDescriptorLeafPubKey(descriptor);
7736
+ return chunkGUTKJMSF_cjs.deriveDescriptorLeafPubKey(descriptor);
7646
7737
  } catch (e) {
7647
7738
  throw new NonRangeableDescriptorError(
7648
7739
  "Cannot derive leaf pubkey: descriptor is not a materialized, parsable tr(...) shape.",
@@ -7651,10 +7742,10 @@ function deriveLeafPubkey(descriptor) {
7651
7742
  }
7652
7743
  }
7653
7744
  function rebuildTapscript(current, pubKey) {
7654
- if (current instanceof chunkGYSK5R57_cjs.DelegateVtxo.Script) {
7655
- return new chunkGYSK5R57_cjs.DelegateVtxo.Script({ ...current.options, pubKey });
7745
+ if (current instanceof chunkGUTKJMSF_cjs.DelegateVtxo.Script) {
7746
+ return new chunkGUTKJMSF_cjs.DelegateVtxo.Script({ ...current.options, pubKey });
7656
7747
  }
7657
- return new chunkGYSK5R57_cjs.DefaultVtxo.Script({ ...current.options, pubKey });
7748
+ return new chunkGUTKJMSF_cjs.DefaultVtxo.Script({ ...current.options, pubKey });
7658
7749
  }
7659
7750
  async function pickActiveReceive(contractRepository, serverPubKey, expectedType) {
7660
7751
  const candidates = await contractRepository.getContracts({
@@ -7663,7 +7754,7 @@ async function pickActiveReceive(contractRepository, serverPubKey, expectedType)
7663
7754
  });
7664
7755
  const serverPubKeyHex = base.hex.encode(serverPubKey);
7665
7756
  const matching = candidates.filter(
7666
- (c) => c.params.serverPubKey === serverPubKeyHex && c.metadata?.source === chunkGYSK5R57_cjs.WALLET_RECEIVE_SOURCE
7757
+ (c) => c.params.serverPubKey === serverPubKeyHex && c.metadata?.source === chunkGUTKJMSF_cjs.WALLET_RECEIVE_SOURCE
7667
7758
  ).sort((a, b) => {
7668
7759
  if (b.createdAt !== a.createdAt) return b.createdAt - a.createdAt;
7669
7760
  return signingDescriptorIndex(b.metadata?.signingDescriptor) - signingDescriptorIndex(a.metadata?.signingDescriptor);
@@ -7719,7 +7810,7 @@ var DescriptorSigningProviderMissingError = class extends Error {
7719
7810
  };
7720
7811
 
7721
7812
  // src/wallet/inputSignerRouter.ts
7722
- var DESCRIPTOR_CAPABLE_CONTRACT_TYPES = /* @__PURE__ */ new Set(["default", "delegate"]);
7813
+ var DESCRIPTOR_CAPABLE_CONTRACT_TYPES = /* @__PURE__ */ new Set(["default", "delegate", "boarding"]);
7723
7814
  var InputSignerRouter = class {
7724
7815
  constructor(deps) {
7725
7816
  this.deps = deps;
@@ -7837,12 +7928,12 @@ var InputSignerRouter = class {
7837
7928
  };
7838
7929
 
7839
7930
  // src/wallet/wallet.ts
7840
- var getArkadeServerUrl = ({ arkServerUrl }) => arkServerUrl || chunkWMIPYZSB_cjs.DEFAULT_ARKADE_SERVER_URL;
7931
+ var getArkadeServerUrl = ({ arkServerUrl }) => arkServerUrl || chunkCMPJR3HS_cjs.DEFAULT_ARKADE_SERVER_URL;
7841
7932
  function intentProofJobs(coins) {
7842
7933
  if (coins.length === 0) return [];
7843
7934
  const coinJobs = coins.map((coin, i) => ({
7844
7935
  index: i + 1,
7845
- lookupScript: chunkWMIPYZSB_cjs.VtxoScript.decode(coin.tapTree).pkScript
7936
+ lookupScript: chunkCMPJR3HS_cjs.VtxoScript.decode(coin.tapTree).pkScript
7846
7937
  }));
7847
7938
  return [{ index: 0, lookupScript: coinJobs[0].lookupScript }, ...coinJobs];
7848
7939
  }
@@ -7851,6 +7942,11 @@ function extractArkProviderUrl(provider) {
7851
7942
  return typeof serverUrl === "string" && serverUrl.length > 0 ? serverUrl : void 0;
7852
7943
  }
7853
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
+ }
7854
7950
  function delayToTimelock(delay) {
7855
7951
  return {
7856
7952
  value: delay,
@@ -7861,27 +7957,37 @@ function dedupeTimelocks(timelocks) {
7861
7957
  const seen = /* @__PURE__ */ new Set();
7862
7958
  const deduped = [];
7863
7959
  for (const timelock of timelocks) {
7864
- const sequence = chunkWMIPYZSB_cjs.timelockToSequence(timelock).toString();
7960
+ const sequence = chunkCMPJR3HS_cjs.timelockToSequence(timelock).toString();
7865
7961
  if (seen.has(sequence)) continue;
7866
7962
  seen.add(sequence);
7867
7963
  deduped.push(timelock);
7868
7964
  }
7869
7965
  return deduped;
7870
7966
  }
7871
- function areSameScriptBaselineTypesCompatible(existingType, requestedType) {
7872
- if (existingType === requestedType) return true;
7873
- return existingType === "default" && requestedType === "boarding" || existingType === "boarding" && requestedType === "default";
7874
- }
7875
7967
  async function ensureWalletContract(manager, params) {
7876
- const [existing] = await manager.getContracts({ script: params.script });
7877
- if (existing && existing.type !== params.type && areSameScriptBaselineTypesCompatible(existing.type, params.type)) {
7878
- if (params.type === "default" && existing.type === "boarding") {
7879
- await manager.updateContract(params.script, { type: "default" });
7880
- }
7881
- return;
7882
- }
7883
7968
  await manager.createContract(params);
7884
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
+ }
7885
7991
  function hasToReadonly(identity) {
7886
7992
  return typeof identity === "object" && identity !== null && "toReadonly" in identity && typeof identity.toReadonly === "function";
7887
7993
  }
@@ -7892,7 +7998,6 @@ var ReadonlyWallet = class _ReadonlyWallet {
7892
7998
  this.onchainProvider = onchainProvider;
7893
7999
  this.indexerProvider = indexerProvider;
7894
8000
  this.arkServerPublicKey = arkServerPublicKey;
7895
- this.boardingTapscript = boardingTapscript;
7896
8001
  this.dustAmount = dustAmount;
7897
8002
  this.walletRepository = walletRepository;
7898
8003
  this.contractRepository = contractRepository;
@@ -7908,6 +8013,7 @@ var ReadonlyWallet = class _ReadonlyWallet {
7908
8013
  }
7909
8014
  }
7910
8015
  this._offchainTapscript = offchainTapscript;
8016
+ this._boardingTapscript = boardingTapscript;
7911
8017
  this.watcherConfig = watcherConfig;
7912
8018
  this._assetManager = new ReadonlyAssetManager(this.indexerProvider);
7913
8019
  this.walletContractTimelocks = walletContractTimelocks && walletContractTimelocks.length > 0 ? dedupeTimelocks(walletContractTimelocks) : [this.offchainTapscript.options.csvTimelock];
@@ -7934,6 +8040,17 @@ var ReadonlyWallet = class _ReadonlyWallet {
7934
8040
  * {@link WalletReceiveRotator.rotate} is the sole intended caller of.
7935
8041
  */
7936
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;
7937
8054
  /**
7938
8055
  * Currently-active receive tapscript. Read-only from the outside;
7939
8056
  * mutated only via {@link Wallet.setOffchainTapscriptForRotation}
@@ -7942,13 +8059,59 @@ var ReadonlyWallet = class _ReadonlyWallet {
7942
8059
  get offchainTapscript() {
7943
8060
  return this._offchainTapscript;
7944
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
+ }
7945
8108
  /**
7946
8109
  * Protected helper to set up shared wallet configuration.
7947
8110
  * Extracts common logic used by both ReadonlyWallet.create() and Wallet.create().
7948
8111
  */
7949
8112
  static async setupWalletConfig(config, pubKey) {
7950
8113
  const arkadeServerUrl = getArkadeServerUrl(config);
7951
- const arkProvider = config.arkProvider || new chunkSPDNHPM4_cjs.RestArkProvider(arkadeServerUrl);
8114
+ const arkProvider = config.arkProvider || new chunkFSAXPBGP_cjs.RestArkProvider(arkadeServerUrl);
7952
8115
  let indexerProvider = config.indexerProvider;
7953
8116
  if (!indexerProvider) {
7954
8117
  let indexerUrl = config.indexerUrl;
@@ -7965,10 +8128,10 @@ var ReadonlyWallet = class _ReadonlyWallet {
7965
8128
  indexerUrl = arkadeServerUrl;
7966
8129
  }
7967
8130
  }
7968
- indexerProvider = new chunkSPDNHPM4_cjs.RestIndexerProvider(indexerUrl);
8131
+ indexerProvider = new chunkFSAXPBGP_cjs.RestIndexerProvider(indexerUrl);
7969
8132
  }
7970
8133
  const info = await arkProvider.getInfo();
7971
- const network = chunkWMIPYZSB_cjs.getNetwork(info.network);
8134
+ const network = chunkCMPJR3HS_cjs.getNetwork(info.network);
7972
8135
  if ("descriptor" in config.identity) {
7973
8136
  const descriptor = config.identity.descriptor;
7974
8137
  const identityIsMainnet = !descriptor.includes("tpub");
@@ -8015,11 +8178,11 @@ var ReadonlyWallet = class _ReadonlyWallet {
8015
8178
  serverPubKey,
8016
8179
  csvTimelock: exitTimelock
8017
8180
  };
8018
- const offchainTapscript = !delegatePubKey ? new chunkGYSK5R57_cjs.DefaultVtxo.Script(offchainOptions) : new chunkGYSK5R57_cjs.DelegateVtxo.Script({ ...offchainOptions, delegatePubKey });
8019
- const boardingTapscript = chunkGYSK5R57_cjs.BoardingContractHandler.createScript({
8181
+ const offchainTapscript = !delegatePubKey ? new chunkGUTKJMSF_cjs.DefaultVtxo.Script(offchainOptions) : new chunkGUTKJMSF_cjs.DelegateVtxo.Script({ ...offchainOptions, delegatePubKey });
8182
+ const boardingTapscript = chunkGUTKJMSF_cjs.BoardingContractHandler.createScript({
8020
8183
  pubKey: base.hex.encode(pubKey),
8021
8184
  serverPubKey: base.hex.encode(serverPubKey),
8022
- csvTimelock: chunkWMIPYZSB_cjs.timelockToSequence(boardingTimelock).toString()
8185
+ csvTimelock: chunkCMPJR3HS_cjs.timelockToSequence(boardingTimelock).toString()
8023
8186
  });
8024
8187
  const walletRepository = config.storage?.walletRepository ?? new IndexedDBWalletRepository();
8025
8188
  const contractRepository = config.storage?.contractRepository ?? new IndexedDBContractRepository();
@@ -8182,43 +8345,59 @@ var ReadonlyWallet = class _ReadonlyWallet {
8182
8345
  await clearSyncCursor(this.walletRepository);
8183
8346
  }
8184
8347
  /**
8185
- * 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).
8186
8361
  */
8187
8362
  async getBoardingTxs() {
8188
8363
  const utxos = [];
8189
8364
  const commitmentsToIgnore = /* @__PURE__ */ new Set();
8190
- const boardingAddress = await this.getBoardingAddress();
8191
- const txs = await this.onchainProvider.getTransactions(boardingAddress);
8365
+ const tapscripts = await this.getBoardingTapscripts();
8192
8366
  const outspendCache = /* @__PURE__ */ new Map();
8193
- for (const tx of txs) {
8194
- for (let i = 0; i < tx.vout.length; i++) {
8195
- const vout = tx.vout[i];
8196
- if (vout.scriptpubkey_address === boardingAddress) {
8197
- let spentStatuses = outspendCache.get(tx.txid);
8198
- if (!spentStatuses) {
8199
- spentStatuses = await this.onchainProvider.getTxOutspends(tx.txid);
8200
- outspendCache.set(tx.txid, spentStatuses);
8201
- }
8202
- const spentStatus = spentStatuses[i];
8203
- if (spentStatus?.spent) {
8204
- 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
+ });
8205
8400
  }
8206
- utxos.push({
8207
- txid: tx.txid,
8208
- vout: i,
8209
- value: Number(vout.value),
8210
- status: {
8211
- confirmed: tx.status.confirmed,
8212
- block_time: tx.status.block_time
8213
- },
8214
- isUnrolled: true,
8215
- virtualStatus: {
8216
- state: spentStatus?.spent ? "spent" : "settled",
8217
- commitmentTxIds: spentStatus?.spent ? [spentStatus.txid] : void 0
8218
- },
8219
- createdAt: tx.status.confirmed ? new Date(tx.status.block_time * 1e3) : /* @__PURE__ */ new Date(0),
8220
- script: base.hex.encode(this.boardingTapscript.pkScript)
8221
- });
8222
8401
  }
8223
8402
  }
8224
8403
  }
@@ -8248,48 +8427,130 @@ var ReadonlyWallet = class _ReadonlyWallet {
8248
8427
  };
8249
8428
  }
8250
8429
  /**
8251
- * 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.
8252
8440
  */
8253
- async getBoardingUtxos() {
8254
- const boardingAddress = await this.getBoardingAddress();
8255
- const boardingUtxos = await this.onchainProvider.getCoins(boardingAddress);
8256
- const utxos = boardingUtxos.map((utxo) => {
8257
- 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"]
8258
8456
  });
8259
- await this.walletRepository.saveUtxos(boardingAddress, utxos);
8260
- 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;
8261
8485
  }
8262
8486
  /**
8263
8487
  * Subscribe to onchain and offchain notifications for newly received funds.
8264
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
+ *
8265
8498
  * @param eventCallback - Callback invoked when matching funds are detected
8266
8499
  * @returns A function that stops the subscriptions
8267
8500
  */
8268
8501
  async notifyIncomingFunds(eventCallback) {
8269
8502
  const arkAddress = await this.getAddress();
8270
- const boardingAddress = await this.getBoardingAddress();
8271
8503
  let onchainStopFunc;
8272
8504
  let indexerStopFunc;
8273
- if (this.onchainProvider && boardingAddress) {
8274
- const findVoutOnTx = (tx) => {
8275
- return tx.vout.findIndex((v) => v.scriptpubkey_address === boardingAddress);
8276
- };
8277
- onchainStopFunc = await this.onchainProvider.watchAddresses(
8278
- [boardingAddress],
8279
- (txs) => {
8280
- const coins = txs.filter((tx) => findVoutOnTx(tx) !== -1).map((tx) => {
8281
- const { txid, status } = tx;
8282
- const vout = findVoutOnTx(tx);
8283
- const value = Number(tx.vout[vout].value);
8284
- return { txid, vout, value, status };
8285
- });
8286
- eventCallback({
8287
- type: "utxo",
8288
- coins
8289
- });
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;
8290
8542
  }
8291
- );
8292
- }
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();
8293
8554
  if (this.indexerProvider && arkAddress) {
8294
8555
  const cm = await this.getContractManager();
8295
8556
  let annotationQueue = Promise.resolve();
@@ -8318,7 +8579,10 @@ var ReadonlyWallet = class _ReadonlyWallet {
8318
8579
  });
8319
8580
  }
8320
8581
  const stopFunc = () => {
8582
+ stopped = true;
8583
+ boardingRotationStopFunc?.();
8321
8584
  onchainStopFunc?.();
8585
+ onchainStopFunc = void 0;
8322
8586
  indexerStopFunc?.();
8323
8587
  };
8324
8588
  return stopFunc;
@@ -8359,7 +8623,7 @@ var ReadonlyWallet = class _ReadonlyWallet {
8359
8623
  });
8360
8624
  for (const contract of contracts) {
8361
8625
  if (map.has(contract.script)) continue;
8362
- const handler = chunkGYSK5R57_cjs.contractHandlers.get(contract.type);
8626
+ const handler = chunkGUTKJMSF_cjs.contractHandlers.get(contract.type);
8363
8627
  if (handler) {
8364
8628
  const script = handler.createScript(contract.params);
8365
8629
  map.set(contract.script, script);
@@ -8425,8 +8689,8 @@ var ReadonlyWallet = class _ReadonlyWallet {
8425
8689
  });
8426
8690
  const baselinePubkey = await this.identity.xOnlyPublicKey();
8427
8691
  for (const csvTimelock of this.walletContractTimelocks) {
8428
- const csvTimelockStr = chunkWMIPYZSB_cjs.timelockToSequence(csvTimelock).toString();
8429
- const defaultScript = new chunkGYSK5R57_cjs.DefaultVtxo.Script({
8692
+ const csvTimelockStr = chunkCMPJR3HS_cjs.timelockToSequence(csvTimelock).toString();
8693
+ const defaultScript = new chunkGUTKJMSF_cjs.DefaultVtxo.Script({
8430
8694
  pubKey: baselinePubkey,
8431
8695
  serverPubKey: this.offchainTapscript.options.serverPubKey,
8432
8696
  csvTimelock
@@ -8443,8 +8707,8 @@ var ReadonlyWallet = class _ReadonlyWallet {
8443
8707
  address: defaultScript.address(this.network.hrp, this.arkServerPublicKey).encode(),
8444
8708
  state: "active"
8445
8709
  });
8446
- if (this.offchainTapscript instanceof chunkGYSK5R57_cjs.DelegateVtxo.Script) {
8447
- const delegateScript = new chunkGYSK5R57_cjs.DelegateVtxo.Script({
8710
+ if (this.offchainTapscript instanceof chunkGUTKJMSF_cjs.DelegateVtxo.Script) {
8711
+ const delegateScript = new chunkGUTKJMSF_cjs.DelegateVtxo.Script({
8448
8712
  pubKey: baselinePubkey,
8449
8713
  serverPubKey: this.offchainTapscript.options.serverPubKey,
8450
8714
  delegatePubKey: this.offchainTapscript.options.delegatePubKey,
@@ -8465,17 +8729,21 @@ var ReadonlyWallet = class _ReadonlyWallet {
8465
8729
  });
8466
8730
  }
8467
8731
  }
8468
- const boardingScriptHex = base.hex.encode(this.boardingTapscript.pkScript);
8469
- const boardingCsvTimelock = this.boardingTapscript.options.csvTimelock ?? chunkGYSK5R57_cjs.DefaultVtxo.Script.DEFAULT_TIMELOCK;
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
+ });
8470
8738
  await ensureWalletContract(manager, {
8471
8739
  type: "boarding",
8472
8740
  params: {
8473
- pubKey: base.hex.encode(this.boardingTapscript.options.pubKey),
8474
- serverPubKey: base.hex.encode(this.boardingTapscript.options.serverPubKey),
8475
- csvTimelock: chunkWMIPYZSB_cjs.timelockToSequence(boardingCsvTimelock).toString()
8741
+ pubKey: base.hex.encode(baselineBoarding.options.pubKey),
8742
+ serverPubKey: base.hex.encode(baselineBoarding.options.serverPubKey),
8743
+ csvTimelock: chunkCMPJR3HS_cjs.timelockToSequence(boardingCsvTimelock).toString()
8476
8744
  },
8477
- script: boardingScriptHex,
8478
- address: this.boardingTapscript.address(this.network.hrp, this.arkServerPublicKey).encode(),
8745
+ script: base.hex.encode(baselineBoarding.pkScript),
8746
+ address: baselineBoarding.address(this.network.hrp, this.arkServerPublicKey).encode(),
8479
8747
  state: "active"
8480
8748
  });
8481
8749
  return manager;
@@ -8575,6 +8843,72 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
8575
8843
  setOffchainTapscriptForRotation(tapscript) {
8576
8844
  this._offchainTapscript = tapscript;
8577
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
+ }
8578
8912
  /**
8579
8913
  * Async mutex that serializes all operations submitting VTXOs to the Arkade
8580
8914
  * server (`settle`, `send`, `sendBitcoin`). This prevents VtxoManager's
@@ -8658,13 +8992,26 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
8658
8992
  const hd = provider instanceof HDDescriptorProvider;
8659
8993
  const staticDescriptor = hd ? void 0 : `tr(${base.hex.encode(await this.identity.xOnlyPublicKey())})`;
8660
8994
  const materialize = (index) => hd ? provider.materializeDescriptorAt(index) : staticDescriptor;
8661
- const delegatePubKey = this.offchainTapscript instanceof chunkGYSK5R57_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
+ );
8662
9001
  const deps = {
8663
9002
  indexerProvider: this.indexerProvider,
8664
9003
  onchainProvider: this.onchainProvider,
8665
9004
  network: { hrp: this.network.hrp },
8666
- 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,
8667
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,
8668
9015
  delegatePubKey
8669
9016
  };
8670
9017
  const result = await manager.scanContracts({
@@ -8765,7 +9112,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
8765
9112
  let serverUnrollScript;
8766
9113
  try {
8767
9114
  const raw = base.hex.decode(setup.info.checkpointTapscript);
8768
- serverUnrollScript = chunkWMIPYZSB_cjs.CSVMultisigTapscript.decode(raw);
9115
+ serverUnrollScript = chunkCMPJR3HS_cjs.CSVMultisigTapscript.decode(raw);
8769
9116
  } catch (e) {
8770
9117
  throw new Error("Invalid checkpointTapscript from server");
8771
9118
  }
@@ -8796,6 +9143,16 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
8796
9143
  boot?.rotator,
8797
9144
  boot?.provider
8798
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
+ }
8799
9156
  await wallet.getVtxoManager();
8800
9157
  return wallet;
8801
9158
  }
@@ -8871,7 +9228,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
8871
9228
  inputs: params.selectedVtxos,
8872
9229
  changeAmount: BigInt(changeAmount)
8873
9230
  };
8874
- const outputAddress = chunkWMIPYZSB_cjs.ArkAddress.decode(params.address);
9231
+ const outputAddress = chunkCMPJR3HS_cjs.ArkAddress.decode(params.address);
8875
9232
  const outputScript = BigInt(params.amount) < this.dustAmount ? outputAddress.subdustPkScript : outputAddress.pkScript;
8876
9233
  const outputs = [
8877
9234
  {
@@ -8938,7 +9295,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
8938
9295
  const { fees } = await this.arkProvider.getInfo();
8939
9296
  const estimator = new Estimator(fees.intentFee);
8940
9297
  let amount = 0;
8941
- const exitScript = chunkWMIPYZSB_cjs.CSVMultisigTapscript.decode(
9298
+ const exitScript = chunkCMPJR3HS_cjs.CSVMultisigTapscript.decode(
8942
9299
  base.hex.decode(this.boardingTapscript.exitScript)
8943
9300
  );
8944
9301
  const boardingTimelock = exitScript.params.timelock;
@@ -8963,7 +9320,10 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
8963
9320
  }
8964
9321
  const vtxos = await this.getVtxos({ withRecoverable: true });
8965
9322
  const filteredVtxos = [];
8966
- for (const vtxo of vtxos) {
9323
+ for (const vtxo of byValueDescending(vtxos)) {
9324
+ if (filteredVtxos.length >= MAX_VTXOS_PER_SETTLEMENT) {
9325
+ break;
9326
+ }
8967
9327
  const inputFee = estimator.evalOffchainInput({
8968
9328
  amount: BigInt(vtxo.value),
8969
9329
  type: vtxo.virtualStatus.state === "swept" ? "recoverable" : "vtxo",
@@ -8987,7 +9347,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
8987
9347
  };
8988
9348
  const outputFee = estimator.evalOffchainOutput({
8989
9349
  amount: output.amount,
8990
- script: base.hex.encode(chunkWMIPYZSB_cjs.ArkAddress.decode(output.address).pkScript)
9350
+ script: base.hex.encode(chunkCMPJR3HS_cjs.ArkAddress.decode(output.address).pkScript)
8991
9351
  });
8992
9352
  output.amount -= BigInt(outputFee.satoshis);
8993
9353
  if (output.amount <= this.dustAmount) {
@@ -9004,7 +9364,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9004
9364
  for (const [index, output] of params.outputs.entries()) {
9005
9365
  let script;
9006
9366
  try {
9007
- const addr = chunkWMIPYZSB_cjs.ArkAddress.decode(output.address);
9367
+ const addr = chunkCMPJR3HS_cjs.ArkAddress.decode(output.address);
9008
9368
  script = addr.pkScript;
9009
9369
  hasOffchainOutputs = true;
9010
9370
  } catch {
@@ -9027,7 +9387,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9027
9387
  }
9028
9388
  }
9029
9389
  let outputAssets;
9030
- const destinationScript = chunkWMIPYZSB_cjs.ArkAddress.decode(await this.getAddress()).pkScript;
9390
+ const destinationScript = chunkCMPJR3HS_cjs.ArkAddress.decode(await this.getAddress()).pkScript;
9031
9391
  const assetOutputIndex = findDestinationOutputIndex(outputs, destinationScript);
9032
9392
  if (assetInputs.size > 0) {
9033
9393
  if (assetOutputIndex === -1) {
@@ -9096,6 +9456,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9096
9456
  eventCallback: eventCallback ? (event) => Promise.resolve(eventCallback(event)) : void 0
9097
9457
  });
9098
9458
  await this.updateDbAfterSettle(params.inputs, commitmentTxid);
9459
+ await this.maybeRotateBoardingAfterBoard(params.inputs);
9099
9460
  return commitmentTxid;
9100
9461
  } catch (error) {
9101
9462
  const inputIds = params.inputs.map((i) => `${i.txid}:${i.vout}`).join(",");
@@ -9113,6 +9474,41 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9113
9474
  });
9114
9475
  }
9115
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
+ }
9116
9512
  async handleSettlementFinalizationEvent(event, inputs, forfeitOutputScript, connectorsGraph) {
9117
9513
  const signedForfeits = [];
9118
9514
  const isVtxo = (input) => "virtualStatus" in input;
@@ -9177,7 +9573,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9177
9573
  index: input.vout,
9178
9574
  witnessUtxo: {
9179
9575
  amount: BigInt(input.value),
9180
- script: chunkWMIPYZSB_cjs.VtxoScript.decode(input.tapTree).pkScript
9576
+ script: chunkCMPJR3HS_cjs.VtxoScript.decode(input.tapTree).pkScript
9181
9577
  },
9182
9578
  sighashType: btcSigner.SigHash.DEFAULT,
9183
9579
  tapLeafScript: [input.forfeitTapLeafScript]
@@ -9196,7 +9592,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9196
9592
  forfeitTx = await this._signerRouter.sign(forfeitTx, [
9197
9593
  {
9198
9594
  index: 0,
9199
- lookupScript: chunkWMIPYZSB_cjs.VtxoScript.decode(input.tapTree).pkScript
9595
+ lookupScript: chunkCMPJR3HS_cjs.VtxoScript.decode(input.tapTree).pkScript
9200
9596
  }
9201
9597
  ]);
9202
9598
  signedForfeits.push(base.base64.encode(forfeitTx.toPSBT()));
@@ -9236,7 +9632,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9236
9632
  if (skip) {
9237
9633
  return { skip };
9238
9634
  }
9239
- const sweepTapscript = chunkWMIPYZSB_cjs.CSVMultisigTapscript.encode({
9635
+ const sweepTapscript = chunkCMPJR3HS_cjs.CSVMultisigTapscript.encode({
9240
9636
  timelock: {
9241
9637
  value: event.batchExpiry,
9242
9638
  type: event.batchExpiry >= 512n ? "seconds" : "blocks"
@@ -9323,11 +9719,24 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9323
9719
  }
9324
9720
  return jobs;
9325
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
+ }
9326
9735
  async safeRegisterIntent(intent, inputs) {
9327
9736
  try {
9328
9737
  return await this.arkProvider.registerIntent(intent);
9329
9738
  } catch (error) {
9330
- if (error instanceof chunkSPDNHPM4_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")) {
9331
9740
  const deleteIntent = await this.makeDeleteIntentSignature(inputs);
9332
9741
  await this.arkProvider.deleteIntent(deleteIntent);
9333
9742
  return this.arkProvider.registerIntent(intent);
@@ -9343,7 +9752,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9343
9752
  expire_at: 0,
9344
9753
  cosigners_public_keys: cosignerPubKeys
9345
9754
  };
9346
- const proof = chunkSPDNHPM4_cjs.Intent.create(message, coins, outputs);
9755
+ const proof = chunkFSAXPBGP_cjs.Intent.create(message, coins, outputs);
9347
9756
  const signedProof = await this._signerRouter.sign(proof, intentProofJobs(coins));
9348
9757
  return {
9349
9758
  proof: base.base64.encode(signedProof.toPSBT()),
@@ -9355,7 +9764,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9355
9764
  type: "delete",
9356
9765
  expire_at: 0
9357
9766
  };
9358
- const proof = chunkSPDNHPM4_cjs.Intent.create(message, coins, []);
9767
+ const proof = chunkFSAXPBGP_cjs.Intent.create(message, coins, []);
9359
9768
  const signedProof = await this._signerRouter.sign(proof, intentProofJobs(coins));
9360
9769
  return {
9361
9770
  proof: base.base64.encode(signedProof.toPSBT()),
@@ -9367,7 +9776,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9367
9776
  type: "get-pending-tx",
9368
9777
  expire_at: 0
9369
9778
  };
9370
- const proof = chunkSPDNHPM4_cjs.Intent.create(message, coins, []);
9779
+ const proof = chunkFSAXPBGP_cjs.Intent.create(message, coins, []);
9371
9780
  const signedProof = await this._signerRouter.sign(proof, intentProofJobs(coins));
9372
9781
  return {
9373
9782
  proof: base.base64.encode(signedProof.toPSBT()),
@@ -9684,7 +10093,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9684
10093
  );
9685
10094
  const arkTxJobs = inputs.map((input, index) => ({
9686
10095
  index,
9687
- lookupScript: chunkWMIPYZSB_cjs.VtxoScript.decode(input.tapTree).pkScript
10096
+ lookupScript: chunkCMPJR3HS_cjs.VtxoScript.decode(input.tapTree).pkScript
9688
10097
  }));
9689
10098
  const checkpointJobs = offchainTx.checkpoints.map(
9690
10099
  (c) => this.inputSigningJobsFromWitnessUtxos(c)
@@ -9889,10 +10298,9 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9889
10298
  // mark virtual outputs as spent/settled, remove boarding inputs
9890
10299
  async updateDbAfterSettle(inputs, commitmentTxid) {
9891
10300
  try {
9892
- const boardingAddress = await this.getBoardingAddress();
9893
10301
  const spentVtxos = [];
9894
10302
  const inputArkTxIds = /* @__PURE__ */ new Set();
9895
- const boardingUtxoToRemove = /* @__PURE__ */ new Set();
10303
+ const boardingRemovalsByAddress = /* @__PURE__ */ new Map();
9896
10304
  const isVtxo = (input) => "virtualStatus" in input;
9897
10305
  const vtxoInputs = inputs.filter(isVtxo);
9898
10306
  const cm = await this.getContractManager();
@@ -9914,7 +10322,20 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9914
10322
  isSpent: true
9915
10323
  });
9916
10324
  } else {
9917
- 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}`);
9918
10339
  }
9919
10340
  }
9920
10341
  if (spentVtxos.length > 0) {
@@ -9946,14 +10367,12 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
9946
10367
  );
9947
10368
  }
9948
10369
  }
9949
- if (boardingUtxoToRemove.size > 0) {
9950
- const currentUtxos = await this.walletRepository.getUtxos(boardingAddress);
9951
- const filtered = currentUtxos.filter(
9952
- (u) => !boardingUtxoToRemove.has(`${u.txid}:${u.vout}`)
9953
- );
9954
- 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);
9955
10374
  if (filtered.length > 0) {
9956
- await this.walletRepository.saveUtxos(boardingAddress, filtered);
10375
+ await this.walletRepository.saveUtxos(address, filtered);
9957
10376
  }
9958
10377
  }
9959
10378
  } catch (e) {
@@ -10161,7 +10580,7 @@ var MessageBus = class {
10161
10580
  this.initialized = true;
10162
10581
  }
10163
10582
  async buildServices(config) {
10164
- const arkProvider = new chunkSPDNHPM4_cjs.RestArkProvider(config.arkServer.url);
10583
+ const arkProvider = new chunkFSAXPBGP_cjs.RestArkProvider(config.arkServer.url);
10165
10584
  const storage = {
10166
10585
  walletRepository: this.walletRepository,
10167
10586
  contractRepository: this.contractRepository
@@ -10537,7 +10956,7 @@ var Ramps = class {
10537
10956
  }
10538
10957
  amount = amount ?? totalAmount;
10539
10958
  const offchainAddress = await this.wallet.getAddress();
10540
- const offchainAddr = chunkWMIPYZSB_cjs.ArkAddress.decode(offchainAddress);
10959
+ const offchainAddr = chunkCMPJR3HS_cjs.ArkAddress.decode(offchainAddress);
10541
10960
  const offchainScript = base.hex.encode(offchainAddr.pkScript);
10542
10961
  const outputFee = estimator.evalOffchainOutput({
10543
10962
  amount,
@@ -10635,7 +11054,7 @@ var Ramps = class {
10635
11054
  let destinationScript;
10636
11055
  for (const networkName of networkNames) {
10637
11056
  try {
10638
- const network = chunkWMIPYZSB_cjs.networks[networkName];
11057
+ const network = chunkCMPJR3HS_cjs.networks[networkName];
10639
11058
  const addr = btcSigner.Address(network).decode(destinationAddress);
10640
11059
  destinationScript = btcSigner.OutScript.encode(addr);
10641
11060
  break;
@@ -11204,7 +11623,7 @@ var WalletMessageHandler = class {
11204
11623
  // Wallet methods
11205
11624
  async handleInitWallet({ payload }) {
11206
11625
  const { arkServerUrl } = payload;
11207
- this.indexerProvider = new chunkSPDNHPM4_cjs.RestIndexerProvider(arkServerUrl);
11626
+ this.indexerProvider = new chunkFSAXPBGP_cjs.RestIndexerProvider(arkServerUrl);
11208
11627
  await this.onWalletInitialized();
11209
11628
  }
11210
11629
  async handleGetBalance() {
@@ -11353,9 +11772,7 @@ var WalletMessageHandler = class {
11353
11772
  );
11354
11773
  }
11355
11774
  if (funds.type === "utxo") {
11356
- const utxos = funds.coins.map((utxo) => extendCoin(this.readonlyWallet, utxo));
11357
- const boardingAddress = await this.readonlyWallet.getBoardingAddress();
11358
- await this.walletRepository?.saveUtxos(boardingAddress, utxos);
11775
+ const utxos = await this.readonlyWallet.getBoardingUtxos();
11359
11776
  this.scheduleForNextTick(
11360
11777
  () => this.tagged({
11361
11778
  type: "UTXO_UPDATE",
@@ -11384,13 +11801,16 @@ var WalletMessageHandler = class {
11384
11801
  return;
11385
11802
  }
11386
11803
  const vtxos = await this.getVtxosFromRepo();
11387
- const boardingAddress = await this.readonlyWallet.getBoardingAddress();
11388
- const coins = await this.readonlyWallet.onchainProvider.getCoins(boardingAddress);
11389
- await this.walletRepository.deleteUtxos(boardingAddress);
11390
- await this.walletRepository.saveUtxos(
11391
- boardingAddress,
11392
- coins.map((utxo) => extendCoin(this.readonlyWallet, utxo))
11393
- );
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
+ }
11394
11814
  const address = await this.readonlyWallet.getAddress();
11395
11815
  const txs = await this.buildTransactionHistoryFromCache(vtxos);
11396
11816
  if (txs) await this.walletRepository.saveTransactions(address, txs);
@@ -12837,12 +13257,12 @@ var OnchainWallet = class _OnchainWallet {
12837
13257
  * @returns Configured onchain wallet
12838
13258
  * @throws Error if the configured identity cannot produce a valid x-only public key
12839
13259
  */
12840
- static async create(identity, networkName = chunkWMIPYZSB_cjs.DEFAULT_NETWORK_NAME, provider) {
13260
+ static async create(identity, networkName = chunkCMPJR3HS_cjs.DEFAULT_NETWORK_NAME, provider) {
12841
13261
  const pubkey = await identity.xOnlyPublicKey();
12842
13262
  if (!pubkey) {
12843
13263
  throw new Error("Invalid configured public key");
12844
13264
  }
12845
- const network = chunkWMIPYZSB_cjs.getNetwork(networkName);
13265
+ const network = chunkCMPJR3HS_cjs.getNetwork(networkName);
12846
13266
  const onchainProvider = provider || new EsploraProvider(ESPLORA_URL[networkName]);
12847
13267
  const onchainP2TR = btcSigner.p2tr(pubkey, void 0, network);
12848
13268
  return new _OnchainWallet(identity, network, onchainP2TR, onchainProvider);
@@ -12948,7 +13368,7 @@ var OnchainWallet = class _OnchainWallet {
12948
13368
  if (!inputs) {
12949
13369
  throw new Error("Fee estimation failed");
12950
13370
  }
12951
- let tx = new chunkSPDNHPM4_cjs.Transaction();
13371
+ let tx = new chunkFSAXPBGP_cjs.Transaction();
12952
13372
  for (const input of inputs) {
12953
13373
  tx.addInput({
12954
13374
  txid: input.txid,
@@ -12979,7 +13399,7 @@ var OnchainWallet = class _OnchainWallet {
12979
13399
  */
12980
13400
  async bumpP2A(parent) {
12981
13401
  const parentVsize = parent.vsize;
12982
- let child = new chunkSPDNHPM4_cjs.Transaction({
13402
+ let child = new chunkFSAXPBGP_cjs.Transaction({
12983
13403
  version: 3,
12984
13404
  allowLegacyWitnessUtxo: true
12985
13405
  });
@@ -13736,7 +14156,7 @@ exports.BIP322 = void 0;
13736
14156
  async function sign2(message, identity, network) {
13737
14157
  const xOnlyPubKey = await identity.xOnlyPublicKey();
13738
14158
  const payment = btcSigner.p2tr(xOnlyPubKey, void 0, network);
13739
- const toSpend = chunkSPDNHPM4_cjs.craftToSpendTx(message, payment.script, TAG_BIP322);
14159
+ const toSpend = chunkFSAXPBGP_cjs.craftToSpendTx(message, payment.script, TAG_BIP322);
13740
14160
  const toSign = craftBIP322ToSignP2TR(toSpend, payment.script, xOnlyPubKey);
13741
14161
  const signed = await identity.sign(toSign, [0]);
13742
14162
  signed.finalizeIdx(0);
@@ -13794,7 +14214,7 @@ function verifyP2TR(message, witnessItems, pkScript, pubkey) {
13794
14214
  if (sighashType !== btcSigner.SigHash.DEFAULT && sighashType !== btcSigner.SigHash.ALL) {
13795
14215
  return false;
13796
14216
  }
13797
- const toSpend = chunkSPDNHPM4_cjs.craftToSpendTx(message, pkScript, TAG_BIP322);
14217
+ const toSpend = chunkFSAXPBGP_cjs.craftToSpendTx(message, pkScript, TAG_BIP322);
13798
14218
  const toSign = craftBIP322ToSignP2TR(toSpend, pkScript, pubkey);
13799
14219
  const sighash = toSign.preimageWitnessV1(0, [pkScript], sighashType, [0n]);
13800
14220
  const rawSig = sig.length === 65 ? sig.subarray(0, 64) : sig;
@@ -13815,7 +14235,7 @@ function verifyP2WPKH(message, witnessItems, pkScript, addressHash) {
13815
14235
  }
13816
14236
  const sighashType = sigWithHash[sigWithHash.length - 1];
13817
14237
  const derSig = sigWithHash.subarray(0, sigWithHash.length - 1);
13818
- const toSpend = chunkSPDNHPM4_cjs.craftToSpendTx(message, pkScript, TAG_BIP322);
14238
+ const toSpend = chunkFSAXPBGP_cjs.craftToSpendTx(message, pkScript, TAG_BIP322);
13819
14239
  const toSign = craftBIP322ToSignSimple(toSpend, pkScript);
13820
14240
  const scriptCode = btcSigner.OutScript.encode({ type: "pkh", hash: addressHash });
13821
14241
  const sighash = toSign.preimageWitnessV0(0, scriptCode, sighashType, 0n);
@@ -13868,7 +14288,7 @@ function encodeCompactSize(n) {
13868
14288
  return buf;
13869
14289
  }
13870
14290
  function craftBIP322ToSignP2TR(toSpend, pkScript, tapInternalKey) {
13871
- const tx = new chunkSPDNHPM4_cjs.Transaction({ version: 0 });
14291
+ const tx = new chunkFSAXPBGP_cjs.Transaction({ version: 0 });
13872
14292
  tx.addInput({
13873
14293
  txid: toSpend.id,
13874
14294
  index: 0,
@@ -13882,12 +14302,12 @@ function craftBIP322ToSignP2TR(toSpend, pkScript, tapInternalKey) {
13882
14302
  });
13883
14303
  tx.addOutput({
13884
14304
  amount: 0n,
13885
- script: chunkSPDNHPM4_cjs.OP_RETURN_EMPTY_PKSCRIPT
14305
+ script: chunkFSAXPBGP_cjs.OP_RETURN_EMPTY_PKSCRIPT
13886
14306
  });
13887
14307
  return tx;
13888
14308
  }
13889
14309
  function craftBIP322ToSignSimple(toSpend, pkScript) {
13890
- const tx = new chunkSPDNHPM4_cjs.Transaction({ version: 0 });
14310
+ const tx = new chunkFSAXPBGP_cjs.Transaction({ version: 0 });
13891
14311
  tx.addInput({
13892
14312
  txid: toSpend.id,
13893
14313
  index: 0,
@@ -13899,7 +14319,7 @@ function craftBIP322ToSignSimple(toSpend, pkScript) {
13899
14319
  });
13900
14320
  tx.addOutput({
13901
14321
  amount: 0n,
13902
- script: chunkSPDNHPM4_cjs.OP_RETURN_EMPTY_PKSCRIPT
14322
+ script: chunkFSAXPBGP_cjs.OP_RETURN_EMPTY_PKSCRIPT
13903
14323
  });
13904
14324
  return tx;
13905
14325
  }
@@ -13960,7 +14380,7 @@ exports.Unroll = void 0;
13960
14380
  if (virtualTxs.txs.length === 0) {
13961
14381
  throw new Error(`Tx ${nextTxToBroadcast.txid} not found`);
13962
14382
  }
13963
- const tx = chunkSPDNHPM4_cjs.Transaction.fromPSBT(base.base64.decode(virtualTxs.txs[0]));
14383
+ const tx = chunkFSAXPBGP_cjs.Transaction.fromPSBT(base.base64.decode(virtualTxs.txs[0]));
13964
14384
  if (nextTxToBroadcast.type === "INDEXER_CHAINED_TX_TYPE_TREE" /* TREE */) {
13965
14385
  const input = tx.getInput(0);
13966
14386
  if (!input) {
@@ -14037,12 +14457,12 @@ async function prepareUnrollTransaction(wallet, vtxoTxIds, outputAddress) {
14037
14457
  if (!exit) {
14038
14458
  throw new Error(`no available exit path found for vtxo ${vtxo.txid}:${vtxo.vout}`);
14039
14459
  }
14040
- 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));
14041
14461
  if (!spendingLeaf) {
14042
14462
  throw new Error(`spending leaf not found for vtxo ${vtxo.txid}:${vtxo.vout}`);
14043
14463
  }
14044
14464
  totalAmount += BigInt(vtxo.value);
14045
- const sequence = chunkWMIPYZSB_cjs.timelockToSequence(exit.params.timelock);
14465
+ const sequence = chunkCMPJR3HS_cjs.timelockToSequence(exit.params.timelock);
14046
14466
  inputs.push({
14047
14467
  txid: vtxo.txid,
14048
14468
  index: vtxo.vout,
@@ -14050,7 +14470,7 @@ async function prepareUnrollTransaction(wallet, vtxoTxIds, outputAddress) {
14050
14470
  sequence,
14051
14471
  witnessUtxo: {
14052
14472
  amount: BigInt(vtxo.value),
14053
- script: chunkWMIPYZSB_cjs.VtxoScript.decode(vtxo.tapTree).pkScript
14473
+ script: chunkCMPJR3HS_cjs.VtxoScript.decode(vtxo.tapTree).pkScript
14054
14474
  },
14055
14475
  sighashType: btcSigner.SigHash.DEFAULT
14056
14476
  });
@@ -14060,7 +14480,7 @@ async function prepareUnrollTransaction(wallet, vtxoTxIds, outputAddress) {
14060
14480
  btcSigner.TaprootControlBlock.encode(spendingLeaf[0]).length
14061
14481
  );
14062
14482
  }
14063
- const tx = new chunkSPDNHPM4_cjs.Transaction({ version: 2 });
14483
+ const tx = new chunkFSAXPBGP_cjs.Transaction({ version: 2 });
14064
14484
  for (const input of inputs) {
14065
14485
  tx.addInput(input);
14066
14486
  }
@@ -14107,7 +14527,7 @@ function doWait(onchainProvider, txid) {
14107
14527
  };
14108
14528
  }
14109
14529
  function availableExitPath(confirmedAt, current, vtxo) {
14110
- const exits = chunkWMIPYZSB_cjs.VtxoScript.decode(vtxo.tapTree).exitPaths();
14530
+ const exits = chunkCMPJR3HS_cjs.VtxoScript.decode(vtxo.tapTree).exitPaths();
14111
14531
  for (const exit of exits) {
14112
14532
  if (exit.params.timelock.type === "blocks") {
14113
14533
  if (current.height >= confirmedAt.height + Number(exit.params.timelock.value)) {
@@ -14146,7 +14566,7 @@ function decodeArkContract(encoded) {
14146
14566
  }
14147
14567
  function contractFromArkContract(encoded, options = {}) {
14148
14568
  const parsed = decodeArkContract(encoded);
14149
- const handler = chunkGYSK5R57_cjs.contractHandlers.get(parsed.type);
14569
+ const handler = chunkGUTKJMSF_cjs.contractHandlers.get(parsed.type);
14150
14570
  if (!handler) {
14151
14571
  throw new Error(`No handler registered for contract type '${parsed.type}'`);
14152
14572
  }
@@ -14160,9 +14580,9 @@ function contractFromArkContract(encoded, options = {}) {
14160
14580
  metadata: options.metadata
14161
14581
  };
14162
14582
  }
14163
- function contractFromArkContractWithAddress(encoded, serverPubKey, addressPrefix = chunkWMIPYZSB_cjs.DEFAULT_NETWORK.hrp, options = {}) {
14583
+ function contractFromArkContractWithAddress(encoded, serverPubKey, addressPrefix = chunkCMPJR3HS_cjs.DEFAULT_NETWORK.hrp, options = {}) {
14164
14584
  const parsed = decodeArkContract(encoded);
14165
- const handler = chunkGYSK5R57_cjs.contractHandlers.getOrThrow(parsed.type);
14585
+ const handler = chunkGUTKJMSF_cjs.contractHandlers.getOrThrow(parsed.type);
14166
14586
  const params = parsed.data;
14167
14587
  const vtxoScript = handler.createScript(params);
14168
14588
  return {
@@ -14274,5 +14694,5 @@ exports.validateVtxoTxGraph = validateVtxoTxGraph;
14274
14694
  exports.verifyTapscriptSignatures = verifyTapscriptSignatures;
14275
14695
  exports.waitForIncomingFunds = waitForIncomingFunds;
14276
14696
  exports.warnAndFilterVtxosForScript = warnAndFilterVtxosForScript;
14277
- //# sourceMappingURL=chunk-7K3ROJF6.cjs.map
14278
- //# sourceMappingURL=chunk-7K3ROJF6.cjs.map
14697
+ //# sourceMappingURL=chunk-XCHBQVMK.cjs.map
14698
+ //# sourceMappingURL=chunk-XCHBQVMK.cjs.map