@arkade-os/sdk 0.4.44 → 0.4.45

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 (68) hide show
  1. package/README.md +35 -0
  2. package/dist/adapters/expo.cjs +4 -4
  3. package/dist/adapters/expo.d.cts +2 -2
  4. package/dist/adapters/expo.d.ts +2 -2
  5. package/dist/adapters/expo.js +2 -2
  6. package/dist/adapters/indexedDB.cjs +3 -3
  7. package/dist/adapters/indexedDB.js +2 -2
  8. package/dist/{ark-I8jfe5VE.d.cts → ark-C-PjOngm.d.cts} +89 -1
  9. package/dist/{ark-I8jfe5VE.d.ts → ark-C-PjOngm.d.ts} +89 -1
  10. package/dist/{asyncStorageTaskQueue-Dap7qUlF.d.cts → asyncStorageTaskQueue-BmBPvTyh.d.cts} +2 -2
  11. package/dist/{asyncStorageTaskQueue-BtSOVZFn.d.ts → asyncStorageTaskQueue-CHpI3moJ.d.ts} +2 -2
  12. package/dist/{chunk-V7WIZR2B.js → chunk-BOA4SHCD.js} +3 -3
  13. package/dist/{chunk-V7WIZR2B.js.map → chunk-BOA4SHCD.js.map} +1 -1
  14. package/dist/{chunk-X37EKDIH.cjs → chunk-HZ7VIN7P.cjs} +11 -11
  15. package/dist/{chunk-X37EKDIH.cjs.map → chunk-HZ7VIN7P.cjs.map} +1 -1
  16. package/dist/{chunk-RJ6XVCX4.cjs → chunk-OFQGANH2.cjs} +7 -7
  17. package/dist/{chunk-RJ6XVCX4.cjs.map → chunk-OFQGANH2.cjs.map} +1 -1
  18. package/dist/{chunk-LCQQPOIT.js → chunk-QZ6HZZZK.js} +3 -3
  19. package/dist/{chunk-LCQQPOIT.js.map → chunk-QZ6HZZZK.js.map} +1 -1
  20. package/dist/{chunk-XIVCG6EP.cjs → chunk-SRCWBFSZ.cjs} +1000 -322
  21. package/dist/chunk-SRCWBFSZ.cjs.map +1 -0
  22. package/dist/{chunk-FMI2GKYO.js → chunk-TGRJ5WAX.js} +919 -243
  23. package/dist/chunk-TGRJ5WAX.js.map +1 -0
  24. package/dist/{chunk-UBYY2TPK.cjs → chunk-UHOHLN3C.cjs} +119 -69
  25. package/dist/chunk-UHOHLN3C.cjs.map +1 -0
  26. package/dist/{chunk-LJ35HPJW.js → chunk-YBQV7XBC.js} +119 -70
  27. package/dist/chunk-YBQV7XBC.js.map +1 -0
  28. package/dist/contracts/handlers/index.d.cts +3 -3
  29. package/dist/contracts/handlers/index.d.ts +3 -3
  30. package/dist/{delegate-CgjVjYOP.d.ts → delegate-BKNqva1j.d.ts} +1 -1
  31. package/dist/{delegate-BRqbh2fW.d.cts → delegate-DOEobYwH.d.cts} +1 -1
  32. package/dist/{index-DHuXlDEg.d.cts → index-BlW4I30l.d.cts} +2 -2
  33. package/dist/{index-DvWNB_rl.d.ts → index-Cm2fGeox.d.ts} +2 -2
  34. package/dist/index.cjs +141 -129
  35. package/dist/index.d.cts +45 -20
  36. package/dist/index.d.ts +45 -20
  37. package/dist/index.js +2 -2
  38. package/dist/repositories/realm/index.cjs +17 -17
  39. package/dist/repositories/realm/index.d.cts +2 -2
  40. package/dist/repositories/realm/index.d.ts +2 -2
  41. package/dist/repositories/realm/index.js +3 -3
  42. package/dist/repositories/sqlite/index.cjs +16 -16
  43. package/dist/repositories/sqlite/index.d.cts +2 -2
  44. package/dist/repositories/sqlite/index.d.ts +2 -2
  45. package/dist/repositories/sqlite/index.js +3 -3
  46. package/dist/{taskRunner-Bptw9UMa.d.ts → taskRunner-BngWSFMi.d.ts} +2 -2
  47. package/dist/{taskRunner-CeFxKhSH.d.cts → taskRunner-DOiyRuJa.d.cts} +2 -2
  48. package/dist/wallet/expo/background.cjs +12 -12
  49. package/dist/wallet/expo/background.d.cts +3 -3
  50. package/dist/wallet/expo/background.d.ts +3 -3
  51. package/dist/wallet/expo/background.js +4 -4
  52. package/dist/wallet/expo/index.cjs +21 -12
  53. package/dist/wallet/expo/index.cjs.map +1 -1
  54. package/dist/wallet/expo/index.d.cts +11 -4
  55. package/dist/wallet/expo/index.d.ts +11 -4
  56. package/dist/wallet/expo/index.js +12 -3
  57. package/dist/wallet/expo/index.js.map +1 -1
  58. package/dist/{wallet-BsqRU8KM.d.cts → wallet-B3awP1Nj.d.ts} +105 -3
  59. package/dist/{wallet-D9z7wssl.d.ts → wallet-DBjumS42.d.cts} +105 -3
  60. package/dist/worker/expo/index.cjs +7 -7
  61. package/dist/worker/expo/index.d.cts +4 -4
  62. package/dist/worker/expo/index.d.ts +4 -4
  63. package/dist/worker/expo/index.js +3 -3
  64. package/package.json +1 -1
  65. package/dist/chunk-FMI2GKYO.js.map +0 -1
  66. package/dist/chunk-LJ35HPJW.js.map +0 -1
  67. package/dist/chunk-UBYY2TPK.cjs.map +0 -1
  68. package/dist/chunk-XIVCG6EP.cjs.map +0 -1
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkUBYY2TPK_cjs = require('./chunk-UBYY2TPK.cjs');
3
+ var chunkUHOHLN3C_cjs = require('./chunk-UHOHLN3C.cjs');
4
4
  var chunk32YKLQPS_cjs = require('./chunk-32YKLQPS.cjs');
5
5
  var chunkHXDZ2QTW_cjs = require('./chunk-HXDZ2QTW.cjs');
6
6
  var utils_js = require('@scure/btc-signer/utils.js');
@@ -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 = chunkUBYY2TPK_cjs.getArkPsbtFields(tx.root, 0, chunkUBYY2TPK_cjs.CosignerPublicKey).map(
184
+ const cosigners = chunkUHOHLN3C_cjs.getArkPsbtFields(tx.root, 0, chunkUHOHLN3C_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 = chunkUBYY2TPK_cjs.getArkPsbtFields(g.root, 0, chunkUBYY2TPK_cjs.CosignerPublicKey).map((c) => c.key);
236
+ const cosigners = chunkUHOHLN3C_cjs.getArkPsbtFields(g.root, 0, chunkUHOHLN3C_cjs.CosignerPublicKey).map((c) => c.key);
237
237
  const { finalKey } = aggregateKeys(cosigners, true, {
238
238
  taprootTweak: this.scriptRoot
239
239
  });
@@ -980,14 +980,14 @@ var RestDelegateProvider = class {
980
980
  */
981
981
  async delegate(intent, forfeitTxs, options) {
982
982
  const url = `${this.url}/v1/delegate`;
983
- const response = await chunkUBYY2TPK_cjs.baseFetch(url, {
983
+ const response = await chunkUHOHLN3C_cjs.baseFetch(url, {
984
984
  method: "POST",
985
985
  headers: {
986
986
  "Content-Type": "application/json"
987
987
  },
988
988
  body: JSON.stringify({
989
989
  intent: {
990
- message: chunkUBYY2TPK_cjs.Intent.encodeMessage(intent.message),
990
+ message: chunkUHOHLN3C_cjs.Intent.encodeMessage(intent.message),
991
991
  proof: intent.proof
992
992
  },
993
993
  forfeit_txs: forfeitTxs,
@@ -1007,7 +1007,7 @@ var RestDelegateProvider = class {
1007
1007
  */
1008
1008
  async getDelegateInfo() {
1009
1009
  const url = `${this.url}/v1/delegator/info`;
1010
- const response = await chunkUBYY2TPK_cjs.baseFetch(url);
1010
+ const response = await chunkUHOHLN3C_cjs.baseFetch(url);
1011
1011
  if (!response.ok) {
1012
1012
  const errorText2 = await response.text();
1013
1013
  throw new Error(`Failed to get delegate info: ${errorText2}`);
@@ -1042,14 +1042,14 @@ var EsploraProvider = class {
1042
1042
  pollingInterval;
1043
1043
  forcePolling;
1044
1044
  async getCoins(address) {
1045
- const response = await chunkUBYY2TPK_cjs.baseFetch(`${this.baseUrl}/address/${address}/utxo`);
1045
+ const response = await chunkUHOHLN3C_cjs.baseFetch(`${this.baseUrl}/address/${address}/utxo`);
1046
1046
  if (!response.ok) {
1047
1047
  throw new Error(`Failed to fetch UTXOs: ${response.statusText}`);
1048
1048
  }
1049
1049
  return response.json();
1050
1050
  }
1051
1051
  async getFeeRate() {
1052
- const response = await chunkUBYY2TPK_cjs.baseFetch(`${this.baseUrl}/fee-estimates`);
1052
+ const response = await chunkUHOHLN3C_cjs.baseFetch(`${this.baseUrl}/fee-estimates`);
1053
1053
  if (response.status === 404) {
1054
1054
  return void 0;
1055
1055
  }
@@ -1070,7 +1070,7 @@ var EsploraProvider = class {
1070
1070
  }
1071
1071
  }
1072
1072
  async getTxOutspends(txid) {
1073
- const response = await chunkUBYY2TPK_cjs.baseFetch(`${this.baseUrl}/tx/${txid}/outspends`);
1073
+ const response = await chunkUHOHLN3C_cjs.baseFetch(`${this.baseUrl}/tx/${txid}/outspends`);
1074
1074
  if (!response.ok) {
1075
1075
  const error = await response.text();
1076
1076
  throw new Error(`Failed to get transaction outspends: ${error}`);
@@ -1078,7 +1078,7 @@ var EsploraProvider = class {
1078
1078
  return response.json();
1079
1079
  }
1080
1080
  async getTransactions(address) {
1081
- const response = await chunkUBYY2TPK_cjs.baseFetch(`${this.baseUrl}/address/${address}/txs`);
1081
+ const response = await chunkUHOHLN3C_cjs.baseFetch(`${this.baseUrl}/address/${address}/txs`);
1082
1082
  if (!response.ok) {
1083
1083
  const error = await response.text();
1084
1084
  throw new Error(`Failed to get transactions: ${error}`);
@@ -1086,7 +1086,7 @@ var EsploraProvider = class {
1086
1086
  return response.json();
1087
1087
  }
1088
1088
  async getTxStatus(txid) {
1089
- const txresponse = await chunkUBYY2TPK_cjs.baseFetch(`${this.baseUrl}/tx/${txid}`);
1089
+ const txresponse = await chunkUHOHLN3C_cjs.baseFetch(`${this.baseUrl}/tx/${txid}`);
1090
1090
  if (!txresponse.ok) {
1091
1091
  throw new Error(txresponse.statusText);
1092
1092
  }
@@ -1094,7 +1094,7 @@ var EsploraProvider = class {
1094
1094
  if (!tx.status.confirmed) {
1095
1095
  return { confirmed: false };
1096
1096
  }
1097
- const response = await chunkUBYY2TPK_cjs.baseFetch(`${this.baseUrl}/tx/${txid}/status`);
1097
+ const response = await chunkUHOHLN3C_cjs.baseFetch(`${this.baseUrl}/tx/${txid}/status`);
1098
1098
  if (!response.ok) {
1099
1099
  throw new Error(`Failed to get transaction status: ${response.statusText}`);
1100
1100
  }
@@ -1178,7 +1178,7 @@ var EsploraProvider = class {
1178
1178
  return stopFunc;
1179
1179
  }
1180
1180
  async getChainTip() {
1181
- const tipBlocks = await chunkUBYY2TPK_cjs.baseFetch(`${this.baseUrl}/blocks`);
1181
+ const tipBlocks = await chunkUHOHLN3C_cjs.baseFetch(`${this.baseUrl}/blocks`);
1182
1182
  if (!tipBlocks.ok) {
1183
1183
  throw new Error(`Failed to get chain tip: ${tipBlocks.statusText}`);
1184
1184
  }
@@ -1197,7 +1197,7 @@ var EsploraProvider = class {
1197
1197
  };
1198
1198
  }
1199
1199
  async broadcastPackage(parent, child) {
1200
- const response = await chunkUBYY2TPK_cjs.baseFetch(`${this.baseUrl}/txs/package`, {
1200
+ const response = await chunkUHOHLN3C_cjs.baseFetch(`${this.baseUrl}/txs/package`, {
1201
1201
  method: "POST",
1202
1202
  headers: {
1203
1203
  "Content-Type": "application/json"
@@ -1211,7 +1211,7 @@ var EsploraProvider = class {
1211
1211
  return response.json();
1212
1212
  }
1213
1213
  async broadcastTx(tx) {
1214
- const response = await chunkUBYY2TPK_cjs.baseFetch(`${this.baseUrl}/tx`, {
1214
+ const response = await chunkUHOHLN3C_cjs.baseFetch(`${this.baseUrl}/tx`, {
1215
1215
  method: "POST",
1216
1216
  headers: {
1217
1217
  "Content-Type": "text/plain"
@@ -1373,7 +1373,7 @@ function findP2AOutput(tx) {
1373
1373
  var CHILD_DUST_AMOUNT = 546;
1374
1374
  function buildAnchorChild(params) {
1375
1375
  const { parent, feeRate, fundingCoins, changeAddress, tapInternalKey, network } = params;
1376
- const child = new chunkUBYY2TPK_cjs.Transaction({ version: 3, allowLegacyWitnessUtxo: true });
1376
+ const child = new chunkUHOHLN3C_cjs.Transaction({ version: 3, allowLegacyWitnessUtxo: true });
1377
1377
  child.addInput(findP2AOutput(parent));
1378
1378
  const estimator = TxWeightEstimator.create().addP2AInput();
1379
1379
  for (const _ of fundingCoins) {
@@ -1421,7 +1421,7 @@ function buildForfeitTx(inputs, forfeitPkScript, txLocktime) {
1421
1421
  );
1422
1422
  }
1423
1423
  function buildForfeitTxWithOutput(inputs, output, txLocktime) {
1424
- const tx = new chunkUBYY2TPK_cjs.Transaction({
1424
+ const tx = new chunkUHOHLN3C_cjs.Transaction({
1425
1425
  version: 3,
1426
1426
  lockTime: txLocktime
1427
1427
  });
@@ -1497,7 +1497,7 @@ function validateVtxoTxGraph(graph, roundTransaction, sweepTapTreeRoot) {
1497
1497
  if (previousScriptKey.length !== 32) {
1498
1498
  throw new Error(`parent output ${childIndex} has invalid script`);
1499
1499
  }
1500
- const cosigners = chunkUBYY2TPK_cjs.getArkPsbtFields(child.root, 0, chunkUBYY2TPK_cjs.CosignerPublicKey);
1500
+ const cosigners = chunkUHOHLN3C_cjs.getArkPsbtFields(child.root, 0, chunkUHOHLN3C_cjs.CosignerPublicKey);
1501
1501
  if (cosigners.length === 0) {
1502
1502
  throw ErrMissingCosignersPublicKeys;
1503
1503
  }
@@ -1597,7 +1597,7 @@ var Extension = class _Extension {
1597
1597
  `expected magic prefix ${base.hex.encode(ARKADE_MAGIC)}, got ${base.hex.encode(payload.slice(0, Math.min(payload.length, ARKADE_MAGIC.length)))}`
1598
1598
  );
1599
1599
  }
1600
- const reader = new chunkUBYY2TPK_cjs.BufferReader(payload.slice(ARKADE_MAGIC.length));
1600
+ const reader = new chunkUHOHLN3C_cjs.BufferReader(payload.slice(ARKADE_MAGIC.length));
1601
1601
  const packets = [];
1602
1602
  while (reader.remaining() > 0) {
1603
1603
  const packetType = reader.readByte();
@@ -1671,7 +1671,7 @@ var Extension = class _Extension {
1671
1671
  */
1672
1672
  getAssetPacket() {
1673
1673
  for (const p of this.packets) {
1674
- if (p instanceof chunkUBYY2TPK_cjs.Packet) {
1674
+ if (p instanceof chunkUHOHLN3C_cjs.Packet) {
1675
1675
  return p;
1676
1676
  }
1677
1677
  }
@@ -1679,8 +1679,8 @@ var Extension = class _Extension {
1679
1679
  }
1680
1680
  };
1681
1681
  function parsePacket(packetType, data) {
1682
- if (packetType === chunkUBYY2TPK_cjs.Packet.PACKET_TYPE) {
1683
- return chunkUBYY2TPK_cjs.Packet.fromBytes(data);
1682
+ if (packetType === chunkUHOHLN3C_cjs.Packet.PACKET_TYPE) {
1683
+ return chunkUHOHLN3C_cjs.Packet.fromBytes(data);
1684
1684
  }
1685
1685
  return new UnknownPacket(packetType, data);
1686
1686
  }
@@ -1987,7 +1987,7 @@ function createAssetPacket(assetInputs, receivers, changeReceiver) {
1987
1987
  const existing = inputsByAssetId.get(asset.assetId);
1988
1988
  inputsByAssetId.set(asset.assetId, [
1989
1989
  ...existing ?? [],
1990
- chunkUBYY2TPK_cjs.AssetInput.create(inputIndex, asset.amount)
1990
+ chunkUHOHLN3C_cjs.AssetInput.create(inputIndex, asset.amount)
1991
1991
  ]);
1992
1992
  }
1993
1993
  }
@@ -1999,7 +1999,7 @@ function createAssetPacket(assetInputs, receivers, changeReceiver) {
1999
1999
  const existing = outputsByAssetId.get(asset.assetId);
2000
2000
  outputsByAssetId.set(asset.assetId, [
2001
2001
  ...existing ?? [],
2002
- chunkUBYY2TPK_cjs.AssetOutput.create(outputIndex, asset.amount)
2002
+ chunkUHOHLN3C_cjs.AssetOutput.create(outputIndex, asset.amount)
2003
2003
  ]);
2004
2004
  }
2005
2005
  }
@@ -2010,7 +2010,7 @@ function createAssetPacket(assetInputs, receivers, changeReceiver) {
2010
2010
  const existing = outputsByAssetId.get(asset.assetId);
2011
2011
  outputsByAssetId.set(asset.assetId, [
2012
2012
  ...existing ?? [],
2013
- chunkUBYY2TPK_cjs.AssetOutput.create(outputIndex, asset.amount)
2013
+ chunkUHOHLN3C_cjs.AssetOutput.create(outputIndex, asset.amount)
2014
2014
  ]);
2015
2015
  }
2016
2016
  }
@@ -2019,11 +2019,11 @@ function createAssetPacket(assetInputs, receivers, changeReceiver) {
2019
2019
  for (const assetIdStr of allAssetIds) {
2020
2020
  const inputs = inputsByAssetId.get(assetIdStr);
2021
2021
  const outputs = outputsByAssetId.get(assetIdStr);
2022
- const assetId = chunkUBYY2TPK_cjs.AssetId.fromString(assetIdStr);
2023
- const group = chunkUBYY2TPK_cjs.AssetGroup.create(assetId, null, inputs ?? [], outputs ?? [], []);
2022
+ const assetId = chunkUHOHLN3C_cjs.AssetId.fromString(assetIdStr);
2023
+ const group = chunkUHOHLN3C_cjs.AssetGroup.create(assetId, null, inputs ?? [], outputs ?? [], []);
2024
2024
  groups.push(group);
2025
2025
  }
2026
- return chunkUBYY2TPK_cjs.Packet.create(groups);
2026
+ return chunkUHOHLN3C_cjs.Packet.create(groups);
2027
2027
  }
2028
2028
  function selectCoinsWithAsset(coins, assetId, requiredAmount) {
2029
2029
  const coinsWithAsset = coins.filter((coin) => coin.assets?.some((a) => a.assetId === assetId));
@@ -2140,7 +2140,7 @@ function buildVirtualTx(inputs, outputs) {
2140
2140
  }
2141
2141
  }
2142
2142
  }
2143
- const tx = new chunkUBYY2TPK_cjs.Transaction({
2143
+ const tx = new chunkUHOHLN3C_cjs.Transaction({
2144
2144
  version: 3,
2145
2145
  lockTime: Number(lockTime)
2146
2146
  });
@@ -2155,7 +2155,7 @@ function buildVirtualTx(inputs, outputs) {
2155
2155
  },
2156
2156
  tapLeafScript: [input.tapLeafScript]
2157
2157
  });
2158
- chunkUBYY2TPK_cjs.setArkPsbtField(tx, i, chunkUBYY2TPK_cjs.VtxoTaprootTree, input.tapTree);
2158
+ chunkUHOHLN3C_cjs.setArkPsbtField(tx, i, chunkUHOHLN3C_cjs.VtxoTaprootTree, input.tapTree);
2159
2159
  }
2160
2160
  for (const output of outputs) {
2161
2161
  tx.addOutput(output);
@@ -3157,7 +3157,7 @@ var VtxoManager = class _VtxoManager {
3157
3157
  `Sweep not economical: output ${outputAmount} sats after ${fee} sats fee is below dust (${dustAmount} sats)`
3158
3158
  );
3159
3159
  }
3160
- const tx = new chunkUBYY2TPK_cjs.Transaction();
3160
+ const tx = new chunkUHOHLN3C_cjs.Transaction();
3161
3161
  for (const utxo of expiredUtxos) {
3162
3162
  const utxoScript = chunkHXDZ2QTW_cjs.VtxoScript.decode(utxo.tapTree);
3163
3163
  const utxoExitLeaf = utxoScript.leaves.find(
@@ -3796,7 +3796,7 @@ var VtxoManager = class _VtxoManager {
3796
3796
  * or doesn't carry the metadata.
3797
3797
  */
3798
3798
  extractSpentOutpoint(error) {
3799
- const ark = chunkUBYY2TPK_cjs.maybeArkError(error);
3799
+ const ark = chunkUHOHLN3C_cjs.maybeArkError(error);
3800
3800
  if (!ark || ark.name !== "VTXO_ALREADY_SPENT") return void 0;
3801
3801
  const raw = ark.metadata?.vtxo_outpoint;
3802
3802
  if (typeof raw !== "string") return void 0;
@@ -4309,6 +4309,592 @@ function wrapHandlerWithIntentPersistence(base, deps) {
4309
4309
  }
4310
4310
  };
4311
4311
  }
4312
+
4313
+ // src/repositories/virtualTxRepository.ts
4314
+ var ChainedTxType = /* @__PURE__ */ ((ChainedTxType2) => {
4315
+ ChainedTxType2[ChainedTxType2["Unspecified"] = 0] = "Unspecified";
4316
+ ChainedTxType2[ChainedTxType2["Commitment"] = 1] = "Commitment";
4317
+ ChainedTxType2[ChainedTxType2["Ark"] = 2] = "Ark";
4318
+ ChainedTxType2[ChainedTxType2["Tree"] = 3] = "Tree";
4319
+ ChainedTxType2[ChainedTxType2["Checkpoint"] = 4] = "Checkpoint";
4320
+ return ChainedTxType2;
4321
+ })(ChainedTxType || {});
4322
+ function mergeChainedTxType(incoming, prev) {
4323
+ if (incoming !== 0 /* Unspecified */) return incoming;
4324
+ return prev ?? 0 /* Unspecified */;
4325
+ }
4326
+
4327
+ // src/wallet/exit/chain.ts
4328
+ var isCommitment = (t) => t === "INDEXER_CHAINED_TX_TYPE_COMMITMENT" /* COMMITMENT */ || t === "INDEXER_CHAINED_TX_TYPE_UNSPECIFIED" /* UNSPECIFIED */;
4329
+ async function buildExitDag(params) {
4330
+ const byTxid = /* @__PURE__ */ new Map();
4331
+ for (const vtxo of params.vtxos) {
4332
+ const outpoint = `${vtxo.txid}:${vtxo.vout}`;
4333
+ const chain = await params.chain.getVtxoChain({ txid: vtxo.txid, vout: vtxo.vout });
4334
+ for (const chainTx of chain) {
4335
+ const existing = byTxid.get(chainTx.txid);
4336
+ if (existing) {
4337
+ existing.forVtxos.add(outpoint);
4338
+ } else {
4339
+ byTxid.set(chainTx.txid, { ...chainTx, forVtxos: /* @__PURE__ */ new Set([outpoint]) });
4340
+ }
4341
+ }
4342
+ }
4343
+ const pending = new Map(
4344
+ [...byTxid.values()].filter((tx) => !isCommitment(tx.type)).map((tx) => [tx.txid, tx])
4345
+ );
4346
+ const inDegree = /* @__PURE__ */ new Map();
4347
+ for (const tx of pending.values()) {
4348
+ const parents = tx.spends.filter((p) => pending.has(p));
4349
+ inDegree.set(tx.txid, parents.length);
4350
+ }
4351
+ const order = [];
4352
+ const queue = [...pending.values()].filter((tx) => inDegree.get(tx.txid) === 0).sort((a, b) => a.txid.localeCompare(b.txid));
4353
+ while (queue.length > 0) {
4354
+ const tx = queue.shift();
4355
+ order.push(tx);
4356
+ const children = [...pending.values()].filter((c) => c.spends.includes(tx.txid)).sort((a, b) => a.txid.localeCompare(b.txid));
4357
+ for (const child of children) {
4358
+ const deg = inDegree.get(child.txid) - 1;
4359
+ inDegree.set(child.txid, deg);
4360
+ if (deg === 0) queue.push(child);
4361
+ }
4362
+ }
4363
+ if (order.length !== pending.size) {
4364
+ throw new Error("inconsistent vtxo chain from indexer (cycle detected)");
4365
+ }
4366
+ const nodes = [];
4367
+ for (const tx of order) {
4368
+ let confirmed = false;
4369
+ try {
4370
+ const status = await params.onchain.getTxStatus(tx.txid);
4371
+ confirmed = status.confirmed;
4372
+ } catch {
4373
+ confirmed = false;
4374
+ }
4375
+ const expires = Number(tx.expiresAt);
4376
+ nodes.push({
4377
+ txid: tx.txid,
4378
+ type: tx.type,
4379
+ expiresAt: Number.isFinite(expires) && expires > 0 ? expires : void 0,
4380
+ forVtxos: [...tx.forVtxos].sort(),
4381
+ confirmed
4382
+ });
4383
+ }
4384
+ return nodes;
4385
+ }
4386
+ function topoSortByDeps(items, idOf, depsOf) {
4387
+ const produced = new Set(items.map(idOf));
4388
+ const emitted = /* @__PURE__ */ new Set();
4389
+ const ordered = [];
4390
+ let remaining = items;
4391
+ while (remaining.length > 0) {
4392
+ const next = [];
4393
+ let progress = false;
4394
+ for (const item of remaining) {
4395
+ if (depsOf(item).every((d) => !produced.has(d) || emitted.has(d))) {
4396
+ ordered.push(item);
4397
+ emitted.add(idOf(item));
4398
+ progress = true;
4399
+ } else {
4400
+ next.push(item);
4401
+ }
4402
+ }
4403
+ if (!progress) {
4404
+ throw new Error("topological sort: cycle or unsatisfiable dependency");
4405
+ }
4406
+ remaining = next;
4407
+ }
4408
+ return ordered;
4409
+ }
4410
+
4411
+ // src/wallet/exit/capture.ts
4412
+ var DEFAULT_MIN_EXIT_WORTH_SATS = 1e3;
4413
+ var DEFAULT_EXIT_CAPTURE_MODE = "lite";
4414
+ function chainTxTypeToChainedExit(t) {
4415
+ switch (t) {
4416
+ case "INDEXER_CHAINED_TX_TYPE_COMMITMENT" /* COMMITMENT */:
4417
+ return 1 /* Commitment */;
4418
+ case "INDEXER_CHAINED_TX_TYPE_ARK" /* ARK */:
4419
+ return 2 /* Ark */;
4420
+ case "INDEXER_CHAINED_TX_TYPE_TREE" /* TREE */:
4421
+ return 3 /* Tree */;
4422
+ case "INDEXER_CHAINED_TX_TYPE_CHECKPOINT" /* CHECKPOINT */:
4423
+ return 4 /* Checkpoint */;
4424
+ default:
4425
+ return 0 /* Unspecified */;
4426
+ }
4427
+ }
4428
+ function orderAncestryFirst(chain) {
4429
+ const ids = new Set(chain.map((c) => c.txid));
4430
+ return topoSortByDeps(
4431
+ chain,
4432
+ (c) => c.txid,
4433
+ (c) => c.spends.filter((s) => ids.has(s))
4434
+ );
4435
+ }
4436
+ async function captureExitBranch(params) {
4437
+ const { resolver, repository, vtxo, value, mode, minExitWorthSats } = params;
4438
+ if (value < minExitWorthSats) return;
4439
+ if (await repository.hasBranch(vtxo)) return;
4440
+ const ordered = orderAncestryFirst(await resolver.getVtxoChain(vtxo));
4441
+ const psbtByTxid = /* @__PURE__ */ new Map();
4442
+ if (mode === "full") {
4443
+ const nonCommitment = ordered.filter((c) => chainTxTypeToChainedExit(c.type) !== 1 /* Commitment */).map((c) => c.txid);
4444
+ if (nonCommitment.length > 0) {
4445
+ for (const psbt of await resolver.getVirtualTxs(nonCommitment)) {
4446
+ psbtByTxid.set(chunkUHOHLN3C_cjs.Transaction.fromPSBT(base.base64.decode(psbt)).id, psbt);
4447
+ }
4448
+ }
4449
+ }
4450
+ const virtualTxs = ordered.map((c) => {
4451
+ const expires = Number(c.expiresAt);
4452
+ return {
4453
+ txid: c.txid,
4454
+ psbt: psbtByTxid.get(c.txid) ?? null,
4455
+ expiresAt: Number.isFinite(expires) && expires > 0 ? expires : null,
4456
+ type: chainTxTypeToChainedExit(c.type)
4457
+ };
4458
+ });
4459
+ const branch = ordered.map((c, i) => ({
4460
+ vtxoTxid: vtxo.txid,
4461
+ vtxoVout: vtxo.vout,
4462
+ virtualTxid: c.txid,
4463
+ position: i
4464
+ }));
4465
+ await repository.upsertVirtualTxs(virtualTxs);
4466
+ await repository.setBranch(vtxo, branch);
4467
+ }
4468
+ async function pruneExitBranches(repository, outpoints) {
4469
+ for (const outpoint of outpoints) {
4470
+ try {
4471
+ await repository.pruneForSpentVtxo(outpoint);
4472
+ } catch {
4473
+ }
4474
+ }
4475
+ }
4476
+ var IndexerExitDataSource = class {
4477
+ constructor(indexer) {
4478
+ this.indexer = indexer;
4479
+ }
4480
+ name = "indexer";
4481
+ async getVtxoChain(vtxo) {
4482
+ const chain = [];
4483
+ let pageIndex = 0;
4484
+ let hasMore = true;
4485
+ while (hasMore) {
4486
+ const { chain: page, page: meta } = await this.indexer.getVtxoChain(
4487
+ { txid: vtxo.txid, vout: vtxo.vout },
4488
+ { pageIndex, pageSize: chunk32YKLQPS_cjs.DEFAULT_PAGE_SIZE }
4489
+ );
4490
+ chain.push(...page);
4491
+ hasMore = meta ? page.length === chunk32YKLQPS_cjs.DEFAULT_PAGE_SIZE : false;
4492
+ pageIndex++;
4493
+ }
4494
+ return chain;
4495
+ }
4496
+ async getVirtualTxs(txids) {
4497
+ const out = /* @__PURE__ */ new Map();
4498
+ let pageIndex = 0;
4499
+ let hasMore = true;
4500
+ while (hasMore) {
4501
+ const { txs, page } = await this.indexer.getVirtualTxs(txids, {
4502
+ pageIndex,
4503
+ pageSize: chunk32YKLQPS_cjs.DEFAULT_PAGE_SIZE
4504
+ });
4505
+ for (const psbt of txs) {
4506
+ out.set(chunkUHOHLN3C_cjs.Transaction.fromPSBT(base.base64.decode(psbt)).id, psbt);
4507
+ }
4508
+ hasMore = page ? txs.length === chunk32YKLQPS_cjs.DEFAULT_PAGE_SIZE : false;
4509
+ pageIndex++;
4510
+ }
4511
+ return out;
4512
+ }
4513
+ };
4514
+ function chainedTxTypeToChainTxType(t) {
4515
+ switch (t) {
4516
+ case 1 /* Commitment */:
4517
+ return "INDEXER_CHAINED_TX_TYPE_COMMITMENT" /* COMMITMENT */;
4518
+ case 2 /* Ark */:
4519
+ return "INDEXER_CHAINED_TX_TYPE_ARK" /* ARK */;
4520
+ case 3 /* Tree */:
4521
+ return "INDEXER_CHAINED_TX_TYPE_TREE" /* TREE */;
4522
+ case 4 /* Checkpoint */:
4523
+ return "INDEXER_CHAINED_TX_TYPE_CHECKPOINT" /* CHECKPOINT */;
4524
+ default:
4525
+ return "INDEXER_CHAINED_TX_TYPE_UNSPECIFIED" /* UNSPECIFIED */;
4526
+ }
4527
+ }
4528
+ function psbtInputTxids(psbtBase64) {
4529
+ const tx = chunkUHOHLN3C_cjs.Transaction.fromPSBT(base.base64.decode(psbtBase64));
4530
+ const ids = [];
4531
+ for (let i = 0; i < tx.inputsLength; i++) {
4532
+ const txid = tx.getInput(i).txid;
4533
+ if (txid) ids.push(base.hex.encode(txid));
4534
+ }
4535
+ return ids;
4536
+ }
4537
+ var RepositoryExitDataSource = class {
4538
+ constructor(repo) {
4539
+ this.repo = repo;
4540
+ }
4541
+ name = "repository";
4542
+ async getVtxoChain(vtxo) {
4543
+ const branch = await this.repo.getBranch(vtxo);
4544
+ if (branch.length === 0) return null;
4545
+ const chain = [];
4546
+ for (const v of branch) {
4547
+ const type = chainedTxTypeToChainTxType(v.type);
4548
+ let spends = [];
4549
+ if (v.type !== 1 /* Commitment */) {
4550
+ if (!v.psbt) return null;
4551
+ spends = psbtInputTxids(v.psbt);
4552
+ }
4553
+ chain.push({
4554
+ txid: v.txid,
4555
+ type,
4556
+ expiresAt: v.expiresAt != null ? String(v.expiresAt) : "",
4557
+ spends
4558
+ });
4559
+ }
4560
+ return chain;
4561
+ }
4562
+ async getVirtualTxs(txids) {
4563
+ const out = /* @__PURE__ */ new Map();
4564
+ for (const txid of txids) {
4565
+ const stored = await this.repo.getVirtualTx(txid);
4566
+ if (stored?.psbt) out.set(txid, stored.psbt);
4567
+ }
4568
+ return out;
4569
+ }
4570
+ };
4571
+
4572
+ // src/wallet/exit/resolver.ts
4573
+ var OrderedExitChainResolver = class {
4574
+ constructor(sources, persist) {
4575
+ this.sources = sources;
4576
+ this.persist = persist;
4577
+ }
4578
+ async getVtxoChain(vtxo) {
4579
+ let lastErr;
4580
+ for (const source of this.sources) {
4581
+ try {
4582
+ const chain = await source.getVtxoChain(vtxo);
4583
+ if (chain) return chain;
4584
+ } catch (e) {
4585
+ lastErr = e;
4586
+ }
4587
+ }
4588
+ if (lastErr) throw lastErr;
4589
+ throw new Error(`no exit-data source resolved the chain for ${vtxo.txid}:${vtxo.vout}`);
4590
+ }
4591
+ async getVirtualTxs(txids) {
4592
+ const found = /* @__PURE__ */ new Map();
4593
+ let remaining = txids;
4594
+ for (const [i, source] of this.sources.entries()) {
4595
+ if (remaining.length === 0) break;
4596
+ let got;
4597
+ try {
4598
+ got = await source.getVirtualTxs(remaining);
4599
+ } catch {
4600
+ continue;
4601
+ }
4602
+ const fresh = [];
4603
+ for (const [txid, psbt] of got) {
4604
+ if (found.has(txid)) continue;
4605
+ found.set(txid, psbt);
4606
+ fresh.push({ txid, psbt, expiresAt: null, type: 0 /* Unspecified */ });
4607
+ }
4608
+ if (i > 0 && this.persist && fresh.length > 0) {
4609
+ try {
4610
+ await this.persist.upsertVirtualTxs(fresh);
4611
+ } catch {
4612
+ }
4613
+ }
4614
+ remaining = txids.filter((t) => !found.has(t));
4615
+ }
4616
+ return [...found.values()];
4617
+ }
4618
+ };
4619
+ function createExitChainResolver(params) {
4620
+ const sources = [];
4621
+ if (params.repository) sources.push(new RepositoryExitDataSource(params.repository));
4622
+ if (params.extraSources) sources.push(...params.extraSources);
4623
+ sources.push(new IndexerExitDataSource(params.indexer));
4624
+ return new OrderedExitChainResolver(sources, params.repository);
4625
+ }
4626
+
4627
+ // src/providers/availability.ts
4628
+ function isRetryableProviderError(error) {
4629
+ return error instanceof chunkUHOHLN3C_cjs.ProviderUnavailableError || error instanceof chunkUHOHLN3C_cjs.FetchError || chunkUHOHLN3C_cjs.isFetchTimeoutError(error);
4630
+ }
4631
+
4632
+ // src/utils/syncCursors.ts
4633
+ var SAFETY_LAG_MS = 3e4;
4634
+ var OVERLAP_MS = 24 * 60 * 60 * 1e3;
4635
+ var walletStateLocks = /* @__PURE__ */ new WeakMap();
4636
+ async function updateWalletState(repo, updater) {
4637
+ const prev = walletStateLocks.get(repo) ?? Promise.resolve();
4638
+ const op = prev.then(async () => {
4639
+ const state = await repo.getWalletState() ?? {};
4640
+ await repo.saveWalletState(updater(state));
4641
+ });
4642
+ walletStateLocks.set(
4643
+ repo,
4644
+ op.catch(() => {
4645
+ })
4646
+ );
4647
+ return op;
4648
+ }
4649
+ var CURSOR_MIGRATED_KEY = "vtxoCursorMigrated";
4650
+ function hasMigrationMarker(state) {
4651
+ return state?.settings?.[CURSOR_MIGRATED_KEY] === true;
4652
+ }
4653
+ async function getSyncCursor(repo) {
4654
+ const state = await repo.getWalletState();
4655
+ if (!hasMigrationMarker(state)) return 0;
4656
+ return state?.lastSyncTime ?? 0;
4657
+ }
4658
+ async function advanceSyncCursor(repo, lastUpdatedAt) {
4659
+ await updateWalletState(repo, (state) => {
4660
+ const current = hasMigrationMarker(state) ? state.lastSyncTime ?? 0 : 0;
4661
+ return {
4662
+ ...state,
4663
+ lastSyncTime: Math.max(current, lastUpdatedAt),
4664
+ settings: {
4665
+ ...state.settings ?? {},
4666
+ [CURSOR_MIGRATED_KEY]: true
4667
+ }
4668
+ };
4669
+ });
4670
+ }
4671
+ async function clearSyncCursor(repo) {
4672
+ await updateWalletState(repo, (state) => {
4673
+ const { [CURSOR_MIGRATED_KEY]: _, ...restSettings } = state.settings ?? {};
4674
+ return {
4675
+ ...state,
4676
+ lastSyncTime: void 0,
4677
+ settings: restSettings
4678
+ };
4679
+ });
4680
+ }
4681
+ function computeSyncWindow(cursor) {
4682
+ const after = Math.max(0, cursor - OVERLAP_MS);
4683
+ return { after };
4684
+ }
4685
+ function cursorCutoff(requestStartedAt) {
4686
+ return (requestStartedAt ?? Date.now()) - SAFETY_LAG_MS;
4687
+ }
4688
+
4689
+ // src/wallet/arkInfoSnapshot.ts
4690
+ var ARK_INFO_SNAPSHOT_KEY = "arkInfoSnapshot";
4691
+ var MalformedArkInfoSnapshotError = class extends Error {
4692
+ constructor(message, options) {
4693
+ super(message, { cause: options?.cause });
4694
+ this.name = "MalformedArkInfoSnapshotError";
4695
+ }
4696
+ };
4697
+ var CURRENT_VERSION = 1;
4698
+ function serializeArkInfoSnapshot(info, savedAt) {
4699
+ return {
4700
+ version: CURRENT_VERSION,
4701
+ savedAt,
4702
+ source: "arkade.getInfo",
4703
+ arkInfo: {
4704
+ network: info.network,
4705
+ signerPubkey: info.signerPubkey,
4706
+ checkpointTapscript: info.checkpointTapscript,
4707
+ forfeitAddress: info.forfeitAddress,
4708
+ forfeitPubkey: info.forfeitPubkey,
4709
+ unilateralExitDelay: info.unilateralExitDelay.toString(),
4710
+ boardingExitDelay: info.boardingExitDelay.toString(),
4711
+ sessionDuration: info.sessionDuration.toString(),
4712
+ dust: info.dust.toString(),
4713
+ fees: info.fees,
4714
+ digest: info.digest,
4715
+ version: info.version,
4716
+ vtxoMinAmount: info.vtxoMinAmount.toString(),
4717
+ vtxoMaxAmount: info.vtxoMaxAmount.toString(),
4718
+ utxoMinAmount: info.utxoMinAmount.toString(),
4719
+ utxoMaxAmount: info.utxoMaxAmount.toString(),
4720
+ deprecatedSigners: info.deprecatedSigners.map((s) => ({
4721
+ pubkey: s.pubkey,
4722
+ cutoffDate: s.cutoffDate.toString()
4723
+ })),
4724
+ scheduledSession: info.scheduledSession ? {
4725
+ duration: info.scheduledSession.duration.toString(),
4726
+ fees: info.scheduledSession.fees,
4727
+ nextEndTime: info.scheduledSession.nextEndTime.toString(),
4728
+ nextStartTime: info.scheduledSession.nextStartTime.toString(),
4729
+ period: info.scheduledSession.period.toString()
4730
+ } : void 0
4731
+ }
4732
+ };
4733
+ }
4734
+ function hydrateArkInfo(snapshot) {
4735
+ const a = snapshot.arkInfo;
4736
+ return {
4737
+ boardingExitDelay: BigInt(a.boardingExitDelay),
4738
+ checkpointTapscript: a.checkpointTapscript,
4739
+ deprecatedSigners: a.deprecatedSigners.map((s) => ({
4740
+ cutoffDate: BigInt(s.cutoffDate),
4741
+ pubkey: s.pubkey
4742
+ })),
4743
+ digest: a.digest,
4744
+ dust: BigInt(a.dust),
4745
+ fees: a.fees,
4746
+ forfeitAddress: a.forfeitAddress,
4747
+ forfeitPubkey: a.forfeitPubkey,
4748
+ network: a.network,
4749
+ scheduledSession: a.scheduledSession ? {
4750
+ duration: BigInt(a.scheduledSession.duration),
4751
+ fees: a.scheduledSession.fees,
4752
+ nextEndTime: BigInt(a.scheduledSession.nextEndTime),
4753
+ nextStartTime: BigInt(a.scheduledSession.nextStartTime),
4754
+ period: BigInt(a.scheduledSession.period)
4755
+ } : void 0,
4756
+ serviceStatus: {},
4757
+ sessionDuration: BigInt(a.sessionDuration),
4758
+ signerPubkey: a.signerPubkey,
4759
+ unilateralExitDelay: BigInt(a.unilateralExitDelay),
4760
+ utxoMaxAmount: BigInt(a.utxoMaxAmount),
4761
+ utxoMinAmount: BigInt(a.utxoMinAmount),
4762
+ version: a.version,
4763
+ vtxoMaxAmount: BigInt(a.vtxoMaxAmount),
4764
+ vtxoMinAmount: BigInt(a.vtxoMinAmount)
4765
+ };
4766
+ }
4767
+ var DECIMAL_STRING = /^-?\d+$/;
4768
+ function assertString(value, path) {
4769
+ if (typeof value !== "string") {
4770
+ throw new MalformedArkInfoSnapshotError(`${path} must be a string`);
4771
+ }
4772
+ }
4773
+ function assertDecimalString(value, path) {
4774
+ assertString(value, path);
4775
+ if (!DECIMAL_STRING.test(value)) {
4776
+ throw new MalformedArkInfoSnapshotError(`${path} must be a decimal integer string`);
4777
+ }
4778
+ }
4779
+ function assertFeeInfo(value, path) {
4780
+ if (typeof value !== "object" || value === null) {
4781
+ throw new MalformedArkInfoSnapshotError(`${path} must be an object`);
4782
+ }
4783
+ const fees = value;
4784
+ assertString(fees.txFeeRate, `${path}.txFeeRate`);
4785
+ if (typeof fees.intentFee !== "object" || fees.intentFee === null) {
4786
+ throw new MalformedArkInfoSnapshotError(`${path}.intentFee must be an object`);
4787
+ }
4788
+ }
4789
+ function parseStoredArkInfoSnapshot(raw) {
4790
+ if (typeof raw !== "object" || raw === null) {
4791
+ throw new MalformedArkInfoSnapshotError("snapshot must be an object");
4792
+ }
4793
+ const snap = raw;
4794
+ if (snap.version !== CURRENT_VERSION) {
4795
+ throw new MalformedArkInfoSnapshotError(
4796
+ `unsupported snapshot version: ${String(snap.version)}`
4797
+ );
4798
+ }
4799
+ if (typeof snap.savedAt !== "number") {
4800
+ throw new MalformedArkInfoSnapshotError("savedAt must be a number");
4801
+ }
4802
+ if (snap.source !== "arkade.getInfo") {
4803
+ throw new MalformedArkInfoSnapshotError(`unexpected source: ${String(snap.source)}`);
4804
+ }
4805
+ if (typeof snap.arkInfo !== "object" || snap.arkInfo === null) {
4806
+ throw new MalformedArkInfoSnapshotError("arkInfo must be an object");
4807
+ }
4808
+ const a = snap.arkInfo;
4809
+ for (const field of [
4810
+ "network",
4811
+ "signerPubkey",
4812
+ "checkpointTapscript",
4813
+ "forfeitAddress",
4814
+ "forfeitPubkey",
4815
+ "digest",
4816
+ "version"
4817
+ ]) {
4818
+ assertString(a[field], `arkInfo.${field}`);
4819
+ }
4820
+ for (const field of [
4821
+ "unilateralExitDelay",
4822
+ "boardingExitDelay",
4823
+ "sessionDuration",
4824
+ "dust",
4825
+ "vtxoMinAmount",
4826
+ "vtxoMaxAmount",
4827
+ "utxoMinAmount",
4828
+ "utxoMaxAmount"
4829
+ ]) {
4830
+ assertDecimalString(a[field], `arkInfo.${field}`);
4831
+ }
4832
+ assertFeeInfo(a.fees, "arkInfo.fees");
4833
+ if (!Array.isArray(a.deprecatedSigners)) {
4834
+ throw new MalformedArkInfoSnapshotError("arkInfo.deprecatedSigners must be an array");
4835
+ }
4836
+ a.deprecatedSigners.forEach((s, i) => {
4837
+ if (typeof s !== "object" || s === null) {
4838
+ throw new MalformedArkInfoSnapshotError(
4839
+ `arkInfo.deprecatedSigners[${i}] must be an object`
4840
+ );
4841
+ }
4842
+ const signer = s;
4843
+ assertString(signer.pubkey, `arkInfo.deprecatedSigners[${i}].pubkey`);
4844
+ assertDecimalString(signer.cutoffDate, `arkInfo.deprecatedSigners[${i}].cutoffDate`);
4845
+ });
4846
+ if (a.scheduledSession !== void 0) {
4847
+ if (typeof a.scheduledSession !== "object" || a.scheduledSession === null) {
4848
+ throw new MalformedArkInfoSnapshotError("arkInfo.scheduledSession must be an object");
4849
+ }
4850
+ const s = a.scheduledSession;
4851
+ for (const field of ["duration", "nextEndTime", "nextStartTime", "period"]) {
4852
+ assertDecimalString(s[field], `arkInfo.scheduledSession.${field}`);
4853
+ }
4854
+ assertFeeInfo(s.fees, "arkInfo.scheduledSession.fees");
4855
+ }
4856
+ return raw;
4857
+ }
4858
+ async function loadArkInfoSnapshot(repo) {
4859
+ const state = await repo.getWalletState();
4860
+ const raw = state?.settings?.[ARK_INFO_SNAPSHOT_KEY];
4861
+ if (raw === void 0 || raw === null) return null;
4862
+ return parseStoredArkInfoSnapshot(raw);
4863
+ }
4864
+ async function saveArkInfoSnapshot(repo, info, savedAt) {
4865
+ const snapshot = serializeArkInfoSnapshot(info, savedAt);
4866
+ await updateWalletState(repo, (state) => ({
4867
+ ...state,
4868
+ settings: {
4869
+ ...state.settings ?? {},
4870
+ [ARK_INFO_SNAPSHOT_KEY]: snapshot
4871
+ }
4872
+ }));
4873
+ }
4874
+ async function resolveArkInfo(arkProvider, walletRepository) {
4875
+ let info;
4876
+ try {
4877
+ info = await arkProvider.getInfo();
4878
+ } catch (err) {
4879
+ if (!isRetryableProviderError(err)) throw err;
4880
+ const snapshot = await loadArkInfoSnapshot(walletRepository);
4881
+ if (!snapshot) {
4882
+ throw new chunkUHOHLN3C_cjs.ProviderUnavailableError(
4883
+ "Arkade server info is unavailable and no cached snapshot exists",
4884
+ { cause: err }
4885
+ );
4886
+ }
4887
+ return { info: hydrateArkInfo(snapshot), source: "cache", lastOnlineAt: snapshot.savedAt };
4888
+ }
4889
+ return { info, source: "live" };
4890
+ }
4891
+ async function saveValidatedArkInfoSnapshot(repo, info, savedAt) {
4892
+ try {
4893
+ await saveArkInfoSnapshot(repo, info, savedAt);
4894
+ } catch (err) {
4895
+ console.warn("Failed to persist Ark info snapshot", err);
4896
+ }
4897
+ }
4312
4898
  var TxTree = class {
4313
4899
  constructor(root, children = /* @__PURE__ */ new Map()) {
4314
4900
  this.root = root;
@@ -4824,7 +5410,7 @@ var AssetManager = class extends ReadonlyAssetManager {
4824
5410
  const virtualCoins = await this.wallet.getVtxos({
4825
5411
  withRecoverable: false
4826
5412
  });
4827
- const controlAssetRef = params.controlAssetId ? chunkUBYY2TPK_cjs.AssetRef.fromId(chunkUBYY2TPK_cjs.AssetId.fromString(params.controlAssetId)) : null;
5413
+ const controlAssetRef = params.controlAssetId ? chunkUHOHLN3C_cjs.AssetRef.fromId(chunkUHOHLN3C_cjs.AssetId.fromString(params.controlAssetId)) : null;
4828
5414
  const coinSelection = selectVirtualCoins(virtualCoins, Number(this.wallet.dustAmount));
4829
5415
  let totalBtcSelected = 0n;
4830
5416
  const assetChanges = /* @__PURE__ */ new Map();
@@ -4837,8 +5423,8 @@ var AssetManager = class extends ReadonlyAssetManager {
4837
5423
  }
4838
5424
  }
4839
5425
  const groups = [];
4840
- const issuedAssetOutput = chunkUBYY2TPK_cjs.AssetOutput.create(0, params.amount);
4841
- const issuedAssetGroup = chunkUBYY2TPK_cjs.AssetGroup.create(
5426
+ const issuedAssetOutput = chunkUHOHLN3C_cjs.AssetOutput.create(0, params.amount);
5427
+ const issuedAssetGroup = chunkUHOHLN3C_cjs.AssetGroup.create(
4842
5428
  null,
4843
5429
  controlAssetRef,
4844
5430
  [],
@@ -4853,15 +5439,15 @@ var AssetManager = class extends ReadonlyAssetManager {
4853
5439
  for (const [inputIndex, assets] of assetInputs) {
4854
5440
  for (const asset of assets) {
4855
5441
  if (asset.assetId !== assetId) continue;
4856
- changeInputs.push(chunkUBYY2TPK_cjs.AssetInput.create(inputIndex, asset.amount));
5442
+ changeInputs.push(chunkUHOHLN3C_cjs.AssetInput.create(inputIndex, asset.amount));
4857
5443
  }
4858
5444
  }
4859
5445
  groups.push(
4860
- chunkUBYY2TPK_cjs.AssetGroup.create(
4861
- chunkUBYY2TPK_cjs.AssetId.fromString(assetId),
5446
+ chunkUHOHLN3C_cjs.AssetGroup.create(
5447
+ chunkUHOHLN3C_cjs.AssetId.fromString(assetId),
4862
5448
  null,
4863
5449
  changeInputs,
4864
- [chunkUBYY2TPK_cjs.AssetOutput.create(0, amount)],
5450
+ [chunkUHOHLN3C_cjs.AssetOutput.create(0, amount)],
4865
5451
  []
4866
5452
  )
4867
5453
  );
@@ -4874,7 +5460,7 @@ var AssetManager = class extends ReadonlyAssetManager {
4874
5460
  script: outputAddress.pkScript,
4875
5461
  amount: BigInt(totalBtcSelected)
4876
5462
  },
4877
- Extension.create([chunkUBYY2TPK_cjs.Packet.create(groups)]).txOut()
5463
+ Extension.create([chunkUHOHLN3C_cjs.Packet.create(groups)]).txOut()
4878
5464
  ];
4879
5465
  const { arkTxid } = await this.wallet.buildAndSubmitOffchainTx(
4880
5466
  coinSelection.inputs,
@@ -4882,7 +5468,7 @@ var AssetManager = class extends ReadonlyAssetManager {
4882
5468
  );
4883
5469
  return {
4884
5470
  arkTxId: arkTxid,
4885
- assetId: chunkUBYY2TPK_cjs.AssetId.create(arkTxid, 0).toString()
5471
+ assetId: chunkUHOHLN3C_cjs.AssetId.create(arkTxid, 0).toString()
4886
5472
  };
4887
5473
  }
4888
5474
  /**
@@ -4954,16 +5540,16 @@ var AssetManager = class extends ReadonlyAssetManager {
4954
5540
  for (const [inputIndex, assets] of assetInputs) {
4955
5541
  for (const asset of assets) {
4956
5542
  if (asset.assetId !== params.assetId) continue;
4957
- reissueInputs.push(chunkUBYY2TPK_cjs.AssetInput.create(inputIndex, asset.amount));
5543
+ reissueInputs.push(chunkUHOHLN3C_cjs.AssetInput.create(inputIndex, asset.amount));
4958
5544
  }
4959
5545
  }
4960
5546
  const totalAssetAmount = assetToReissueAmount + params.amount;
4961
- const reissueAssetIdObj = chunkUBYY2TPK_cjs.AssetId.fromString(params.assetId);
4962
- const reissueAssetGroup = chunkUBYY2TPK_cjs.AssetGroup.create(
5547
+ const reissueAssetIdObj = chunkUHOHLN3C_cjs.AssetId.fromString(params.assetId);
5548
+ const reissueAssetGroup = chunkUHOHLN3C_cjs.AssetGroup.create(
4963
5549
  reissueAssetIdObj,
4964
5550
  null,
4965
5551
  reissueInputs,
4966
- [chunkUBYY2TPK_cjs.AssetOutput.create(0, totalAssetAmount)],
5552
+ [chunkUHOHLN3C_cjs.AssetOutput.create(0, totalAssetAmount)],
4967
5553
  []
4968
5554
  );
4969
5555
  const groups = [reissueAssetGroup];
@@ -4972,15 +5558,15 @@ var AssetManager = class extends ReadonlyAssetManager {
4972
5558
  for (const [inputIndex, assets] of assetInputs) {
4973
5559
  for (const asset of assets) {
4974
5560
  if (asset.assetId !== assetId) continue;
4975
- changeInputs.push(chunkUBYY2TPK_cjs.AssetInput.create(inputIndex, asset.amount));
5561
+ changeInputs.push(chunkUHOHLN3C_cjs.AssetInput.create(inputIndex, asset.amount));
4976
5562
  }
4977
5563
  }
4978
5564
  groups.push(
4979
- chunkUBYY2TPK_cjs.AssetGroup.create(
4980
- chunkUBYY2TPK_cjs.AssetId.fromString(assetId),
5565
+ chunkUHOHLN3C_cjs.AssetGroup.create(
5566
+ chunkUHOHLN3C_cjs.AssetId.fromString(assetId),
4981
5567
  null,
4982
5568
  changeInputs,
4983
- [chunkUBYY2TPK_cjs.AssetOutput.create(0, amount)],
5569
+ [chunkUHOHLN3C_cjs.AssetOutput.create(0, amount)],
4984
5570
  []
4985
5571
  )
4986
5572
  );
@@ -4992,7 +5578,7 @@ var AssetManager = class extends ReadonlyAssetManager {
4992
5578
  script: outputAddress.pkScript,
4993
5579
  amount: BigInt(totalBtcSelected)
4994
5580
  },
4995
- Extension.create([chunkUBYY2TPK_cjs.Packet.create(groups)]).txOut()
5581
+ Extension.create([chunkUHOHLN3C_cjs.Packet.create(groups)]).txOut()
4996
5582
  ];
4997
5583
  const { arkTxid } = await this.wallet.buildAndSubmitOffchainTx(selectedCoins, outputs);
4998
5584
  return arkTxid;
@@ -5059,15 +5645,15 @@ var AssetManager = class extends ReadonlyAssetManager {
5059
5645
  for (const [inputIndex, assets] of assetInputs) {
5060
5646
  for (const asset of assets) {
5061
5647
  if (asset.assetId !== assetId) continue;
5062
- changeInputs.push(chunkUBYY2TPK_cjs.AssetInput.create(inputIndex, asset.amount));
5648
+ changeInputs.push(chunkUHOHLN3C_cjs.AssetInput.create(inputIndex, asset.amount));
5063
5649
  }
5064
5650
  }
5065
5651
  groups.push(
5066
- chunkUBYY2TPK_cjs.AssetGroup.create(
5067
- chunkUBYY2TPK_cjs.AssetId.fromString(assetId),
5652
+ chunkUHOHLN3C_cjs.AssetGroup.create(
5653
+ chunkUHOHLN3C_cjs.AssetId.fromString(assetId),
5068
5654
  null,
5069
5655
  changeInputs,
5070
- amount > 0n ? [chunkUBYY2TPK_cjs.AssetOutput.create(0, amount)] : [],
5656
+ amount > 0n ? [chunkUHOHLN3C_cjs.AssetOutput.create(0, amount)] : [],
5071
5657
  []
5072
5658
  )
5073
5659
  );
@@ -5079,7 +5665,7 @@ var AssetManager = class extends ReadonlyAssetManager {
5079
5665
  script: outputAddress.pkScript,
5080
5666
  amount: BigInt(totalBtcSelected)
5081
5667
  },
5082
- Extension.create([chunkUBYY2TPK_cjs.Packet.create(groups)]).txOut()
5668
+ Extension.create([chunkUHOHLN3C_cjs.Packet.create(groups)]).txOut()
5083
5669
  ];
5084
5670
  const { arkTxid } = await this.wallet.buildAndSubmitOffchainTx(selectedCoins, outputs);
5085
5671
  return arkTxid;
@@ -5104,7 +5690,7 @@ function castMetadata(metadata) {
5104
5690
  } else {
5105
5691
  throw new Error("Invalid metadata value type");
5106
5692
  }
5107
- md.push(chunkUBYY2TPK_cjs.Metadata.create(textEncoder.encode(key), valueBytes));
5693
+ md.push(chunkUHOHLN3C_cjs.Metadata.create(textEncoder.encode(key), valueBytes));
5108
5694
  }
5109
5695
  return md;
5110
5696
  }
@@ -5389,7 +5975,7 @@ async function makeSignedDelegateIntent(identity, coins, outputs, onchainOutputs
5389
5975
  expire_at: 0,
5390
5976
  cosigners_public_keys: cosignerPubKeys
5391
5977
  };
5392
- const proof = chunkUBYY2TPK_cjs.Intent.create(message, coins, outputs);
5978
+ const proof = chunkUHOHLN3C_cjs.Intent.create(message, coins, outputs);
5393
5979
  const signedProof = await identity.sign(proof);
5394
5980
  return {
5395
5981
  proof: base.base64.encode(signedProof.toPSBT()),
@@ -5418,20 +6004,6 @@ function isAnnotated(v) {
5418
6004
  return v.tapTree !== void 0 && v.forfeitTapLeafScript !== void 0 && v.intentTapLeafScript !== void 0;
5419
6005
  }
5420
6006
 
5421
- // src/repositories/virtualTxRepository.ts
5422
- var ChainedTxType = /* @__PURE__ */ ((ChainedTxType2) => {
5423
- ChainedTxType2[ChainedTxType2["Unspecified"] = 0] = "Unspecified";
5424
- ChainedTxType2[ChainedTxType2["Commitment"] = 1] = "Commitment";
5425
- ChainedTxType2[ChainedTxType2["Ark"] = 2] = "Ark";
5426
- ChainedTxType2[ChainedTxType2["Tree"] = 3] = "Tree";
5427
- ChainedTxType2[ChainedTxType2["Checkpoint"] = 4] = "Checkpoint";
5428
- return ChainedTxType2;
5429
- })(ChainedTxType || {});
5430
- function mergeChainedTxType(incoming, prev) {
5431
- if (incoming !== 0 /* Unspecified */) return incoming;
5432
- return prev ?? 0 /* Unspecified */;
5433
- }
5434
-
5435
6007
  // src/repositories/inMemory/intentRepository.ts
5436
6008
  var InMemoryIntentRepository = class {
5437
6009
  version = 1;
@@ -7487,7 +8059,7 @@ var ContractWatcher = class {
7487
8059
  this.connectionState = "connected";
7488
8060
  this.reconnectAttempts = 0;
7489
8061
  this.listenLoop().catch((e) => {
7490
- if (chunkUBYY2TPK_cjs.isEventSourceError(e)) {
8062
+ if (chunkUHOHLN3C_cjs.isEventSourceError(e)) {
7491
8063
  console.debug("ContractWatcher subscription disconnected; reconnecting");
7492
8064
  } else {
7493
8065
  console.error(e);
@@ -7806,106 +8378,49 @@ async function reconcileIntents(deps) {
7806
8378
  console.error("reconcileIntents: failed to read non-terminal intents", e);
7807
8379
  return;
7808
8380
  }
7809
- if (intents.length === 0) return;
7810
- const outpoints = dedupeOutpoints(intents.flatMap((i) => i.intentVtxos));
7811
- let vtxosByOutpoint = /* @__PURE__ */ new Map();
7812
- if (outpoints.length > 0) {
7813
- try {
7814
- const { vtxos } = await deps.indexerProvider.getVtxos({ outpoints });
7815
- vtxosByOutpoint = new Map(vtxos.map((v) => [outpointKey(v), v]));
7816
- } catch (e) {
7817
- console.error("reconcileIntents: failed to fetch input VTXO state", e);
7818
- return;
7819
- }
7820
- }
7821
- const nowMs = now();
7822
- for (const intent of intents) {
7823
- try {
7824
- const next = await classifyIntent(intent, vtxosByOutpoint, nowMs);
7825
- if (!next) continue;
7826
- const [fresh] = await deps.intentRepository.getIntents({
7827
- intentTxIds: [intent.intentTxId]
7828
- });
7829
- if (!fresh || fresh.state !== intent.state) continue;
7830
- await deps.intentRepository.saveIntent(next);
7831
- } catch (e) {
7832
- console.error(`reconcileIntents: failed to reconcile intent ${intent.intentTxId}`, e);
7833
- }
7834
- }
7835
- }
7836
- function terminal(intent, state, now, patch) {
7837
- return { ...intent, ...patch, state, updatedAt: now };
7838
- }
7839
- function outpointKey(o) {
7840
- return `${o.txid}:${o.vout}`;
7841
- }
7842
- function dedupeOutpoints(outpoints) {
7843
- const seen = /* @__PURE__ */ new Set();
7844
- const out = [];
7845
- for (const o of outpoints) {
7846
- const k = outpointKey(o);
7847
- if (seen.has(k)) continue;
7848
- seen.add(k);
7849
- out.push(o);
7850
- }
7851
- return out;
7852
- }
7853
-
7854
- // src/utils/syncCursors.ts
7855
- var SAFETY_LAG_MS = 3e4;
7856
- var OVERLAP_MS = 24 * 60 * 60 * 1e3;
7857
- var walletStateLocks = /* @__PURE__ */ new WeakMap();
7858
- async function updateWalletState(repo, updater) {
7859
- const prev = walletStateLocks.get(repo) ?? Promise.resolve();
7860
- const op = prev.then(async () => {
7861
- const state = await repo.getWalletState() ?? {};
7862
- await repo.saveWalletState(updater(state));
7863
- });
7864
- walletStateLocks.set(
7865
- repo,
7866
- op.catch(() => {
7867
- })
7868
- );
7869
- return op;
7870
- }
7871
- var CURSOR_MIGRATED_KEY = "vtxoCursorMigrated";
7872
- function hasMigrationMarker(state) {
7873
- return state?.settings?.[CURSOR_MIGRATED_KEY] === true;
7874
- }
7875
- async function getSyncCursor(repo) {
7876
- const state = await repo.getWalletState();
7877
- if (!hasMigrationMarker(state)) return 0;
7878
- return state?.lastSyncTime ?? 0;
7879
- }
7880
- async function advanceSyncCursor(repo, lastUpdatedAt) {
7881
- await updateWalletState(repo, (state) => {
7882
- const current = hasMigrationMarker(state) ? state.lastSyncTime ?? 0 : 0;
7883
- return {
7884
- ...state,
7885
- lastSyncTime: Math.max(current, lastUpdatedAt),
7886
- settings: {
7887
- ...state.settings ?? {},
7888
- [CURSOR_MIGRATED_KEY]: true
7889
- }
7890
- };
7891
- });
8381
+ if (intents.length === 0) return;
8382
+ const outpoints = dedupeOutpoints(intents.flatMap((i) => i.intentVtxos));
8383
+ let vtxosByOutpoint = /* @__PURE__ */ new Map();
8384
+ if (outpoints.length > 0) {
8385
+ try {
8386
+ const { vtxos } = await deps.indexerProvider.getVtxos({ outpoints });
8387
+ vtxosByOutpoint = new Map(vtxos.map((v) => [outpointKey(v), v]));
8388
+ } catch (e) {
8389
+ console.error("reconcileIntents: failed to fetch input VTXO state", e);
8390
+ return;
8391
+ }
8392
+ }
8393
+ const nowMs = now();
8394
+ for (const intent of intents) {
8395
+ try {
8396
+ const next = await classifyIntent(intent, vtxosByOutpoint, nowMs);
8397
+ if (!next) continue;
8398
+ const [fresh] = await deps.intentRepository.getIntents({
8399
+ intentTxIds: [intent.intentTxId]
8400
+ });
8401
+ if (!fresh || fresh.state !== intent.state) continue;
8402
+ await deps.intentRepository.saveIntent(next);
8403
+ } catch (e) {
8404
+ console.error(`reconcileIntents: failed to reconcile intent ${intent.intentTxId}`, e);
8405
+ }
8406
+ }
7892
8407
  }
7893
- async function clearSyncCursor(repo) {
7894
- await updateWalletState(repo, (state) => {
7895
- const { [CURSOR_MIGRATED_KEY]: _, ...restSettings } = state.settings ?? {};
7896
- return {
7897
- ...state,
7898
- lastSyncTime: void 0,
7899
- settings: restSettings
7900
- };
7901
- });
8408
+ function terminal(intent, state, now, patch) {
8409
+ return { ...intent, ...patch, state, updatedAt: now };
7902
8410
  }
7903
- function computeSyncWindow(cursor) {
7904
- const after = Math.max(0, cursor - OVERLAP_MS);
7905
- return { after };
8411
+ function outpointKey(o) {
8412
+ return `${o.txid}:${o.vout}`;
7906
8413
  }
7907
- function cursorCutoff(requestStartedAt) {
7908
- return (requestStartedAt ?? Date.now()) - SAFETY_LAG_MS;
8414
+ function dedupeOutpoints(outpoints) {
8415
+ const seen = /* @__PURE__ */ new Set();
8416
+ const out = [];
8417
+ for (const o of outpoints) {
8418
+ const k = outpointKey(o);
8419
+ if (seen.has(k)) continue;
8420
+ seen.add(k);
8421
+ out.push(o);
8422
+ }
8423
+ return out;
7909
8424
  }
7910
8425
 
7911
8426
  // src/contracts/contractManager.ts
@@ -7920,6 +8435,10 @@ var ContractManager = class _ContractManager {
7920
8435
  initialized = false;
7921
8436
  eventCallbacks = /* @__PURE__ */ new Set();
7922
8437
  stopWatcherFn;
8438
+ /** `undefined` while online; the failure reason once a sync degrades. */
8439
+ syncDegradedReason;
8440
+ /** Epoch-ms of the last successful provider sync, if any. */
8441
+ lastSyncedAt;
7923
8442
  constructor(config) {
7924
8443
  this.config = config;
7925
8444
  this.watcher = new ContractWatcher({
@@ -7942,6 +8461,26 @@ var ContractManager = class _ContractManager {
7942
8461
  await cm.initialize();
7943
8462
  return cm;
7944
8463
  }
8464
+ /**
8465
+ * Latest provider-sync health. See {@link ContractSyncState}. Degradation is
8466
+ * recorded by {@link initialize}, {@link getContractsWithVtxos}, and
8467
+ * {@link createContract}; it flips back to `online` on the next successful
8468
+ * sync. Purely a freshness signal — not a source of truth for wallet data.
8469
+ */
8470
+ getSyncState() {
8471
+ return this.syncDegradedReason === void 0 ? { mode: "online", lastSyncedAt: this.lastSyncedAt } : {
8472
+ mode: "degraded",
8473
+ reason: this.syncDegradedReason,
8474
+ lastSyncedAt: this.lastSyncedAt
8475
+ };
8476
+ }
8477
+ markSyncOnline() {
8478
+ this.syncDegradedReason = void 0;
8479
+ this.lastSyncedAt = Date.now();
8480
+ }
8481
+ markSyncDegraded(err) {
8482
+ this.syncDegradedReason = err instanceof Error ? err.message : String(err);
8483
+ }
7945
8484
  async initialize() {
7946
8485
  if (this.initialized) {
7947
8486
  return;
@@ -7950,7 +8489,13 @@ var ContractManager = class _ContractManager {
7950
8489
  for (const contract of contracts) {
7951
8490
  await this.watcher.addContract(contract);
7952
8491
  }
7953
- await this.reconcileWatched();
8492
+ try {
8493
+ await this.reconcileWatched();
8494
+ this.markSyncOnline();
8495
+ } catch (err) {
8496
+ if (!isRetryableProviderError(err)) throw err;
8497
+ this.markSyncDegraded(err);
8498
+ }
7954
8499
  this.initialized = true;
7955
8500
  this.stopWatcherFn = await this.watcher.startWatching((event) => {
7956
8501
  this.handleContractEvent(event).catch((error) => {
@@ -8004,7 +8549,13 @@ var ContractManager = class _ContractManager {
8004
8549
  async createContract(params) {
8005
8550
  const { contract, persisted } = await this.upsertContract(params);
8006
8551
  if (persisted) {
8007
- await this.fetchContractVxosFromIndexer([contract]);
8552
+ try {
8553
+ await this.fetchContractVxosFromIndexer([contract]);
8554
+ this.markSyncOnline();
8555
+ } catch (err) {
8556
+ if (!isRetryableProviderError(err)) throw err;
8557
+ this.markSyncDegraded(err);
8558
+ }
8008
8559
  await this.watcher.addContract(contract);
8009
8560
  }
8010
8561
  return contract;
@@ -8203,7 +8754,13 @@ var ContractManager = class _ContractManager {
8203
8754
  }
8204
8755
  async getContractsWithVtxos(filter, pageSize) {
8205
8756
  const contracts = await this.getContracts(filter);
8206
- await this.syncContracts({ contracts, pageSize });
8757
+ try {
8758
+ await this.syncContracts({ contracts, pageSize });
8759
+ this.markSyncOnline();
8760
+ } catch (err) {
8761
+ if (!isRetryableProviderError(err)) throw err;
8762
+ this.markSyncDegraded(err);
8763
+ }
8207
8764
  const vtxos = await this.getVtxosForContracts(contracts);
8208
8765
  return contracts.map((contract) => ({
8209
8766
  contract,
@@ -8441,15 +8998,33 @@ var ContractManager = class _ContractManager {
8441
8998
  * Handle events from the watcher.
8442
8999
  */
8443
9000
  async handleContractEvent(event) {
8444
- switch (event.type) {
8445
- // Delta-sync only the changed virtual outputs for this contract.
8446
- case "vtxo_received":
8447
- case "vtxo_spent":
8448
- await this.syncContracts({ contracts: [event.contract] });
8449
- break;
8450
- case "connection_reset":
8451
- await this.reconcileWatched();
8452
- break;
9001
+ try {
9002
+ switch (event.type) {
9003
+ // Delta-sync only the changed virtual outputs for this contract.
9004
+ case "vtxo_received":
9005
+ await this.syncContracts({ contracts: [event.contract] });
9006
+ this.markSyncOnline();
9007
+ break;
9008
+ case "vtxo_spent":
9009
+ await this.syncContracts({ contracts: [event.contract] });
9010
+ this.markSyncOnline();
9011
+ if (this.config.onVtxosSpent) {
9012
+ try {
9013
+ await this.config.onVtxosSpent(
9014
+ event.vtxos.map((v) => ({ txid: v.txid, vout: v.vout }))
9015
+ );
9016
+ } catch {
9017
+ }
9018
+ }
9019
+ break;
9020
+ case "connection_reset":
9021
+ await this.reconcileWatched();
9022
+ this.markSyncOnline();
9023
+ break;
9024
+ }
9025
+ } catch (err) {
9026
+ if (!isRetryableProviderError(err)) throw err;
9027
+ this.markSyncDegraded(err);
8453
9028
  }
8454
9029
  this.emitEvent(event);
8455
9030
  }
@@ -8531,6 +9106,12 @@ var ContractManager = class _ContractManager {
8531
9106
  contract,
8532
9107
  filtered
8533
9108
  );
9109
+ if (this.config.onVtxosPersisted) {
9110
+ try {
9111
+ await this.config.onVtxosPersisted(contract, filtered);
9112
+ } catch {
9113
+ }
9114
+ }
8534
9115
  }
8535
9116
  }
8536
9117
  async fetchContractVxosFromIndexer(contracts, pageSize, syncWindow) {
@@ -8551,6 +9132,15 @@ var ContractManager = class _ContractManager {
8551
9132
  contract,
8552
9133
  filtered
8553
9134
  );
9135
+ if (this.config.onVtxosPersisted) {
9136
+ try {
9137
+ await this.config.onVtxosPersisted(
9138
+ contract,
9139
+ filtered
9140
+ );
9141
+ } catch {
9142
+ }
9143
+ }
8554
9144
  }
8555
9145
  }
8556
9146
  return result;
@@ -9424,6 +10014,8 @@ var ReadonlyWallet = class _ReadonlyWallet {
9424
10014
  * (ContractManager isn't given it); `undefined` ⇒ no-op.
9425
10015
  */
9426
10016
  virtualTxRepository;
10017
+ /** Opt-in exit-data capture settings; see {@link StorageConfig.exitDataCapture}. */
10018
+ exitDataCapture;
9427
10019
  _assetManager;
9428
10020
  walletContractTimelocks;
9429
10021
  // Outpoints ("txid:vout") committed to an in-flight settle/send. Filtered
@@ -9466,6 +10058,72 @@ var ReadonlyWallet = class _ReadonlyWallet {
9466
10058
  * construction-time snapshot for their lifetime.
9467
10059
  */
9468
10060
  _arkServerPublicKey;
10061
+ /**
10062
+ * Whether this wallet was constructed from live operator server-info
10063
+ * (`"live"`) or from a cached snapshot because the operator was unreachable
10064
+ * (`"cache"`). Freshness signal for {@link getProviderConnectionState}.
10065
+ */
10066
+ _serverInfoSource = "live";
10067
+ /**
10068
+ * Epoch-ms of the last known live operator contact: construction time on the
10069
+ * `live` boot path, the cached snapshot's `savedAt` on the `cache` path.
10070
+ */
10071
+ _serverInfoLastOnlineAt;
10072
+ /** @see {@link _serverInfoSource} */
10073
+ get serverInfoSource() {
10074
+ return this._serverInfoSource;
10075
+ }
10076
+ /**
10077
+ * Composed provider-connection freshness: the boot server-info source
10078
+ * (Arkade) combined with the contract-manager's indexer-sync health, if the
10079
+ * manager has been initialized. Reads no live provider state — it never
10080
+ * forces a `ContractManager` to construct — so it is safe for readonly
10081
+ * callers that only use address/balance APIs.
10082
+ *
10083
+ * - Boot fell back to a cached snapshot → degraded on `arkade` (`cache`).
10084
+ * - Otherwise, if the contract manager has degraded to repository data →
10085
+ * degraded on `indexer` (`repository`).
10086
+ * - Otherwise online.
10087
+ *
10088
+ * This only describes sync freshness; wallet balances/VTXOs are always read
10089
+ * from the repository regardless of this state.
10090
+ */
10091
+ getProviderConnectionState() {
10092
+ if (this._serverInfoSource === "cache") {
10093
+ return {
10094
+ mode: "degraded",
10095
+ source: "cache",
10096
+ provider: "arkade",
10097
+ reason: "constructed from cached server-info; operator was unreachable at boot",
10098
+ lastOnlineAt: this._serverInfoLastOnlineAt
10099
+ };
10100
+ }
10101
+ const sync = this._contractManager?.getSyncState();
10102
+ if (sync?.mode === "degraded") {
10103
+ return {
10104
+ mode: "degraded",
10105
+ source: "repository",
10106
+ provider: "indexer",
10107
+ reason: sync.reason,
10108
+ lastOnlineAt: sync.lastSyncedAt ?? this._serverInfoLastOnlineAt
10109
+ };
10110
+ }
10111
+ return {
10112
+ mode: "online",
10113
+ source: "live",
10114
+ lastOnlineAt: sync?.lastSyncedAt ?? this._serverInfoLastOnlineAt ?? 0
10115
+ };
10116
+ }
10117
+ /**
10118
+ * The contract-manager's current provider-sync health **without forcing it
10119
+ * to initialize** — reads the already-constructed manager, or reports
10120
+ * `online` when none exists yet. Unlike {@link getContractManager}, this
10121
+ * never triggers a remote sync, so it is safe on a pure diagnostics path
10122
+ * (e.g. the service-worker sync-state message).
10123
+ */
10124
+ getContractSyncState() {
10125
+ return this._contractManager?.getSyncState() ?? { mode: "online" };
10126
+ }
9469
10127
  /**
9470
10128
  * x-only hex of the operator's deprecated signer keys (from
9471
10129
  * `ArkInfo.deprecatedSigners`), cached for the OFFLINE read/watch paths.
@@ -9581,7 +10239,7 @@ var ReadonlyWallet = class _ReadonlyWallet {
9581
10239
  */
9582
10240
  static async setupWalletConfig(config, pubKey) {
9583
10241
  const arkadeServerUrl = getArkadeServerUrl(config);
9584
- const arkProvider = config.arkProvider || new chunkUBYY2TPK_cjs.RestArkProvider(arkadeServerUrl);
10242
+ const arkProvider = config.arkProvider || new chunkUHOHLN3C_cjs.RestArkProvider(arkadeServerUrl);
9585
10243
  let indexerProvider = config.indexerProvider;
9586
10244
  if (!indexerProvider) {
9587
10245
  let indexerUrl = config.indexerUrl;
@@ -9598,9 +10256,15 @@ var ReadonlyWallet = class _ReadonlyWallet {
9598
10256
  indexerUrl = arkadeServerUrl;
9599
10257
  }
9600
10258
  }
9601
- indexerProvider = new chunkUBYY2TPK_cjs.RestIndexerProvider(indexerUrl);
10259
+ indexerProvider = new chunkUHOHLN3C_cjs.RestIndexerProvider(indexerUrl);
9602
10260
  }
9603
- const info = await arkProvider.getInfo();
10261
+ const walletRepository = config.storage?.walletRepository ?? new IndexedDBWalletRepository();
10262
+ const contractRepository = config.storage?.contractRepository ?? new IndexedDBContractRepository();
10263
+ const {
10264
+ info,
10265
+ source: serverInfoSource,
10266
+ lastOnlineAt: serverInfoLastOnlineAt
10267
+ } = await resolveArkInfo(arkProvider, walletRepository);
9604
10268
  const network = chunkHXDZ2QTW_cjs.getNetwork(info.network);
9605
10269
  if ("descriptor" in config.identity) {
9606
10270
  const descriptor = config.identity.descriptor;
@@ -9654,8 +10318,6 @@ var ReadonlyWallet = class _ReadonlyWallet {
9654
10318
  serverPubKey: base.hex.encode(serverPubKey),
9655
10319
  csvTimelock: chunkHXDZ2QTW_cjs.timelockToSequence(boardingTimelock).toString()
9656
10320
  });
9657
- const walletRepository = config.storage?.walletRepository ?? new IndexedDBWalletRepository();
9658
- const contractRepository = config.storage?.contractRepository ?? new IndexedDBContractRepository();
9659
10321
  return {
9660
10322
  arkProvider,
9661
10323
  indexerProvider,
@@ -9669,6 +10331,8 @@ var ReadonlyWallet = class _ReadonlyWallet {
9669
10331
  walletRepository,
9670
10332
  contractRepository,
9671
10333
  info,
10334
+ serverInfoSource,
10335
+ serverInfoLastOnlineAt,
9672
10336
  delegateProvider: config.delegateProvider || config.delegatorProvider,
9673
10337
  /** @deprecated alias for `delegateProvider` */
9674
10338
  delegatorProvider: config.delegateProvider || config.delegatorProvider,
@@ -9704,6 +10368,15 @@ var ReadonlyWallet = class _ReadonlyWallet {
9704
10368
  );
9705
10369
  wallet.intentRepository = config.storage?.intentRepository;
9706
10370
  wallet.virtualTxRepository = config.storage?.virtualTxRepository;
10371
+ wallet.exitDataCapture = config.storage?.exitDataCapture;
10372
+ wallet._serverInfoSource = setup.serverInfoSource;
10373
+ if (setup.serverInfoSource === "live") {
10374
+ const now = Date.now();
10375
+ await saveValidatedArkInfoSnapshot(setup.walletRepository, setup.info, now);
10376
+ wallet._serverInfoLastOnlineAt = now;
10377
+ } else {
10378
+ wallet._serverInfoLastOnlineAt = setup.serverInfoLastOnlineAt;
10379
+ }
9707
10380
  wallet.refreshDeprecatedSigners(setup.info);
9708
10381
  return wallet;
9709
10382
  }
@@ -9834,7 +10507,10 @@ var ReadonlyWallet = class _ReadonlyWallet {
9834
10507
  const response = await contractManager.getContractsWithVtxos();
9835
10508
  const allVtxos = response.flatMap((_) => _.vtxos);
9836
10509
  const { boardingTxs, commitmentsToIgnore } = await this.getBoardingTxs();
9837
- const getTxCreatedAt = (txid) => this.indexerProvider.getVtxos({ outpoints: [{ txid, vout: 0 }] }).then((res) => res.vtxos[0]?.createdAt.getTime());
10510
+ const getTxCreatedAt = (txid) => this.indexerProvider.getVtxos({ outpoints: [{ txid, vout: 0 }] }).then((res) => res.vtxos[0]?.createdAt.getTime()).catch((err) => {
10511
+ if (isRetryableProviderError(err)) return void 0;
10512
+ throw err;
10513
+ });
9838
10514
  return buildTransactionHistory(allVtxos, boardingTxs, commitmentsToIgnore, getTxCreatedAt);
9839
10515
  }
9840
10516
  /**
@@ -10253,11 +10929,39 @@ var ReadonlyWallet = class _ReadonlyWallet {
10253
10929
  }
10254
10930
  }
10255
10931
  async initializeContractManager() {
10932
+ const virtualTxRepository = this.virtualTxRepository;
10933
+ let onVtxosPersisted;
10934
+ let onVtxosSpent;
10935
+ if (virtualTxRepository) {
10936
+ const capture = this.exitDataCapture;
10937
+ const resolver = createExitChainResolver({
10938
+ indexer: this.indexerProvider,
10939
+ repository: virtualTxRepository,
10940
+ extraSources: capture?.sources
10941
+ });
10942
+ onVtxosPersisted = async (_contract, vtxos) => {
10943
+ for (const v of vtxos) {
10944
+ if (v.virtualStatus.state === "spent") continue;
10945
+ await captureExitBranch({
10946
+ resolver,
10947
+ repository: virtualTxRepository,
10948
+ vtxo: { txid: v.txid, vout: v.vout },
10949
+ value: v.value,
10950
+ mode: capture?.mode ?? DEFAULT_EXIT_CAPTURE_MODE,
10951
+ minExitWorthSats: capture?.minExitWorthSats ?? DEFAULT_MIN_EXIT_WORTH_SATS
10952
+ }).catch(() => {
10953
+ });
10954
+ }
10955
+ };
10956
+ onVtxosSpent = (vtxos) => pruneExitBranches(virtualTxRepository, vtxos);
10957
+ }
10256
10958
  const manager = await ContractManager.create({
10257
10959
  indexerProvider: this.indexerProvider,
10258
10960
  contractRepository: this.contractRepository,
10259
10961
  walletRepository: this.walletRepository,
10260
10962
  intentRepository: this.intentRepository,
10963
+ onVtxosPersisted,
10964
+ onVtxosSpent,
10261
10965
  watcherConfig: this.watcherConfig
10262
10966
  });
10263
10967
  const baselinePubkey = await this.identity.xOnlyPublicKey();
@@ -10932,6 +11636,14 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
10932
11636
  boot?.rotator,
10933
11637
  boot?.provider
10934
11638
  );
11639
+ wallet._serverInfoSource = setup.serverInfoSource;
11640
+ if (setup.serverInfoSource === "live") {
11641
+ const now = Date.now();
11642
+ await saveValidatedArkInfoSnapshot(setup.walletRepository, setup.info, now);
11643
+ wallet._serverInfoLastOnlineAt = now;
11644
+ } else {
11645
+ wallet._serverInfoLastOnlineAt = setup.serverInfoLastOnlineAt;
11646
+ }
10935
11647
  wallet.refreshDeprecatedSigners(setup.info);
10936
11648
  {
10937
11649
  const ap = setup.arkProvider;
@@ -10953,6 +11665,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
10953
11665
  }
10954
11666
  wallet.intentRepository = config.storage?.intentRepository;
10955
11667
  wallet.virtualTxRepository = config.storage?.virtualTxRepository;
11668
+ wallet.exitDataCapture = config.storage?.exitDataCapture;
10956
11669
  await wallet.getVtxoManager();
10957
11670
  return wallet;
10958
11671
  }
@@ -11613,9 +12326,9 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
11613
12326
  ...existing ?? {},
11614
12327
  intentTxId,
11615
12328
  registerProof: intent.proof,
11616
- registerProofMessage: chunkUBYY2TPK_cjs.Intent.encodeMessage(intent.message),
12329
+ registerProofMessage: chunkUHOHLN3C_cjs.Intent.encodeMessage(intent.message),
11617
12330
  deleteProof: deleteIntent.proof,
11618
- deleteProofMessage: chunkUBYY2TPK_cjs.Intent.encodeMessage(deleteIntent.message),
12331
+ deleteProofMessage: chunkUHOHLN3C_cjs.Intent.encodeMessage(deleteIntent.message),
11619
12332
  intentVtxos: inputs.map((i) => ({
11620
12333
  txid: i.txid,
11621
12334
  vout: i.vout
@@ -11647,7 +12360,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
11647
12360
  try {
11648
12361
  return await this.arkProvider.registerIntent(intent);
11649
12362
  } catch (error) {
11650
- if (error instanceof chunkUBYY2TPK_cjs.ArkError && error.code === 0 && error.message.includes("duplicated input")) {
12363
+ if (error instanceof chunkUHOHLN3C_cjs.ArkError && error.code === 0 && error.message.includes("duplicated input")) {
11651
12364
  const deleteIntent = await this.makeDeleteIntentSignature(inputs);
11652
12365
  await this.arkProvider.deleteIntent(deleteIntent);
11653
12366
  return this.arkProvider.registerIntent(intent);
@@ -11663,7 +12376,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
11663
12376
  expire_at: 0,
11664
12377
  cosigners_public_keys: cosignerPubKeys
11665
12378
  };
11666
- const proof = chunkUBYY2TPK_cjs.Intent.create(message, coins, outputs);
12379
+ const proof = chunkUHOHLN3C_cjs.Intent.create(message, coins, outputs);
11667
12380
  const signedProof = await this._signerRouter.sign(proof, intentProofJobs(coins));
11668
12381
  return {
11669
12382
  proof: base.base64.encode(signedProof.toPSBT()),
@@ -11675,7 +12388,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
11675
12388
  type: "delete",
11676
12389
  expire_at: 0
11677
12390
  };
11678
- const proof = chunkUBYY2TPK_cjs.Intent.create(message, coins, []);
12391
+ const proof = chunkUHOHLN3C_cjs.Intent.create(message, coins, []);
11679
12392
  const signedProof = await this._signerRouter.sign(proof, intentProofJobs(coins));
11680
12393
  return {
11681
12394
  proof: base.base64.encode(signedProof.toPSBT()),
@@ -11687,7 +12400,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
11687
12400
  type: "get-pending-tx",
11688
12401
  expire_at: 0
11689
12402
  };
11690
- const proof = chunkUBYY2TPK_cjs.Intent.create(message, coins, []);
12403
+ const proof = chunkUHOHLN3C_cjs.Intent.create(message, coins, []);
11691
12404
  const signedProof = await this._signerRouter.sign(proof, intentProofJobs(coins));
11692
12405
  return {
11693
12406
  proof: base.base64.encode(signedProof.toPSBT()),
@@ -12645,7 +13358,7 @@ var MessageBus = class {
12645
13358
  this.initialized = true;
12646
13359
  }
12647
13360
  async buildServices(config) {
12648
- const arkProvider = new chunkUBYY2TPK_cjs.RestArkProvider(config.arkServer.url);
13361
+ const arkProvider = new chunkUHOHLN3C_cjs.RestArkProvider(config.arkServer.url);
12649
13362
  const storage = {
12650
13363
  walletRepository: this.walletRepository,
12651
13364
  contractRepository: this.contractRepository
@@ -13470,10 +14183,18 @@ var WalletMessageHandler = class {
13470
14183
  type: "WALLET_STATUS",
13471
14184
  payload: {
13472
14185
  walletInitialized: true,
13473
- xOnlyPublicKey: pubKey
14186
+ xOnlyPublicKey: pubKey,
14187
+ providerConnectionState: this.readonlyWallet.getProviderConnectionState()
13474
14188
  }
13475
14189
  });
13476
14190
  }
14191
+ case "GET_CONTRACT_SYNC_STATE": {
14192
+ return this.tagged({
14193
+ id,
14194
+ type: "CONTRACT_SYNC_STATE",
14195
+ payload: { syncState: this.readonlyWallet.getContractSyncState() }
14196
+ });
14197
+ }
13477
14198
  case "CLEAR": {
13478
14199
  await this.clear();
13479
14200
  return this.tagged({
@@ -13802,7 +14523,7 @@ var WalletMessageHandler = class {
13802
14523
  // Wallet methods
13803
14524
  async handleInitWallet({ payload }) {
13804
14525
  const { arkServerUrl } = payload;
13805
- this.indexerProvider = new chunkUBYY2TPK_cjs.RestIndexerProvider(arkServerUrl);
14526
+ this.indexerProvider = new chunkUHOHLN3C_cjs.RestIndexerProvider(arkServerUrl);
13806
14527
  await this.onWalletInitialized();
13807
14528
  }
13808
14529
  async handleGetBalance() {
@@ -14236,6 +14957,7 @@ var DEFAULT_MESSAGE_TIMEOUTS = {
14236
14957
  GET_BALANCE: 1e4,
14237
14958
  GET_BOARDING_ADDRESS: 1e4,
14238
14959
  GET_STATUS: 1e4,
14960
+ GET_CONTRACT_SYNC_STATE: 1e4,
14239
14961
  GET_DELEGATE_INFO: 1e4,
14240
14962
  IS_CONTRACT_MANAGER_WATCHING: 1e4,
14241
14963
  // Medium reads — may involve indexer queries
@@ -14844,6 +15566,19 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
14844
15566
  throw new Error(`Failed to get status: ${error}`);
14845
15567
  }
14846
15568
  }
15569
+ /**
15570
+ * Wallet-level provider-connection freshness, delegated to the worker via
15571
+ * `GET_STATUS`. Async by necessity (the worker boundary is asynchronous); no
15572
+ * synchronous variant is offered because it would have the same transport
15573
+ * mismatch as the contract-manager proxy's cached `getSyncState()`.
15574
+ */
15575
+ async getProviderConnectionState() {
15576
+ const { providerConnectionState } = await this.getStatus();
15577
+ if (!providerConnectionState) {
15578
+ throw new Error("Worker did not report provider connection state");
15579
+ }
15580
+ return providerConnectionState;
15581
+ }
14847
15582
  async getActivityHistory() {
14848
15583
  return buildActivities(await this.getTransactionHistory(), this.activity.all());
14849
15584
  }
@@ -14898,6 +15633,32 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
14898
15633
  return wallet.sendMessage(message);
14899
15634
  };
14900
15635
  const messageTag = this.messageTag;
15636
+ const fetchSyncState = async () => {
15637
+ const message = {
15638
+ type: "GET_CONTRACT_SYNC_STATE",
15639
+ id: getRandomId(),
15640
+ tag: messageTag
15641
+ };
15642
+ const response = await sendContractMessage(message);
15643
+ return response.payload.syncState;
15644
+ };
15645
+ const UNKNOWN_STATE = {
15646
+ mode: "degraded",
15647
+ reason: "contract sync state unavailable from the worker"
15648
+ };
15649
+ let syncState = UNKNOWN_STATE;
15650
+ let everProbed = false;
15651
+ const refreshSyncState = async () => {
15652
+ try {
15653
+ syncState = await fetchSyncState();
15654
+ everProbed = true;
15655
+ } catch {
15656
+ if (!everProbed) {
15657
+ syncState = UNKNOWN_STATE;
15658
+ }
15659
+ }
15660
+ };
15661
+ await refreshSyncState();
14901
15662
  const manager = {
14902
15663
  async createContract(params) {
14903
15664
  const message = {
@@ -14908,6 +15669,7 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
14908
15669
  };
14909
15670
  try {
14910
15671
  const response = await sendContractMessage(message);
15672
+ await refreshSyncState();
14911
15673
  return response.payload.contract;
14912
15674
  } catch (e) {
14913
15675
  throw new Error("Failed to create contract");
@@ -14936,11 +15698,15 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
14936
15698
  };
14937
15699
  try {
14938
15700
  const response = await sendContractMessage(message);
15701
+ await refreshSyncState();
14939
15702
  return response.payload.contracts;
14940
15703
  } catch (e) {
14941
15704
  throw new Error("Failed to get contracts with vtxos");
14942
15705
  }
14943
15706
  },
15707
+ getSyncState() {
15708
+ return syncState;
15709
+ },
14944
15710
  async annotateVtxos(vtxos) {
14945
15711
  if (vtxos.length === 0) return [];
14946
15712
  const message = {
@@ -15049,7 +15815,11 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
15049
15815
  tag: messageTag,
15050
15816
  payload: opts
15051
15817
  };
15052
- await sendContractMessage(message);
15818
+ try {
15819
+ await sendContractMessage(message);
15820
+ } finally {
15821
+ await refreshSyncState();
15822
+ }
15053
15823
  },
15054
15824
  async refreshOutpoints(outpoints) {
15055
15825
  const message = {
@@ -15058,7 +15828,11 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
15058
15828
  tag: messageTag,
15059
15829
  payload: { outpoints }
15060
15830
  };
15061
- await sendContractMessage(message);
15831
+ try {
15832
+ await sendContractMessage(message);
15833
+ } finally {
15834
+ await refreshSyncState();
15835
+ }
15062
15836
  },
15063
15837
  scanContracts() {
15064
15838
  return Promise.reject(
@@ -15609,7 +16383,7 @@ var OnchainWallet = class _OnchainWallet {
15609
16383
  if (!inputs) {
15610
16384
  throw new Error("Fee estimation failed");
15611
16385
  }
15612
- let tx = new chunkUBYY2TPK_cjs.Transaction();
16386
+ let tx = new chunkUHOHLN3C_cjs.Transaction();
15613
16387
  for (const input of inputs) {
15614
16388
  tx.addInput({
15615
16389
  txid: input.txid,
@@ -15667,7 +16441,7 @@ var OnchainWallet = class _OnchainWallet {
15667
16441
  * @throws If the parent has no anchor, or funding cannot be selected/signed
15668
16442
  */
15669
16443
  async bumpAnchor(parentHex, feeRate) {
15670
- const parent = chunkUBYY2TPK_cjs.Transaction.fromRaw(base.hex.decode(parentHex));
16444
+ const parent = chunkUHOHLN3C_cjs.Transaction.fromRaw(base.hex.decode(parentHex));
15671
16445
  const coins = (await this.getCoins()).filter((c) => c.status.confirmed);
15672
16446
  const child = await this.buildBumpPackage(parent, feeRate, coins);
15673
16447
  return [parent.hex, child.hex];
@@ -16428,7 +17202,7 @@ exports.BIP322 = void 0;
16428
17202
  async function sign2(message, identity, network) {
16429
17203
  const xOnlyPubKey = await identity.xOnlyPublicKey();
16430
17204
  const payment = btcSigner.p2tr(xOnlyPubKey, void 0, network);
16431
- const toSpend = chunkUBYY2TPK_cjs.craftToSpendTx(message, payment.script, TAG_BIP322);
17205
+ const toSpend = chunkUHOHLN3C_cjs.craftToSpendTx(message, payment.script, TAG_BIP322);
16432
17206
  const toSign = craftBIP322ToSignP2TR(toSpend, payment.script, xOnlyPubKey);
16433
17207
  const signed = await identity.sign(toSign, [0]);
16434
17208
  signed.finalizeIdx(0);
@@ -16486,7 +17260,7 @@ function verifyP2TR(message, witnessItems, pkScript, pubkey) {
16486
17260
  if (sighashType !== btcSigner.SigHash.DEFAULT && sighashType !== btcSigner.SigHash.ALL) {
16487
17261
  return false;
16488
17262
  }
16489
- const toSpend = chunkUBYY2TPK_cjs.craftToSpendTx(message, pkScript, TAG_BIP322);
17263
+ const toSpend = chunkUHOHLN3C_cjs.craftToSpendTx(message, pkScript, TAG_BIP322);
16490
17264
  const toSign = craftBIP322ToSignP2TR(toSpend, pkScript, pubkey);
16491
17265
  const sighash = toSign.preimageWitnessV1(0, [pkScript], sighashType, [0n]);
16492
17266
  const rawSig = sig.length === 65 ? sig.subarray(0, 64) : sig;
@@ -16507,7 +17281,7 @@ function verifyP2WPKH(message, witnessItems, pkScript, addressHash) {
16507
17281
  }
16508
17282
  const sighashType = sigWithHash[sigWithHash.length - 1];
16509
17283
  const derSig = sigWithHash.subarray(0, sigWithHash.length - 1);
16510
- const toSpend = chunkUBYY2TPK_cjs.craftToSpendTx(message, pkScript, TAG_BIP322);
17284
+ const toSpend = chunkUHOHLN3C_cjs.craftToSpendTx(message, pkScript, TAG_BIP322);
16511
17285
  const toSign = craftBIP322ToSignSimple(toSpend, pkScript);
16512
17286
  const scriptCode = btcSigner.OutScript.encode({ type: "pkh", hash: addressHash });
16513
17287
  const sighash = toSign.preimageWitnessV0(0, scriptCode, sighashType, 0n);
@@ -16560,7 +17334,7 @@ function encodeCompactSize(n) {
16560
17334
  return buf;
16561
17335
  }
16562
17336
  function craftBIP322ToSignP2TR(toSpend, pkScript, tapInternalKey) {
16563
- const tx = new chunkUBYY2TPK_cjs.Transaction({ version: 0 });
17337
+ const tx = new chunkUHOHLN3C_cjs.Transaction({ version: 0 });
16564
17338
  tx.addInput({
16565
17339
  txid: toSpend.id,
16566
17340
  index: 0,
@@ -16574,12 +17348,12 @@ function craftBIP322ToSignP2TR(toSpend, pkScript, tapInternalKey) {
16574
17348
  });
16575
17349
  tx.addOutput({
16576
17350
  amount: 0n,
16577
- script: chunkUBYY2TPK_cjs.OP_RETURN_EMPTY_PKSCRIPT
17351
+ script: chunkUHOHLN3C_cjs.OP_RETURN_EMPTY_PKSCRIPT
16578
17352
  });
16579
17353
  return tx;
16580
17354
  }
16581
17355
  function craftBIP322ToSignSimple(toSpend, pkScript) {
16582
- const tx = new chunkUBYY2TPK_cjs.Transaction({ version: 0 });
17356
+ const tx = new chunkUHOHLN3C_cjs.Transaction({ version: 0 });
16583
17357
  tx.addInput({
16584
17358
  txid: toSpend.id,
16585
17359
  index: 0,
@@ -16591,12 +17365,12 @@ function craftBIP322ToSignSimple(toSpend, pkScript) {
16591
17365
  });
16592
17366
  tx.addOutput({
16593
17367
  amount: 0n,
16594
- script: chunkUBYY2TPK_cjs.OP_RETURN_EMPTY_PKSCRIPT
17368
+ script: chunkUHOHLN3C_cjs.OP_RETURN_EMPTY_PKSCRIPT
16595
17369
  });
16596
17370
  return tx;
16597
17371
  }
16598
17372
  function finalizeVirtualTx(type, psbtBase64) {
16599
- const tx = chunkUBYY2TPK_cjs.Transaction.fromPSBT(base.base64.decode(psbtBase64));
17373
+ const tx = chunkUHOHLN3C_cjs.Transaction.fromPSBT(base.base64.decode(psbtBase64));
16600
17374
  if (type === "INDEXER_CHAINED_TX_TYPE_TREE" /* TREE */) {
16601
17375
  const input = tx.getInput(0);
16602
17376
  if (!input) {
@@ -16673,7 +17447,7 @@ async function resolveUnilateralPath(params) {
16673
17447
  }
16674
17448
 
16675
17449
  // src/wallet/unroll.ts
16676
- function chainTxTypeToChainedExit(t) {
17450
+ function chainTxTypeToChainedExit2(t) {
16677
17451
  switch (t) {
16678
17452
  case "INDEXER_CHAINED_TX_TYPE_COMMITMENT" /* COMMITMENT */:
16679
17453
  return 1 /* Commitment */;
@@ -16736,7 +17510,7 @@ exports.Unroll = void 0;
16736
17510
  txid: next.txid,
16737
17511
  psbt,
16738
17512
  expiresAt: null,
16739
- type: chainTxTypeToChainedExit(next.type)
17513
+ type: chainTxTypeToChainedExit2(next.type)
16740
17514
  };
16741
17515
  try {
16742
17516
  await repo.upsertVirtualTxs([cached]);
@@ -16868,7 +17642,7 @@ async function prepareUnrollTransaction(wallet, vtxoTxIds, outputAddress) {
16868
17642
  btcSigner.TaprootControlBlock.encode(spendingLeaf[0]).length
16869
17643
  );
16870
17644
  }
16871
- const tx = new chunkUBYY2TPK_cjs.Transaction({ version: 2 });
17645
+ const tx = new chunkUHOHLN3C_cjs.Transaction({ version: 2 });
16872
17646
  for (const input of inputs) {
16873
17647
  tx.addInput(input);
16874
17648
  }
@@ -16914,99 +17688,6 @@ function doWait(onchainProvider, txid) {
16914
17688
  });
16915
17689
  };
16916
17690
  }
16917
-
16918
- // src/wallet/exit/chain.ts
16919
- var isCommitment = (t) => t === "INDEXER_CHAINED_TX_TYPE_COMMITMENT" /* COMMITMENT */ || t === "INDEXER_CHAINED_TX_TYPE_UNSPECIFIED" /* UNSPECIFIED */;
16920
- async function buildExitDag(params) {
16921
- const byTxid = /* @__PURE__ */ new Map();
16922
- for (const vtxo of params.vtxos) {
16923
- const outpoint = `${vtxo.txid}:${vtxo.vout}`;
16924
- let pageIndex = 0;
16925
- let hasMore = true;
16926
- while (hasMore) {
16927
- const { chain, page } = await params.indexer.getVtxoChain(
16928
- { txid: vtxo.txid, vout: vtxo.vout },
16929
- { pageIndex, pageSize: chunk32YKLQPS_cjs.DEFAULT_PAGE_SIZE }
16930
- );
16931
- for (const chainTx of chain) {
16932
- const existing = byTxid.get(chainTx.txid);
16933
- if (existing) {
16934
- existing.forVtxos.add(outpoint);
16935
- } else {
16936
- byTxid.set(chainTx.txid, { ...chainTx, forVtxos: /* @__PURE__ */ new Set([outpoint]) });
16937
- }
16938
- }
16939
- hasMore = page ? chain.length === chunk32YKLQPS_cjs.DEFAULT_PAGE_SIZE : false;
16940
- pageIndex++;
16941
- }
16942
- }
16943
- const pending = new Map(
16944
- [...byTxid.values()].filter((tx) => !isCommitment(tx.type)).map((tx) => [tx.txid, tx])
16945
- );
16946
- const inDegree = /* @__PURE__ */ new Map();
16947
- for (const tx of pending.values()) {
16948
- const parents = tx.spends.filter((p) => pending.has(p));
16949
- inDegree.set(tx.txid, parents.length);
16950
- }
16951
- const order = [];
16952
- const queue = [...pending.values()].filter((tx) => inDegree.get(tx.txid) === 0).sort((a, b) => a.txid.localeCompare(b.txid));
16953
- while (queue.length > 0) {
16954
- const tx = queue.shift();
16955
- order.push(tx);
16956
- const children = [...pending.values()].filter((c) => c.spends.includes(tx.txid)).sort((a, b) => a.txid.localeCompare(b.txid));
16957
- for (const child of children) {
16958
- const deg = inDegree.get(child.txid) - 1;
16959
- inDegree.set(child.txid, deg);
16960
- if (deg === 0) queue.push(child);
16961
- }
16962
- }
16963
- if (order.length !== pending.size) {
16964
- throw new Error("inconsistent vtxo chain from indexer (cycle detected)");
16965
- }
16966
- const nodes = [];
16967
- for (const tx of order) {
16968
- let confirmed = false;
16969
- try {
16970
- const status = await params.onchain.getTxStatus(tx.txid);
16971
- confirmed = status.confirmed;
16972
- } catch {
16973
- confirmed = false;
16974
- }
16975
- const expires = Number(tx.expiresAt);
16976
- nodes.push({
16977
- txid: tx.txid,
16978
- type: tx.type,
16979
- expiresAt: Number.isFinite(expires) && expires > 0 ? expires : void 0,
16980
- forVtxos: [...tx.forVtxos].sort(),
16981
- confirmed
16982
- });
16983
- }
16984
- return nodes;
16985
- }
16986
- function topoSortByDeps(items, idOf, depsOf) {
16987
- const produced = new Set(items.map(idOf));
16988
- const emitted = /* @__PURE__ */ new Set();
16989
- const ordered = [];
16990
- let remaining = items;
16991
- while (remaining.length > 0) {
16992
- const next = [];
16993
- let progress = false;
16994
- for (const item of remaining) {
16995
- if (depsOf(item).every((d) => !produced.has(d) || emitted.has(d))) {
16996
- ordered.push(item);
16997
- emitted.add(idOf(item));
16998
- progress = true;
16999
- } else {
17000
- next.push(item);
17001
- }
17002
- }
17003
- if (!progress) {
17004
- throw new Error("topological sort: cycle or unsatisfiable dependency");
17005
- }
17006
- remaining = next;
17007
- }
17008
- return ordered;
17009
- }
17010
17691
  function extraWitnessSize(path) {
17011
17692
  return (path.extraWitness ?? []).reduce((sum, item) => sum + 1 + item.length, 0);
17012
17693
  }
@@ -17028,7 +17709,7 @@ async function buildSignedSweep(params) {
17028
17709
  `uneconomic vtxo ${vtxo.txid}:${vtxo.vout}: value ${vtxo.value} - fee ${fee} < dust`
17029
17710
  );
17030
17711
  }
17031
- const tx = new chunkUBYY2TPK_cjs.Transaction({ version: 2 });
17712
+ const tx = new chunkUHOHLN3C_cjs.Transaction({ version: 2 });
17032
17713
  tx.addInput({
17033
17714
  txid: vtxo.txid,
17034
17715
  index: vtxo.vout,
@@ -17113,27 +17794,22 @@ async function computeExitLayout(opts, feeRate) {
17113
17794
  const { wallet, onchainWallet } = opts;
17114
17795
  const vtxos = await selectExitVtxos(opts);
17115
17796
  if (vtxos.length === 0) throw new Error("no vtxos to exit");
17797
+ const resolver = createExitChainResolver({
17798
+ indexer: wallet.indexerProvider,
17799
+ repository: wallet.virtualTxRepository,
17800
+ extraSources: wallet.exitDataCapture?.sources
17801
+ });
17116
17802
  const dag = await buildExitDag({
17117
17803
  vtxos,
17118
- indexer: wallet.indexerProvider,
17804
+ chain: resolver,
17119
17805
  onchain: wallet.onchainProvider
17120
17806
  });
17121
17807
  const pendingNodes = dag.filter((n) => !n.confirmed);
17122
17808
  const psbts = /* @__PURE__ */ new Map();
17123
17809
  if (pendingNodes.length > 0) {
17124
- const txids = pendingNodes.map((n) => n.txid);
17125
- let pageIndex = 0;
17126
- let hasMore = true;
17127
- while (hasMore) {
17128
- const { txs, page } = await wallet.indexerProvider.getVirtualTxs(txids, {
17129
- pageIndex,
17130
- pageSize: chunk32YKLQPS_cjs.DEFAULT_PAGE_SIZE
17131
- });
17132
- for (const psbt of txs) {
17133
- psbts.set(chunkUBYY2TPK_cjs.Transaction.fromPSBT(base.base64.decode(psbt)).id, psbt);
17134
- }
17135
- hasMore = page ? txs.length === chunk32YKLQPS_cjs.DEFAULT_PAGE_SIZE : false;
17136
- pageIndex++;
17810
+ const txs = await resolver.getVirtualTxs(pendingNodes.map((n) => n.txid));
17811
+ for (const psbt of txs) {
17812
+ psbts.set(chunkUHOHLN3C_cjs.Transaction.fromPSBT(base.base64.decode(psbt)).id, psbt);
17137
17813
  }
17138
17814
  }
17139
17815
  const childVsize = Number(
@@ -17578,7 +18254,7 @@ async function prepare(opts) {
17578
18254
  if (newFee <= splitterFee) break;
17579
18255
  splitterFee = newFee;
17580
18256
  }
17581
- const splitter = new chunkUBYY2TPK_cjs.Transaction({ version: 2 });
18257
+ const splitter = new chunkUHOHLN3C_cjs.Transaction({ version: 2 });
17582
18258
  for (const coin of selected.inputs) {
17583
18259
  splitter.addInput({
17584
18260
  txid: coin.txid,
@@ -17851,6 +18527,7 @@ exports.combineTapscriptSigs = combineTapscriptSigs;
17851
18527
  exports.contractFromArkContract = contractFromArkContract;
17852
18528
  exports.contractFromArkContractWithAddress = contractFromArkContractWithAddress;
17853
18529
  exports.createDefaultActivityRegistry = createDefaultActivityRegistry;
18530
+ exports.createExitChainResolver = createExitChainResolver;
17854
18531
  exports.decodeArkContract = decodeArkContract;
17855
18532
  exports.deserializeAssets = deserializeAssets;
17856
18533
  exports.deserializeExitPackage = deserializeExitPackage;
@@ -17869,6 +18546,7 @@ exports.isCooperativelyMigratable = isCooperativelyMigratable;
17869
18546
  exports.isDiscoverable = isDiscoverable;
17870
18547
  exports.isExpired = isExpired;
17871
18548
  exports.isRecoverable = isRecoverable;
18549
+ exports.isRetryableProviderError = isRetryableProviderError;
17872
18550
  exports.isSpendable = isSpendable;
17873
18551
  exports.isSubdust = isSubdust;
17874
18552
  exports.isTerminalIntentState = isTerminalIntentState;
@@ -17894,5 +18572,5 @@ exports.validateVtxoTxGraph = validateVtxoTxGraph;
17894
18572
  exports.verifyTapscriptSignatures = verifyTapscriptSignatures;
17895
18573
  exports.waitForIncomingFunds = waitForIncomingFunds;
17896
18574
  exports.warnAndFilterVtxosForScript = warnAndFilterVtxosForScript;
17897
- //# sourceMappingURL=chunk-XIVCG6EP.cjs.map
17898
- //# sourceMappingURL=chunk-XIVCG6EP.cjs.map
18575
+ //# sourceMappingURL=chunk-SRCWBFSZ.cjs.map
18576
+ //# sourceMappingURL=chunk-SRCWBFSZ.cjs.map