@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,4 +1,4 @@
1
- import { craftToSpendTx, Transaction, OP_RETURN_EMPTY_PKSCRIPT, baseFetch, Intent, getArkPsbtFields, CosignerPublicKey, setArkPsbtField, VtxoTaprootTree, maybeArkError, AssetRef, AssetId, AssetOutput, AssetGroup, AssetInput, Packet, Metadata, isEventSourceError, RestArkProvider, RestIndexerProvider, ArkError, BufferReader } from './chunk-LJ35HPJW.js';
1
+ import { craftToSpendTx, Transaction, OP_RETURN_EMPTY_PKSCRIPT, baseFetch, Intent, getArkPsbtFields, CosignerPublicKey, setArkPsbtField, VtxoTaprootTree, maybeArkError, ProviderUnavailableError, FetchError, isFetchTimeoutError, AssetRef, AssetId, AssetOutput, AssetGroup, AssetInput, Packet, Metadata, isEventSourceError, RestArkProvider, RestIndexerProvider, ArkError, BufferReader } from './chunk-YBQV7XBC.js';
2
2
  import { contractHandlers, isMainnetDescriptor, descriptorIsOurs, DEFAULT_PAGE_SIZE, DelegateVtxo, WALLET_RECEIVE_SOURCE, deriveDescriptorLeafPubKey, DefaultVtxo, BoardingContractHandler } from './chunk-YNEDJTX2.js';
3
3
  import { VtxoScript, sequenceToTimelock, timelockToSequence, DEFAULT_NETWORK, DEFAULT_NETWORK_NAME, decodeTapscript, scriptFromTapLeafScript, CLTVMultisigTapscript, ArkAddress, CSVMultisigTapscript, getSequence, getNetwork, MultisigTapscript, networks as networks$1, DEFAULT_ARKADE_SERVER_URL } from './chunk-BE5MUB7T.js';
4
4
  import { sha256, hash160, sha256x2, concatBytes, randomPrivateKeyBytes, pubECDSA, pubSchnorr, equalBytes as equalBytes$1 } from '@scure/btc-signer/utils.js';
@@ -4287,6 +4287,592 @@ function wrapHandlerWithIntentPersistence(base, deps) {
4287
4287
  }
4288
4288
  };
4289
4289
  }
4290
+
4291
+ // src/repositories/virtualTxRepository.ts
4292
+ var ChainedTxType = /* @__PURE__ */ ((ChainedTxType2) => {
4293
+ ChainedTxType2[ChainedTxType2["Unspecified"] = 0] = "Unspecified";
4294
+ ChainedTxType2[ChainedTxType2["Commitment"] = 1] = "Commitment";
4295
+ ChainedTxType2[ChainedTxType2["Ark"] = 2] = "Ark";
4296
+ ChainedTxType2[ChainedTxType2["Tree"] = 3] = "Tree";
4297
+ ChainedTxType2[ChainedTxType2["Checkpoint"] = 4] = "Checkpoint";
4298
+ return ChainedTxType2;
4299
+ })(ChainedTxType || {});
4300
+ function mergeChainedTxType(incoming, prev) {
4301
+ if (incoming !== 0 /* Unspecified */) return incoming;
4302
+ return prev ?? 0 /* Unspecified */;
4303
+ }
4304
+
4305
+ // src/wallet/exit/chain.ts
4306
+ var isCommitment = (t) => t === "INDEXER_CHAINED_TX_TYPE_COMMITMENT" /* COMMITMENT */ || t === "INDEXER_CHAINED_TX_TYPE_UNSPECIFIED" /* UNSPECIFIED */;
4307
+ async function buildExitDag(params) {
4308
+ const byTxid = /* @__PURE__ */ new Map();
4309
+ for (const vtxo of params.vtxos) {
4310
+ const outpoint = `${vtxo.txid}:${vtxo.vout}`;
4311
+ const chain = await params.chain.getVtxoChain({ txid: vtxo.txid, vout: vtxo.vout });
4312
+ for (const chainTx of chain) {
4313
+ const existing = byTxid.get(chainTx.txid);
4314
+ if (existing) {
4315
+ existing.forVtxos.add(outpoint);
4316
+ } else {
4317
+ byTxid.set(chainTx.txid, { ...chainTx, forVtxos: /* @__PURE__ */ new Set([outpoint]) });
4318
+ }
4319
+ }
4320
+ }
4321
+ const pending = new Map(
4322
+ [...byTxid.values()].filter((tx) => !isCommitment(tx.type)).map((tx) => [tx.txid, tx])
4323
+ );
4324
+ const inDegree = /* @__PURE__ */ new Map();
4325
+ for (const tx of pending.values()) {
4326
+ const parents = tx.spends.filter((p) => pending.has(p));
4327
+ inDegree.set(tx.txid, parents.length);
4328
+ }
4329
+ const order = [];
4330
+ const queue = [...pending.values()].filter((tx) => inDegree.get(tx.txid) === 0).sort((a, b) => a.txid.localeCompare(b.txid));
4331
+ while (queue.length > 0) {
4332
+ const tx = queue.shift();
4333
+ order.push(tx);
4334
+ const children = [...pending.values()].filter((c) => c.spends.includes(tx.txid)).sort((a, b) => a.txid.localeCompare(b.txid));
4335
+ for (const child of children) {
4336
+ const deg = inDegree.get(child.txid) - 1;
4337
+ inDegree.set(child.txid, deg);
4338
+ if (deg === 0) queue.push(child);
4339
+ }
4340
+ }
4341
+ if (order.length !== pending.size) {
4342
+ throw new Error("inconsistent vtxo chain from indexer (cycle detected)");
4343
+ }
4344
+ const nodes = [];
4345
+ for (const tx of order) {
4346
+ let confirmed = false;
4347
+ try {
4348
+ const status = await params.onchain.getTxStatus(tx.txid);
4349
+ confirmed = status.confirmed;
4350
+ } catch {
4351
+ confirmed = false;
4352
+ }
4353
+ const expires = Number(tx.expiresAt);
4354
+ nodes.push({
4355
+ txid: tx.txid,
4356
+ type: tx.type,
4357
+ expiresAt: Number.isFinite(expires) && expires > 0 ? expires : void 0,
4358
+ forVtxos: [...tx.forVtxos].sort(),
4359
+ confirmed
4360
+ });
4361
+ }
4362
+ return nodes;
4363
+ }
4364
+ function topoSortByDeps(items, idOf, depsOf) {
4365
+ const produced = new Set(items.map(idOf));
4366
+ const emitted = /* @__PURE__ */ new Set();
4367
+ const ordered = [];
4368
+ let remaining = items;
4369
+ while (remaining.length > 0) {
4370
+ const next = [];
4371
+ let progress = false;
4372
+ for (const item of remaining) {
4373
+ if (depsOf(item).every((d) => !produced.has(d) || emitted.has(d))) {
4374
+ ordered.push(item);
4375
+ emitted.add(idOf(item));
4376
+ progress = true;
4377
+ } else {
4378
+ next.push(item);
4379
+ }
4380
+ }
4381
+ if (!progress) {
4382
+ throw new Error("topological sort: cycle or unsatisfiable dependency");
4383
+ }
4384
+ remaining = next;
4385
+ }
4386
+ return ordered;
4387
+ }
4388
+
4389
+ // src/wallet/exit/capture.ts
4390
+ var DEFAULT_MIN_EXIT_WORTH_SATS = 1e3;
4391
+ var DEFAULT_EXIT_CAPTURE_MODE = "lite";
4392
+ function chainTxTypeToChainedExit(t) {
4393
+ switch (t) {
4394
+ case "INDEXER_CHAINED_TX_TYPE_COMMITMENT" /* COMMITMENT */:
4395
+ return 1 /* Commitment */;
4396
+ case "INDEXER_CHAINED_TX_TYPE_ARK" /* ARK */:
4397
+ return 2 /* Ark */;
4398
+ case "INDEXER_CHAINED_TX_TYPE_TREE" /* TREE */:
4399
+ return 3 /* Tree */;
4400
+ case "INDEXER_CHAINED_TX_TYPE_CHECKPOINT" /* CHECKPOINT */:
4401
+ return 4 /* Checkpoint */;
4402
+ default:
4403
+ return 0 /* Unspecified */;
4404
+ }
4405
+ }
4406
+ function orderAncestryFirst(chain) {
4407
+ const ids = new Set(chain.map((c) => c.txid));
4408
+ return topoSortByDeps(
4409
+ chain,
4410
+ (c) => c.txid,
4411
+ (c) => c.spends.filter((s) => ids.has(s))
4412
+ );
4413
+ }
4414
+ async function captureExitBranch(params) {
4415
+ const { resolver, repository, vtxo, value, mode, minExitWorthSats } = params;
4416
+ if (value < minExitWorthSats) return;
4417
+ if (await repository.hasBranch(vtxo)) return;
4418
+ const ordered = orderAncestryFirst(await resolver.getVtxoChain(vtxo));
4419
+ const psbtByTxid = /* @__PURE__ */ new Map();
4420
+ if (mode === "full") {
4421
+ const nonCommitment = ordered.filter((c) => chainTxTypeToChainedExit(c.type) !== 1 /* Commitment */).map((c) => c.txid);
4422
+ if (nonCommitment.length > 0) {
4423
+ for (const psbt of await resolver.getVirtualTxs(nonCommitment)) {
4424
+ psbtByTxid.set(Transaction.fromPSBT(base64.decode(psbt)).id, psbt);
4425
+ }
4426
+ }
4427
+ }
4428
+ const virtualTxs = ordered.map((c) => {
4429
+ const expires = Number(c.expiresAt);
4430
+ return {
4431
+ txid: c.txid,
4432
+ psbt: psbtByTxid.get(c.txid) ?? null,
4433
+ expiresAt: Number.isFinite(expires) && expires > 0 ? expires : null,
4434
+ type: chainTxTypeToChainedExit(c.type)
4435
+ };
4436
+ });
4437
+ const branch = ordered.map((c, i) => ({
4438
+ vtxoTxid: vtxo.txid,
4439
+ vtxoVout: vtxo.vout,
4440
+ virtualTxid: c.txid,
4441
+ position: i
4442
+ }));
4443
+ await repository.upsertVirtualTxs(virtualTxs);
4444
+ await repository.setBranch(vtxo, branch);
4445
+ }
4446
+ async function pruneExitBranches(repository, outpoints) {
4447
+ for (const outpoint of outpoints) {
4448
+ try {
4449
+ await repository.pruneForSpentVtxo(outpoint);
4450
+ } catch {
4451
+ }
4452
+ }
4453
+ }
4454
+ var IndexerExitDataSource = class {
4455
+ constructor(indexer) {
4456
+ this.indexer = indexer;
4457
+ }
4458
+ name = "indexer";
4459
+ async getVtxoChain(vtxo) {
4460
+ const chain = [];
4461
+ let pageIndex = 0;
4462
+ let hasMore = true;
4463
+ while (hasMore) {
4464
+ const { chain: page, page: meta } = await this.indexer.getVtxoChain(
4465
+ { txid: vtxo.txid, vout: vtxo.vout },
4466
+ { pageIndex, pageSize: DEFAULT_PAGE_SIZE }
4467
+ );
4468
+ chain.push(...page);
4469
+ hasMore = meta ? page.length === DEFAULT_PAGE_SIZE : false;
4470
+ pageIndex++;
4471
+ }
4472
+ return chain;
4473
+ }
4474
+ async getVirtualTxs(txids) {
4475
+ const out = /* @__PURE__ */ new Map();
4476
+ let pageIndex = 0;
4477
+ let hasMore = true;
4478
+ while (hasMore) {
4479
+ const { txs, page } = await this.indexer.getVirtualTxs(txids, {
4480
+ pageIndex,
4481
+ pageSize: DEFAULT_PAGE_SIZE
4482
+ });
4483
+ for (const psbt of txs) {
4484
+ out.set(Transaction.fromPSBT(base64.decode(psbt)).id, psbt);
4485
+ }
4486
+ hasMore = page ? txs.length === DEFAULT_PAGE_SIZE : false;
4487
+ pageIndex++;
4488
+ }
4489
+ return out;
4490
+ }
4491
+ };
4492
+ function chainedTxTypeToChainTxType(t) {
4493
+ switch (t) {
4494
+ case 1 /* Commitment */:
4495
+ return "INDEXER_CHAINED_TX_TYPE_COMMITMENT" /* COMMITMENT */;
4496
+ case 2 /* Ark */:
4497
+ return "INDEXER_CHAINED_TX_TYPE_ARK" /* ARK */;
4498
+ case 3 /* Tree */:
4499
+ return "INDEXER_CHAINED_TX_TYPE_TREE" /* TREE */;
4500
+ case 4 /* Checkpoint */:
4501
+ return "INDEXER_CHAINED_TX_TYPE_CHECKPOINT" /* CHECKPOINT */;
4502
+ default:
4503
+ return "INDEXER_CHAINED_TX_TYPE_UNSPECIFIED" /* UNSPECIFIED */;
4504
+ }
4505
+ }
4506
+ function psbtInputTxids(psbtBase64) {
4507
+ const tx = Transaction.fromPSBT(base64.decode(psbtBase64));
4508
+ const ids = [];
4509
+ for (let i = 0; i < tx.inputsLength; i++) {
4510
+ const txid = tx.getInput(i).txid;
4511
+ if (txid) ids.push(hex.encode(txid));
4512
+ }
4513
+ return ids;
4514
+ }
4515
+ var RepositoryExitDataSource = class {
4516
+ constructor(repo) {
4517
+ this.repo = repo;
4518
+ }
4519
+ name = "repository";
4520
+ async getVtxoChain(vtxo) {
4521
+ const branch = await this.repo.getBranch(vtxo);
4522
+ if (branch.length === 0) return null;
4523
+ const chain = [];
4524
+ for (const v of branch) {
4525
+ const type = chainedTxTypeToChainTxType(v.type);
4526
+ let spends = [];
4527
+ if (v.type !== 1 /* Commitment */) {
4528
+ if (!v.psbt) return null;
4529
+ spends = psbtInputTxids(v.psbt);
4530
+ }
4531
+ chain.push({
4532
+ txid: v.txid,
4533
+ type,
4534
+ expiresAt: v.expiresAt != null ? String(v.expiresAt) : "",
4535
+ spends
4536
+ });
4537
+ }
4538
+ return chain;
4539
+ }
4540
+ async getVirtualTxs(txids) {
4541
+ const out = /* @__PURE__ */ new Map();
4542
+ for (const txid of txids) {
4543
+ const stored = await this.repo.getVirtualTx(txid);
4544
+ if (stored?.psbt) out.set(txid, stored.psbt);
4545
+ }
4546
+ return out;
4547
+ }
4548
+ };
4549
+
4550
+ // src/wallet/exit/resolver.ts
4551
+ var OrderedExitChainResolver = class {
4552
+ constructor(sources, persist) {
4553
+ this.sources = sources;
4554
+ this.persist = persist;
4555
+ }
4556
+ async getVtxoChain(vtxo) {
4557
+ let lastErr;
4558
+ for (const source of this.sources) {
4559
+ try {
4560
+ const chain = await source.getVtxoChain(vtxo);
4561
+ if (chain) return chain;
4562
+ } catch (e) {
4563
+ lastErr = e;
4564
+ }
4565
+ }
4566
+ if (lastErr) throw lastErr;
4567
+ throw new Error(`no exit-data source resolved the chain for ${vtxo.txid}:${vtxo.vout}`);
4568
+ }
4569
+ async getVirtualTxs(txids) {
4570
+ const found = /* @__PURE__ */ new Map();
4571
+ let remaining = txids;
4572
+ for (const [i, source] of this.sources.entries()) {
4573
+ if (remaining.length === 0) break;
4574
+ let got;
4575
+ try {
4576
+ got = await source.getVirtualTxs(remaining);
4577
+ } catch {
4578
+ continue;
4579
+ }
4580
+ const fresh = [];
4581
+ for (const [txid, psbt] of got) {
4582
+ if (found.has(txid)) continue;
4583
+ found.set(txid, psbt);
4584
+ fresh.push({ txid, psbt, expiresAt: null, type: 0 /* Unspecified */ });
4585
+ }
4586
+ if (i > 0 && this.persist && fresh.length > 0) {
4587
+ try {
4588
+ await this.persist.upsertVirtualTxs(fresh);
4589
+ } catch {
4590
+ }
4591
+ }
4592
+ remaining = txids.filter((t) => !found.has(t));
4593
+ }
4594
+ return [...found.values()];
4595
+ }
4596
+ };
4597
+ function createExitChainResolver(params) {
4598
+ const sources = [];
4599
+ if (params.repository) sources.push(new RepositoryExitDataSource(params.repository));
4600
+ if (params.extraSources) sources.push(...params.extraSources);
4601
+ sources.push(new IndexerExitDataSource(params.indexer));
4602
+ return new OrderedExitChainResolver(sources, params.repository);
4603
+ }
4604
+
4605
+ // src/providers/availability.ts
4606
+ function isRetryableProviderError(error) {
4607
+ return error instanceof ProviderUnavailableError || error instanceof FetchError || isFetchTimeoutError(error);
4608
+ }
4609
+
4610
+ // src/utils/syncCursors.ts
4611
+ var SAFETY_LAG_MS = 3e4;
4612
+ var OVERLAP_MS = 24 * 60 * 60 * 1e3;
4613
+ var walletStateLocks = /* @__PURE__ */ new WeakMap();
4614
+ async function updateWalletState(repo, updater) {
4615
+ const prev = walletStateLocks.get(repo) ?? Promise.resolve();
4616
+ const op = prev.then(async () => {
4617
+ const state = await repo.getWalletState() ?? {};
4618
+ await repo.saveWalletState(updater(state));
4619
+ });
4620
+ walletStateLocks.set(
4621
+ repo,
4622
+ op.catch(() => {
4623
+ })
4624
+ );
4625
+ return op;
4626
+ }
4627
+ var CURSOR_MIGRATED_KEY = "vtxoCursorMigrated";
4628
+ function hasMigrationMarker(state) {
4629
+ return state?.settings?.[CURSOR_MIGRATED_KEY] === true;
4630
+ }
4631
+ async function getSyncCursor(repo) {
4632
+ const state = await repo.getWalletState();
4633
+ if (!hasMigrationMarker(state)) return 0;
4634
+ return state?.lastSyncTime ?? 0;
4635
+ }
4636
+ async function advanceSyncCursor(repo, lastUpdatedAt) {
4637
+ await updateWalletState(repo, (state) => {
4638
+ const current = hasMigrationMarker(state) ? state.lastSyncTime ?? 0 : 0;
4639
+ return {
4640
+ ...state,
4641
+ lastSyncTime: Math.max(current, lastUpdatedAt),
4642
+ settings: {
4643
+ ...state.settings ?? {},
4644
+ [CURSOR_MIGRATED_KEY]: true
4645
+ }
4646
+ };
4647
+ });
4648
+ }
4649
+ async function clearSyncCursor(repo) {
4650
+ await updateWalletState(repo, (state) => {
4651
+ const { [CURSOR_MIGRATED_KEY]: _, ...restSettings } = state.settings ?? {};
4652
+ return {
4653
+ ...state,
4654
+ lastSyncTime: void 0,
4655
+ settings: restSettings
4656
+ };
4657
+ });
4658
+ }
4659
+ function computeSyncWindow(cursor) {
4660
+ const after = Math.max(0, cursor - OVERLAP_MS);
4661
+ return { after };
4662
+ }
4663
+ function cursorCutoff(requestStartedAt) {
4664
+ return (requestStartedAt ?? Date.now()) - SAFETY_LAG_MS;
4665
+ }
4666
+
4667
+ // src/wallet/arkInfoSnapshot.ts
4668
+ var ARK_INFO_SNAPSHOT_KEY = "arkInfoSnapshot";
4669
+ var MalformedArkInfoSnapshotError = class extends Error {
4670
+ constructor(message, options) {
4671
+ super(message, { cause: options?.cause });
4672
+ this.name = "MalformedArkInfoSnapshotError";
4673
+ }
4674
+ };
4675
+ var CURRENT_VERSION = 1;
4676
+ function serializeArkInfoSnapshot(info, savedAt) {
4677
+ return {
4678
+ version: CURRENT_VERSION,
4679
+ savedAt,
4680
+ source: "arkade.getInfo",
4681
+ arkInfo: {
4682
+ network: info.network,
4683
+ signerPubkey: info.signerPubkey,
4684
+ checkpointTapscript: info.checkpointTapscript,
4685
+ forfeitAddress: info.forfeitAddress,
4686
+ forfeitPubkey: info.forfeitPubkey,
4687
+ unilateralExitDelay: info.unilateralExitDelay.toString(),
4688
+ boardingExitDelay: info.boardingExitDelay.toString(),
4689
+ sessionDuration: info.sessionDuration.toString(),
4690
+ dust: info.dust.toString(),
4691
+ fees: info.fees,
4692
+ digest: info.digest,
4693
+ version: info.version,
4694
+ vtxoMinAmount: info.vtxoMinAmount.toString(),
4695
+ vtxoMaxAmount: info.vtxoMaxAmount.toString(),
4696
+ utxoMinAmount: info.utxoMinAmount.toString(),
4697
+ utxoMaxAmount: info.utxoMaxAmount.toString(),
4698
+ deprecatedSigners: info.deprecatedSigners.map((s) => ({
4699
+ pubkey: s.pubkey,
4700
+ cutoffDate: s.cutoffDate.toString()
4701
+ })),
4702
+ scheduledSession: info.scheduledSession ? {
4703
+ duration: info.scheduledSession.duration.toString(),
4704
+ fees: info.scheduledSession.fees,
4705
+ nextEndTime: info.scheduledSession.nextEndTime.toString(),
4706
+ nextStartTime: info.scheduledSession.nextStartTime.toString(),
4707
+ period: info.scheduledSession.period.toString()
4708
+ } : void 0
4709
+ }
4710
+ };
4711
+ }
4712
+ function hydrateArkInfo(snapshot) {
4713
+ const a = snapshot.arkInfo;
4714
+ return {
4715
+ boardingExitDelay: BigInt(a.boardingExitDelay),
4716
+ checkpointTapscript: a.checkpointTapscript,
4717
+ deprecatedSigners: a.deprecatedSigners.map((s) => ({
4718
+ cutoffDate: BigInt(s.cutoffDate),
4719
+ pubkey: s.pubkey
4720
+ })),
4721
+ digest: a.digest,
4722
+ dust: BigInt(a.dust),
4723
+ fees: a.fees,
4724
+ forfeitAddress: a.forfeitAddress,
4725
+ forfeitPubkey: a.forfeitPubkey,
4726
+ network: a.network,
4727
+ scheduledSession: a.scheduledSession ? {
4728
+ duration: BigInt(a.scheduledSession.duration),
4729
+ fees: a.scheduledSession.fees,
4730
+ nextEndTime: BigInt(a.scheduledSession.nextEndTime),
4731
+ nextStartTime: BigInt(a.scheduledSession.nextStartTime),
4732
+ period: BigInt(a.scheduledSession.period)
4733
+ } : void 0,
4734
+ serviceStatus: {},
4735
+ sessionDuration: BigInt(a.sessionDuration),
4736
+ signerPubkey: a.signerPubkey,
4737
+ unilateralExitDelay: BigInt(a.unilateralExitDelay),
4738
+ utxoMaxAmount: BigInt(a.utxoMaxAmount),
4739
+ utxoMinAmount: BigInt(a.utxoMinAmount),
4740
+ version: a.version,
4741
+ vtxoMaxAmount: BigInt(a.vtxoMaxAmount),
4742
+ vtxoMinAmount: BigInt(a.vtxoMinAmount)
4743
+ };
4744
+ }
4745
+ var DECIMAL_STRING = /^-?\d+$/;
4746
+ function assertString(value, path) {
4747
+ if (typeof value !== "string") {
4748
+ throw new MalformedArkInfoSnapshotError(`${path} must be a string`);
4749
+ }
4750
+ }
4751
+ function assertDecimalString(value, path) {
4752
+ assertString(value, path);
4753
+ if (!DECIMAL_STRING.test(value)) {
4754
+ throw new MalformedArkInfoSnapshotError(`${path} must be a decimal integer string`);
4755
+ }
4756
+ }
4757
+ function assertFeeInfo(value, path) {
4758
+ if (typeof value !== "object" || value === null) {
4759
+ throw new MalformedArkInfoSnapshotError(`${path} must be an object`);
4760
+ }
4761
+ const fees = value;
4762
+ assertString(fees.txFeeRate, `${path}.txFeeRate`);
4763
+ if (typeof fees.intentFee !== "object" || fees.intentFee === null) {
4764
+ throw new MalformedArkInfoSnapshotError(`${path}.intentFee must be an object`);
4765
+ }
4766
+ }
4767
+ function parseStoredArkInfoSnapshot(raw) {
4768
+ if (typeof raw !== "object" || raw === null) {
4769
+ throw new MalformedArkInfoSnapshotError("snapshot must be an object");
4770
+ }
4771
+ const snap = raw;
4772
+ if (snap.version !== CURRENT_VERSION) {
4773
+ throw new MalformedArkInfoSnapshotError(
4774
+ `unsupported snapshot version: ${String(snap.version)}`
4775
+ );
4776
+ }
4777
+ if (typeof snap.savedAt !== "number") {
4778
+ throw new MalformedArkInfoSnapshotError("savedAt must be a number");
4779
+ }
4780
+ if (snap.source !== "arkade.getInfo") {
4781
+ throw new MalformedArkInfoSnapshotError(`unexpected source: ${String(snap.source)}`);
4782
+ }
4783
+ if (typeof snap.arkInfo !== "object" || snap.arkInfo === null) {
4784
+ throw new MalformedArkInfoSnapshotError("arkInfo must be an object");
4785
+ }
4786
+ const a = snap.arkInfo;
4787
+ for (const field of [
4788
+ "network",
4789
+ "signerPubkey",
4790
+ "checkpointTapscript",
4791
+ "forfeitAddress",
4792
+ "forfeitPubkey",
4793
+ "digest",
4794
+ "version"
4795
+ ]) {
4796
+ assertString(a[field], `arkInfo.${field}`);
4797
+ }
4798
+ for (const field of [
4799
+ "unilateralExitDelay",
4800
+ "boardingExitDelay",
4801
+ "sessionDuration",
4802
+ "dust",
4803
+ "vtxoMinAmount",
4804
+ "vtxoMaxAmount",
4805
+ "utxoMinAmount",
4806
+ "utxoMaxAmount"
4807
+ ]) {
4808
+ assertDecimalString(a[field], `arkInfo.${field}`);
4809
+ }
4810
+ assertFeeInfo(a.fees, "arkInfo.fees");
4811
+ if (!Array.isArray(a.deprecatedSigners)) {
4812
+ throw new MalformedArkInfoSnapshotError("arkInfo.deprecatedSigners must be an array");
4813
+ }
4814
+ a.deprecatedSigners.forEach((s, i) => {
4815
+ if (typeof s !== "object" || s === null) {
4816
+ throw new MalformedArkInfoSnapshotError(
4817
+ `arkInfo.deprecatedSigners[${i}] must be an object`
4818
+ );
4819
+ }
4820
+ const signer = s;
4821
+ assertString(signer.pubkey, `arkInfo.deprecatedSigners[${i}].pubkey`);
4822
+ assertDecimalString(signer.cutoffDate, `arkInfo.deprecatedSigners[${i}].cutoffDate`);
4823
+ });
4824
+ if (a.scheduledSession !== void 0) {
4825
+ if (typeof a.scheduledSession !== "object" || a.scheduledSession === null) {
4826
+ throw new MalformedArkInfoSnapshotError("arkInfo.scheduledSession must be an object");
4827
+ }
4828
+ const s = a.scheduledSession;
4829
+ for (const field of ["duration", "nextEndTime", "nextStartTime", "period"]) {
4830
+ assertDecimalString(s[field], `arkInfo.scheduledSession.${field}`);
4831
+ }
4832
+ assertFeeInfo(s.fees, "arkInfo.scheduledSession.fees");
4833
+ }
4834
+ return raw;
4835
+ }
4836
+ async function loadArkInfoSnapshot(repo) {
4837
+ const state = await repo.getWalletState();
4838
+ const raw = state?.settings?.[ARK_INFO_SNAPSHOT_KEY];
4839
+ if (raw === void 0 || raw === null) return null;
4840
+ return parseStoredArkInfoSnapshot(raw);
4841
+ }
4842
+ async function saveArkInfoSnapshot(repo, info, savedAt) {
4843
+ const snapshot = serializeArkInfoSnapshot(info, savedAt);
4844
+ await updateWalletState(repo, (state) => ({
4845
+ ...state,
4846
+ settings: {
4847
+ ...state.settings ?? {},
4848
+ [ARK_INFO_SNAPSHOT_KEY]: snapshot
4849
+ }
4850
+ }));
4851
+ }
4852
+ async function resolveArkInfo(arkProvider, walletRepository) {
4853
+ let info;
4854
+ try {
4855
+ info = await arkProvider.getInfo();
4856
+ } catch (err) {
4857
+ if (!isRetryableProviderError(err)) throw err;
4858
+ const snapshot = await loadArkInfoSnapshot(walletRepository);
4859
+ if (!snapshot) {
4860
+ throw new ProviderUnavailableError(
4861
+ "Arkade server info is unavailable and no cached snapshot exists",
4862
+ { cause: err }
4863
+ );
4864
+ }
4865
+ return { info: hydrateArkInfo(snapshot), source: "cache", lastOnlineAt: snapshot.savedAt };
4866
+ }
4867
+ return { info, source: "live" };
4868
+ }
4869
+ async function saveValidatedArkInfoSnapshot(repo, info, savedAt) {
4870
+ try {
4871
+ await saveArkInfoSnapshot(repo, info, savedAt);
4872
+ } catch (err) {
4873
+ console.warn("Failed to persist Ark info snapshot", err);
4874
+ }
4875
+ }
4290
4876
  var TxTree = class {
4291
4877
  constructor(root, children = /* @__PURE__ */ new Map()) {
4292
4878
  this.root = root;
@@ -5396,20 +5982,6 @@ function isAnnotated(v) {
5396
5982
  return v.tapTree !== void 0 && v.forfeitTapLeafScript !== void 0 && v.intentTapLeafScript !== void 0;
5397
5983
  }
5398
5984
 
5399
- // src/repositories/virtualTxRepository.ts
5400
- var ChainedTxType = /* @__PURE__ */ ((ChainedTxType2) => {
5401
- ChainedTxType2[ChainedTxType2["Unspecified"] = 0] = "Unspecified";
5402
- ChainedTxType2[ChainedTxType2["Commitment"] = 1] = "Commitment";
5403
- ChainedTxType2[ChainedTxType2["Ark"] = 2] = "Ark";
5404
- ChainedTxType2[ChainedTxType2["Tree"] = 3] = "Tree";
5405
- ChainedTxType2[ChainedTxType2["Checkpoint"] = 4] = "Checkpoint";
5406
- return ChainedTxType2;
5407
- })(ChainedTxType || {});
5408
- function mergeChainedTxType(incoming, prev) {
5409
- if (incoming !== 0 /* Unspecified */) return incoming;
5410
- return prev ?? 0 /* Unspecified */;
5411
- }
5412
-
5413
5985
  // src/repositories/inMemory/intentRepository.ts
5414
5986
  var InMemoryIntentRepository = class {
5415
5987
  version = 1;
@@ -7784,106 +8356,49 @@ async function reconcileIntents(deps) {
7784
8356
  console.error("reconcileIntents: failed to read non-terminal intents", e);
7785
8357
  return;
7786
8358
  }
7787
- if (intents.length === 0) return;
7788
- const outpoints = dedupeOutpoints(intents.flatMap((i) => i.intentVtxos));
7789
- let vtxosByOutpoint = /* @__PURE__ */ new Map();
7790
- if (outpoints.length > 0) {
7791
- try {
7792
- const { vtxos } = await deps.indexerProvider.getVtxos({ outpoints });
7793
- vtxosByOutpoint = new Map(vtxos.map((v) => [outpointKey(v), v]));
7794
- } catch (e) {
7795
- console.error("reconcileIntents: failed to fetch input VTXO state", e);
7796
- return;
7797
- }
7798
- }
7799
- const nowMs = now();
7800
- for (const intent of intents) {
7801
- try {
7802
- const next = await classifyIntent(intent, vtxosByOutpoint, nowMs);
7803
- if (!next) continue;
7804
- const [fresh] = await deps.intentRepository.getIntents({
7805
- intentTxIds: [intent.intentTxId]
7806
- });
7807
- if (!fresh || fresh.state !== intent.state) continue;
7808
- await deps.intentRepository.saveIntent(next);
7809
- } catch (e) {
7810
- console.error(`reconcileIntents: failed to reconcile intent ${intent.intentTxId}`, e);
7811
- }
7812
- }
7813
- }
7814
- function terminal(intent, state, now, patch) {
7815
- return { ...intent, ...patch, state, updatedAt: now };
7816
- }
7817
- function outpointKey(o) {
7818
- return `${o.txid}:${o.vout}`;
7819
- }
7820
- function dedupeOutpoints(outpoints) {
7821
- const seen = /* @__PURE__ */ new Set();
7822
- const out = [];
7823
- for (const o of outpoints) {
7824
- const k = outpointKey(o);
7825
- if (seen.has(k)) continue;
7826
- seen.add(k);
7827
- out.push(o);
7828
- }
7829
- return out;
7830
- }
7831
-
7832
- // src/utils/syncCursors.ts
7833
- var SAFETY_LAG_MS = 3e4;
7834
- var OVERLAP_MS = 24 * 60 * 60 * 1e3;
7835
- var walletStateLocks = /* @__PURE__ */ new WeakMap();
7836
- async function updateWalletState(repo, updater) {
7837
- const prev = walletStateLocks.get(repo) ?? Promise.resolve();
7838
- const op = prev.then(async () => {
7839
- const state = await repo.getWalletState() ?? {};
7840
- await repo.saveWalletState(updater(state));
7841
- });
7842
- walletStateLocks.set(
7843
- repo,
7844
- op.catch(() => {
7845
- })
7846
- );
7847
- return op;
7848
- }
7849
- var CURSOR_MIGRATED_KEY = "vtxoCursorMigrated";
7850
- function hasMigrationMarker(state) {
7851
- return state?.settings?.[CURSOR_MIGRATED_KEY] === true;
7852
- }
7853
- async function getSyncCursor(repo) {
7854
- const state = await repo.getWalletState();
7855
- if (!hasMigrationMarker(state)) return 0;
7856
- return state?.lastSyncTime ?? 0;
7857
- }
7858
- async function advanceSyncCursor(repo, lastUpdatedAt) {
7859
- await updateWalletState(repo, (state) => {
7860
- const current = hasMigrationMarker(state) ? state.lastSyncTime ?? 0 : 0;
7861
- return {
7862
- ...state,
7863
- lastSyncTime: Math.max(current, lastUpdatedAt),
7864
- settings: {
7865
- ...state.settings ?? {},
7866
- [CURSOR_MIGRATED_KEY]: true
7867
- }
7868
- };
7869
- });
8359
+ if (intents.length === 0) return;
8360
+ const outpoints = dedupeOutpoints(intents.flatMap((i) => i.intentVtxos));
8361
+ let vtxosByOutpoint = /* @__PURE__ */ new Map();
8362
+ if (outpoints.length > 0) {
8363
+ try {
8364
+ const { vtxos } = await deps.indexerProvider.getVtxos({ outpoints });
8365
+ vtxosByOutpoint = new Map(vtxos.map((v) => [outpointKey(v), v]));
8366
+ } catch (e) {
8367
+ console.error("reconcileIntents: failed to fetch input VTXO state", e);
8368
+ return;
8369
+ }
8370
+ }
8371
+ const nowMs = now();
8372
+ for (const intent of intents) {
8373
+ try {
8374
+ const next = await classifyIntent(intent, vtxosByOutpoint, nowMs);
8375
+ if (!next) continue;
8376
+ const [fresh] = await deps.intentRepository.getIntents({
8377
+ intentTxIds: [intent.intentTxId]
8378
+ });
8379
+ if (!fresh || fresh.state !== intent.state) continue;
8380
+ await deps.intentRepository.saveIntent(next);
8381
+ } catch (e) {
8382
+ console.error(`reconcileIntents: failed to reconcile intent ${intent.intentTxId}`, e);
8383
+ }
8384
+ }
7870
8385
  }
7871
- async function clearSyncCursor(repo) {
7872
- await updateWalletState(repo, (state) => {
7873
- const { [CURSOR_MIGRATED_KEY]: _, ...restSettings } = state.settings ?? {};
7874
- return {
7875
- ...state,
7876
- lastSyncTime: void 0,
7877
- settings: restSettings
7878
- };
7879
- });
8386
+ function terminal(intent, state, now, patch) {
8387
+ return { ...intent, ...patch, state, updatedAt: now };
7880
8388
  }
7881
- function computeSyncWindow(cursor) {
7882
- const after = Math.max(0, cursor - OVERLAP_MS);
7883
- return { after };
8389
+ function outpointKey(o) {
8390
+ return `${o.txid}:${o.vout}`;
7884
8391
  }
7885
- function cursorCutoff(requestStartedAt) {
7886
- return (requestStartedAt ?? Date.now()) - SAFETY_LAG_MS;
8392
+ function dedupeOutpoints(outpoints) {
8393
+ const seen = /* @__PURE__ */ new Set();
8394
+ const out = [];
8395
+ for (const o of outpoints) {
8396
+ const k = outpointKey(o);
8397
+ if (seen.has(k)) continue;
8398
+ seen.add(k);
8399
+ out.push(o);
8400
+ }
8401
+ return out;
7887
8402
  }
7888
8403
 
7889
8404
  // src/contracts/contractManager.ts
@@ -7898,6 +8413,10 @@ var ContractManager = class _ContractManager {
7898
8413
  initialized = false;
7899
8414
  eventCallbacks = /* @__PURE__ */ new Set();
7900
8415
  stopWatcherFn;
8416
+ /** `undefined` while online; the failure reason once a sync degrades. */
8417
+ syncDegradedReason;
8418
+ /** Epoch-ms of the last successful provider sync, if any. */
8419
+ lastSyncedAt;
7901
8420
  constructor(config) {
7902
8421
  this.config = config;
7903
8422
  this.watcher = new ContractWatcher({
@@ -7920,6 +8439,26 @@ var ContractManager = class _ContractManager {
7920
8439
  await cm.initialize();
7921
8440
  return cm;
7922
8441
  }
8442
+ /**
8443
+ * Latest provider-sync health. See {@link ContractSyncState}. Degradation is
8444
+ * recorded by {@link initialize}, {@link getContractsWithVtxos}, and
8445
+ * {@link createContract}; it flips back to `online` on the next successful
8446
+ * sync. Purely a freshness signal — not a source of truth for wallet data.
8447
+ */
8448
+ getSyncState() {
8449
+ return this.syncDegradedReason === void 0 ? { mode: "online", lastSyncedAt: this.lastSyncedAt } : {
8450
+ mode: "degraded",
8451
+ reason: this.syncDegradedReason,
8452
+ lastSyncedAt: this.lastSyncedAt
8453
+ };
8454
+ }
8455
+ markSyncOnline() {
8456
+ this.syncDegradedReason = void 0;
8457
+ this.lastSyncedAt = Date.now();
8458
+ }
8459
+ markSyncDegraded(err) {
8460
+ this.syncDegradedReason = err instanceof Error ? err.message : String(err);
8461
+ }
7923
8462
  async initialize() {
7924
8463
  if (this.initialized) {
7925
8464
  return;
@@ -7928,7 +8467,13 @@ var ContractManager = class _ContractManager {
7928
8467
  for (const contract of contracts) {
7929
8468
  await this.watcher.addContract(contract);
7930
8469
  }
7931
- await this.reconcileWatched();
8470
+ try {
8471
+ await this.reconcileWatched();
8472
+ this.markSyncOnline();
8473
+ } catch (err) {
8474
+ if (!isRetryableProviderError(err)) throw err;
8475
+ this.markSyncDegraded(err);
8476
+ }
7932
8477
  this.initialized = true;
7933
8478
  this.stopWatcherFn = await this.watcher.startWatching((event) => {
7934
8479
  this.handleContractEvent(event).catch((error) => {
@@ -7982,7 +8527,13 @@ var ContractManager = class _ContractManager {
7982
8527
  async createContract(params) {
7983
8528
  const { contract, persisted } = await this.upsertContract(params);
7984
8529
  if (persisted) {
7985
- await this.fetchContractVxosFromIndexer([contract]);
8530
+ try {
8531
+ await this.fetchContractVxosFromIndexer([contract]);
8532
+ this.markSyncOnline();
8533
+ } catch (err) {
8534
+ if (!isRetryableProviderError(err)) throw err;
8535
+ this.markSyncDegraded(err);
8536
+ }
7986
8537
  await this.watcher.addContract(contract);
7987
8538
  }
7988
8539
  return contract;
@@ -8181,7 +8732,13 @@ var ContractManager = class _ContractManager {
8181
8732
  }
8182
8733
  async getContractsWithVtxos(filter, pageSize) {
8183
8734
  const contracts = await this.getContracts(filter);
8184
- await this.syncContracts({ contracts, pageSize });
8735
+ try {
8736
+ await this.syncContracts({ contracts, pageSize });
8737
+ this.markSyncOnline();
8738
+ } catch (err) {
8739
+ if (!isRetryableProviderError(err)) throw err;
8740
+ this.markSyncDegraded(err);
8741
+ }
8185
8742
  const vtxos = await this.getVtxosForContracts(contracts);
8186
8743
  return contracts.map((contract) => ({
8187
8744
  contract,
@@ -8419,15 +8976,33 @@ var ContractManager = class _ContractManager {
8419
8976
  * Handle events from the watcher.
8420
8977
  */
8421
8978
  async handleContractEvent(event) {
8422
- switch (event.type) {
8423
- // Delta-sync only the changed virtual outputs for this contract.
8424
- case "vtxo_received":
8425
- case "vtxo_spent":
8426
- await this.syncContracts({ contracts: [event.contract] });
8427
- break;
8428
- case "connection_reset":
8429
- await this.reconcileWatched();
8430
- break;
8979
+ try {
8980
+ switch (event.type) {
8981
+ // Delta-sync only the changed virtual outputs for this contract.
8982
+ case "vtxo_received":
8983
+ await this.syncContracts({ contracts: [event.contract] });
8984
+ this.markSyncOnline();
8985
+ break;
8986
+ case "vtxo_spent":
8987
+ await this.syncContracts({ contracts: [event.contract] });
8988
+ this.markSyncOnline();
8989
+ if (this.config.onVtxosSpent) {
8990
+ try {
8991
+ await this.config.onVtxosSpent(
8992
+ event.vtxos.map((v) => ({ txid: v.txid, vout: v.vout }))
8993
+ );
8994
+ } catch {
8995
+ }
8996
+ }
8997
+ break;
8998
+ case "connection_reset":
8999
+ await this.reconcileWatched();
9000
+ this.markSyncOnline();
9001
+ break;
9002
+ }
9003
+ } catch (err) {
9004
+ if (!isRetryableProviderError(err)) throw err;
9005
+ this.markSyncDegraded(err);
8431
9006
  }
8432
9007
  this.emitEvent(event);
8433
9008
  }
@@ -8509,6 +9084,12 @@ var ContractManager = class _ContractManager {
8509
9084
  contract,
8510
9085
  filtered
8511
9086
  );
9087
+ if (this.config.onVtxosPersisted) {
9088
+ try {
9089
+ await this.config.onVtxosPersisted(contract, filtered);
9090
+ } catch {
9091
+ }
9092
+ }
8512
9093
  }
8513
9094
  }
8514
9095
  async fetchContractVxosFromIndexer(contracts, pageSize, syncWindow) {
@@ -8529,6 +9110,15 @@ var ContractManager = class _ContractManager {
8529
9110
  contract,
8530
9111
  filtered
8531
9112
  );
9113
+ if (this.config.onVtxosPersisted) {
9114
+ try {
9115
+ await this.config.onVtxosPersisted(
9116
+ contract,
9117
+ filtered
9118
+ );
9119
+ } catch {
9120
+ }
9121
+ }
8532
9122
  }
8533
9123
  }
8534
9124
  return result;
@@ -9402,6 +9992,8 @@ var ReadonlyWallet = class _ReadonlyWallet {
9402
9992
  * (ContractManager isn't given it); `undefined` ⇒ no-op.
9403
9993
  */
9404
9994
  virtualTxRepository;
9995
+ /** Opt-in exit-data capture settings; see {@link StorageConfig.exitDataCapture}. */
9996
+ exitDataCapture;
9405
9997
  _assetManager;
9406
9998
  walletContractTimelocks;
9407
9999
  // Outpoints ("txid:vout") committed to an in-flight settle/send. Filtered
@@ -9444,6 +10036,72 @@ var ReadonlyWallet = class _ReadonlyWallet {
9444
10036
  * construction-time snapshot for their lifetime.
9445
10037
  */
9446
10038
  _arkServerPublicKey;
10039
+ /**
10040
+ * Whether this wallet was constructed from live operator server-info
10041
+ * (`"live"`) or from a cached snapshot because the operator was unreachable
10042
+ * (`"cache"`). Freshness signal for {@link getProviderConnectionState}.
10043
+ */
10044
+ _serverInfoSource = "live";
10045
+ /**
10046
+ * Epoch-ms of the last known live operator contact: construction time on the
10047
+ * `live` boot path, the cached snapshot's `savedAt` on the `cache` path.
10048
+ */
10049
+ _serverInfoLastOnlineAt;
10050
+ /** @see {@link _serverInfoSource} */
10051
+ get serverInfoSource() {
10052
+ return this._serverInfoSource;
10053
+ }
10054
+ /**
10055
+ * Composed provider-connection freshness: the boot server-info source
10056
+ * (Arkade) combined with the contract-manager's indexer-sync health, if the
10057
+ * manager has been initialized. Reads no live provider state — it never
10058
+ * forces a `ContractManager` to construct — so it is safe for readonly
10059
+ * callers that only use address/balance APIs.
10060
+ *
10061
+ * - Boot fell back to a cached snapshot → degraded on `arkade` (`cache`).
10062
+ * - Otherwise, if the contract manager has degraded to repository data →
10063
+ * degraded on `indexer` (`repository`).
10064
+ * - Otherwise online.
10065
+ *
10066
+ * This only describes sync freshness; wallet balances/VTXOs are always read
10067
+ * from the repository regardless of this state.
10068
+ */
10069
+ getProviderConnectionState() {
10070
+ if (this._serverInfoSource === "cache") {
10071
+ return {
10072
+ mode: "degraded",
10073
+ source: "cache",
10074
+ provider: "arkade",
10075
+ reason: "constructed from cached server-info; operator was unreachable at boot",
10076
+ lastOnlineAt: this._serverInfoLastOnlineAt
10077
+ };
10078
+ }
10079
+ const sync = this._contractManager?.getSyncState();
10080
+ if (sync?.mode === "degraded") {
10081
+ return {
10082
+ mode: "degraded",
10083
+ source: "repository",
10084
+ provider: "indexer",
10085
+ reason: sync.reason,
10086
+ lastOnlineAt: sync.lastSyncedAt ?? this._serverInfoLastOnlineAt
10087
+ };
10088
+ }
10089
+ return {
10090
+ mode: "online",
10091
+ source: "live",
10092
+ lastOnlineAt: sync?.lastSyncedAt ?? this._serverInfoLastOnlineAt ?? 0
10093
+ };
10094
+ }
10095
+ /**
10096
+ * The contract-manager's current provider-sync health **without forcing it
10097
+ * to initialize** — reads the already-constructed manager, or reports
10098
+ * `online` when none exists yet. Unlike {@link getContractManager}, this
10099
+ * never triggers a remote sync, so it is safe on a pure diagnostics path
10100
+ * (e.g. the service-worker sync-state message).
10101
+ */
10102
+ getContractSyncState() {
10103
+ return this._contractManager?.getSyncState() ?? { mode: "online" };
10104
+ }
9447
10105
  /**
9448
10106
  * x-only hex of the operator's deprecated signer keys (from
9449
10107
  * `ArkInfo.deprecatedSigners`), cached for the OFFLINE read/watch paths.
@@ -9578,7 +10236,13 @@ var ReadonlyWallet = class _ReadonlyWallet {
9578
10236
  }
9579
10237
  indexerProvider = new RestIndexerProvider(indexerUrl);
9580
10238
  }
9581
- const info = await arkProvider.getInfo();
10239
+ const walletRepository = config.storage?.walletRepository ?? new IndexedDBWalletRepository();
10240
+ const contractRepository = config.storage?.contractRepository ?? new IndexedDBContractRepository();
10241
+ const {
10242
+ info,
10243
+ source: serverInfoSource,
10244
+ lastOnlineAt: serverInfoLastOnlineAt
10245
+ } = await resolveArkInfo(arkProvider, walletRepository);
9582
10246
  const network = getNetwork(info.network);
9583
10247
  if ("descriptor" in config.identity) {
9584
10248
  const descriptor = config.identity.descriptor;
@@ -9632,8 +10296,6 @@ var ReadonlyWallet = class _ReadonlyWallet {
9632
10296
  serverPubKey: hex.encode(serverPubKey),
9633
10297
  csvTimelock: timelockToSequence(boardingTimelock).toString()
9634
10298
  });
9635
- const walletRepository = config.storage?.walletRepository ?? new IndexedDBWalletRepository();
9636
- const contractRepository = config.storage?.contractRepository ?? new IndexedDBContractRepository();
9637
10299
  return {
9638
10300
  arkProvider,
9639
10301
  indexerProvider,
@@ -9647,6 +10309,8 @@ var ReadonlyWallet = class _ReadonlyWallet {
9647
10309
  walletRepository,
9648
10310
  contractRepository,
9649
10311
  info,
10312
+ serverInfoSource,
10313
+ serverInfoLastOnlineAt,
9650
10314
  delegateProvider: config.delegateProvider || config.delegatorProvider,
9651
10315
  /** @deprecated alias for `delegateProvider` */
9652
10316
  delegatorProvider: config.delegateProvider || config.delegatorProvider,
@@ -9682,6 +10346,15 @@ var ReadonlyWallet = class _ReadonlyWallet {
9682
10346
  );
9683
10347
  wallet.intentRepository = config.storage?.intentRepository;
9684
10348
  wallet.virtualTxRepository = config.storage?.virtualTxRepository;
10349
+ wallet.exitDataCapture = config.storage?.exitDataCapture;
10350
+ wallet._serverInfoSource = setup.serverInfoSource;
10351
+ if (setup.serverInfoSource === "live") {
10352
+ const now = Date.now();
10353
+ await saveValidatedArkInfoSnapshot(setup.walletRepository, setup.info, now);
10354
+ wallet._serverInfoLastOnlineAt = now;
10355
+ } else {
10356
+ wallet._serverInfoLastOnlineAt = setup.serverInfoLastOnlineAt;
10357
+ }
9685
10358
  wallet.refreshDeprecatedSigners(setup.info);
9686
10359
  return wallet;
9687
10360
  }
@@ -9812,7 +10485,10 @@ var ReadonlyWallet = class _ReadonlyWallet {
9812
10485
  const response = await contractManager.getContractsWithVtxos();
9813
10486
  const allVtxos = response.flatMap((_) => _.vtxos);
9814
10487
  const { boardingTxs, commitmentsToIgnore } = await this.getBoardingTxs();
9815
- const getTxCreatedAt = (txid) => this.indexerProvider.getVtxos({ outpoints: [{ txid, vout: 0 }] }).then((res) => res.vtxos[0]?.createdAt.getTime());
10488
+ const getTxCreatedAt = (txid) => this.indexerProvider.getVtxos({ outpoints: [{ txid, vout: 0 }] }).then((res) => res.vtxos[0]?.createdAt.getTime()).catch((err) => {
10489
+ if (isRetryableProviderError(err)) return void 0;
10490
+ throw err;
10491
+ });
9816
10492
  return buildTransactionHistory(allVtxos, boardingTxs, commitmentsToIgnore, getTxCreatedAt);
9817
10493
  }
9818
10494
  /**
@@ -10231,11 +10907,39 @@ var ReadonlyWallet = class _ReadonlyWallet {
10231
10907
  }
10232
10908
  }
10233
10909
  async initializeContractManager() {
10910
+ const virtualTxRepository = this.virtualTxRepository;
10911
+ let onVtxosPersisted;
10912
+ let onVtxosSpent;
10913
+ if (virtualTxRepository) {
10914
+ const capture = this.exitDataCapture;
10915
+ const resolver = createExitChainResolver({
10916
+ indexer: this.indexerProvider,
10917
+ repository: virtualTxRepository,
10918
+ extraSources: capture?.sources
10919
+ });
10920
+ onVtxosPersisted = async (_contract, vtxos) => {
10921
+ for (const v of vtxos) {
10922
+ if (v.virtualStatus.state === "spent") continue;
10923
+ await captureExitBranch({
10924
+ resolver,
10925
+ repository: virtualTxRepository,
10926
+ vtxo: { txid: v.txid, vout: v.vout },
10927
+ value: v.value,
10928
+ mode: capture?.mode ?? DEFAULT_EXIT_CAPTURE_MODE,
10929
+ minExitWorthSats: capture?.minExitWorthSats ?? DEFAULT_MIN_EXIT_WORTH_SATS
10930
+ }).catch(() => {
10931
+ });
10932
+ }
10933
+ };
10934
+ onVtxosSpent = (vtxos) => pruneExitBranches(virtualTxRepository, vtxos);
10935
+ }
10234
10936
  const manager = await ContractManager.create({
10235
10937
  indexerProvider: this.indexerProvider,
10236
10938
  contractRepository: this.contractRepository,
10237
10939
  walletRepository: this.walletRepository,
10238
10940
  intentRepository: this.intentRepository,
10941
+ onVtxosPersisted,
10942
+ onVtxosSpent,
10239
10943
  watcherConfig: this.watcherConfig
10240
10944
  });
10241
10945
  const baselinePubkey = await this.identity.xOnlyPublicKey();
@@ -10910,6 +11614,14 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
10910
11614
  boot?.rotator,
10911
11615
  boot?.provider
10912
11616
  );
11617
+ wallet._serverInfoSource = setup.serverInfoSource;
11618
+ if (setup.serverInfoSource === "live") {
11619
+ const now = Date.now();
11620
+ await saveValidatedArkInfoSnapshot(setup.walletRepository, setup.info, now);
11621
+ wallet._serverInfoLastOnlineAt = now;
11622
+ } else {
11623
+ wallet._serverInfoLastOnlineAt = setup.serverInfoLastOnlineAt;
11624
+ }
10913
11625
  wallet.refreshDeprecatedSigners(setup.info);
10914
11626
  {
10915
11627
  const ap = setup.arkProvider;
@@ -10931,6 +11643,7 @@ var Wallet2 = class _Wallet extends ReadonlyWallet {
10931
11643
  }
10932
11644
  wallet.intentRepository = config.storage?.intentRepository;
10933
11645
  wallet.virtualTxRepository = config.storage?.virtualTxRepository;
11646
+ wallet.exitDataCapture = config.storage?.exitDataCapture;
10934
11647
  await wallet.getVtxoManager();
10935
11648
  return wallet;
10936
11649
  }
@@ -13448,10 +14161,18 @@ var WalletMessageHandler = class {
13448
14161
  type: "WALLET_STATUS",
13449
14162
  payload: {
13450
14163
  walletInitialized: true,
13451
- xOnlyPublicKey: pubKey
14164
+ xOnlyPublicKey: pubKey,
14165
+ providerConnectionState: this.readonlyWallet.getProviderConnectionState()
13452
14166
  }
13453
14167
  });
13454
14168
  }
14169
+ case "GET_CONTRACT_SYNC_STATE": {
14170
+ return this.tagged({
14171
+ id,
14172
+ type: "CONTRACT_SYNC_STATE",
14173
+ payload: { syncState: this.readonlyWallet.getContractSyncState() }
14174
+ });
14175
+ }
13455
14176
  case "CLEAR": {
13456
14177
  await this.clear();
13457
14178
  return this.tagged({
@@ -14214,6 +14935,7 @@ var DEFAULT_MESSAGE_TIMEOUTS = {
14214
14935
  GET_BALANCE: 1e4,
14215
14936
  GET_BOARDING_ADDRESS: 1e4,
14216
14937
  GET_STATUS: 1e4,
14938
+ GET_CONTRACT_SYNC_STATE: 1e4,
14217
14939
  GET_DELEGATE_INFO: 1e4,
14218
14940
  IS_CONTRACT_MANAGER_WATCHING: 1e4,
14219
14941
  // Medium reads — may involve indexer queries
@@ -14822,6 +15544,19 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
14822
15544
  throw new Error(`Failed to get status: ${error}`);
14823
15545
  }
14824
15546
  }
15547
+ /**
15548
+ * Wallet-level provider-connection freshness, delegated to the worker via
15549
+ * `GET_STATUS`. Async by necessity (the worker boundary is asynchronous); no
15550
+ * synchronous variant is offered because it would have the same transport
15551
+ * mismatch as the contract-manager proxy's cached `getSyncState()`.
15552
+ */
15553
+ async getProviderConnectionState() {
15554
+ const { providerConnectionState } = await this.getStatus();
15555
+ if (!providerConnectionState) {
15556
+ throw new Error("Worker did not report provider connection state");
15557
+ }
15558
+ return providerConnectionState;
15559
+ }
14825
15560
  async getActivityHistory() {
14826
15561
  return buildActivities(await this.getTransactionHistory(), this.activity.all());
14827
15562
  }
@@ -14876,6 +15611,32 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
14876
15611
  return wallet.sendMessage(message);
14877
15612
  };
14878
15613
  const messageTag = this.messageTag;
15614
+ const fetchSyncState = async () => {
15615
+ const message = {
15616
+ type: "GET_CONTRACT_SYNC_STATE",
15617
+ id: getRandomId(),
15618
+ tag: messageTag
15619
+ };
15620
+ const response = await sendContractMessage(message);
15621
+ return response.payload.syncState;
15622
+ };
15623
+ const UNKNOWN_STATE = {
15624
+ mode: "degraded",
15625
+ reason: "contract sync state unavailable from the worker"
15626
+ };
15627
+ let syncState = UNKNOWN_STATE;
15628
+ let everProbed = false;
15629
+ const refreshSyncState = async () => {
15630
+ try {
15631
+ syncState = await fetchSyncState();
15632
+ everProbed = true;
15633
+ } catch {
15634
+ if (!everProbed) {
15635
+ syncState = UNKNOWN_STATE;
15636
+ }
15637
+ }
15638
+ };
15639
+ await refreshSyncState();
14879
15640
  const manager = {
14880
15641
  async createContract(params) {
14881
15642
  const message = {
@@ -14886,6 +15647,7 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
14886
15647
  };
14887
15648
  try {
14888
15649
  const response = await sendContractMessage(message);
15650
+ await refreshSyncState();
14889
15651
  return response.payload.contract;
14890
15652
  } catch (e) {
14891
15653
  throw new Error("Failed to create contract");
@@ -14914,11 +15676,15 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
14914
15676
  };
14915
15677
  try {
14916
15678
  const response = await sendContractMessage(message);
15679
+ await refreshSyncState();
14917
15680
  return response.payload.contracts;
14918
15681
  } catch (e) {
14919
15682
  throw new Error("Failed to get contracts with vtxos");
14920
15683
  }
14921
15684
  },
15685
+ getSyncState() {
15686
+ return syncState;
15687
+ },
14922
15688
  async annotateVtxos(vtxos) {
14923
15689
  if (vtxos.length === 0) return [];
14924
15690
  const message = {
@@ -15027,7 +15793,11 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
15027
15793
  tag: messageTag,
15028
15794
  payload: opts
15029
15795
  };
15030
- await sendContractMessage(message);
15796
+ try {
15797
+ await sendContractMessage(message);
15798
+ } finally {
15799
+ await refreshSyncState();
15800
+ }
15031
15801
  },
15032
15802
  async refreshOutpoints(outpoints) {
15033
15803
  const message = {
@@ -15036,7 +15806,11 @@ var ServiceWorkerReadonlyWallet = class _ServiceWorkerReadonlyWallet {
15036
15806
  tag: messageTag,
15037
15807
  payload: { outpoints }
15038
15808
  };
15039
- await sendContractMessage(message);
15809
+ try {
15810
+ await sendContractMessage(message);
15811
+ } finally {
15812
+ await refreshSyncState();
15813
+ }
15040
15814
  },
15041
15815
  scanContracts() {
15042
15816
  return Promise.reject(
@@ -16651,7 +17425,7 @@ async function resolveUnilateralPath(params) {
16651
17425
  }
16652
17426
 
16653
17427
  // src/wallet/unroll.ts
16654
- function chainTxTypeToChainedExit(t) {
17428
+ function chainTxTypeToChainedExit2(t) {
16655
17429
  switch (t) {
16656
17430
  case "INDEXER_CHAINED_TX_TYPE_COMMITMENT" /* COMMITMENT */:
16657
17431
  return 1 /* Commitment */;
@@ -16714,7 +17488,7 @@ var Unroll;
16714
17488
  txid: next.txid,
16715
17489
  psbt,
16716
17490
  expiresAt: null,
16717
- type: chainTxTypeToChainedExit(next.type)
17491
+ type: chainTxTypeToChainedExit2(next.type)
16718
17492
  };
16719
17493
  try {
16720
17494
  await repo.upsertVirtualTxs([cached]);
@@ -16892,99 +17666,6 @@ function doWait(onchainProvider, txid) {
16892
17666
  });
16893
17667
  };
16894
17668
  }
16895
-
16896
- // src/wallet/exit/chain.ts
16897
- var isCommitment = (t) => t === "INDEXER_CHAINED_TX_TYPE_COMMITMENT" /* COMMITMENT */ || t === "INDEXER_CHAINED_TX_TYPE_UNSPECIFIED" /* UNSPECIFIED */;
16898
- async function buildExitDag(params) {
16899
- const byTxid = /* @__PURE__ */ new Map();
16900
- for (const vtxo of params.vtxos) {
16901
- const outpoint = `${vtxo.txid}:${vtxo.vout}`;
16902
- let pageIndex = 0;
16903
- let hasMore = true;
16904
- while (hasMore) {
16905
- const { chain, page } = await params.indexer.getVtxoChain(
16906
- { txid: vtxo.txid, vout: vtxo.vout },
16907
- { pageIndex, pageSize: DEFAULT_PAGE_SIZE }
16908
- );
16909
- for (const chainTx of chain) {
16910
- const existing = byTxid.get(chainTx.txid);
16911
- if (existing) {
16912
- existing.forVtxos.add(outpoint);
16913
- } else {
16914
- byTxid.set(chainTx.txid, { ...chainTx, forVtxos: /* @__PURE__ */ new Set([outpoint]) });
16915
- }
16916
- }
16917
- hasMore = page ? chain.length === DEFAULT_PAGE_SIZE : false;
16918
- pageIndex++;
16919
- }
16920
- }
16921
- const pending = new Map(
16922
- [...byTxid.values()].filter((tx) => !isCommitment(tx.type)).map((tx) => [tx.txid, tx])
16923
- );
16924
- const inDegree = /* @__PURE__ */ new Map();
16925
- for (const tx of pending.values()) {
16926
- const parents = tx.spends.filter((p) => pending.has(p));
16927
- inDegree.set(tx.txid, parents.length);
16928
- }
16929
- const order = [];
16930
- const queue = [...pending.values()].filter((tx) => inDegree.get(tx.txid) === 0).sort((a, b) => a.txid.localeCompare(b.txid));
16931
- while (queue.length > 0) {
16932
- const tx = queue.shift();
16933
- order.push(tx);
16934
- const children = [...pending.values()].filter((c) => c.spends.includes(tx.txid)).sort((a, b) => a.txid.localeCompare(b.txid));
16935
- for (const child of children) {
16936
- const deg = inDegree.get(child.txid) - 1;
16937
- inDegree.set(child.txid, deg);
16938
- if (deg === 0) queue.push(child);
16939
- }
16940
- }
16941
- if (order.length !== pending.size) {
16942
- throw new Error("inconsistent vtxo chain from indexer (cycle detected)");
16943
- }
16944
- const nodes = [];
16945
- for (const tx of order) {
16946
- let confirmed = false;
16947
- try {
16948
- const status = await params.onchain.getTxStatus(tx.txid);
16949
- confirmed = status.confirmed;
16950
- } catch {
16951
- confirmed = false;
16952
- }
16953
- const expires = Number(tx.expiresAt);
16954
- nodes.push({
16955
- txid: tx.txid,
16956
- type: tx.type,
16957
- expiresAt: Number.isFinite(expires) && expires > 0 ? expires : void 0,
16958
- forVtxos: [...tx.forVtxos].sort(),
16959
- confirmed
16960
- });
16961
- }
16962
- return nodes;
16963
- }
16964
- function topoSortByDeps(items, idOf, depsOf) {
16965
- const produced = new Set(items.map(idOf));
16966
- const emitted = /* @__PURE__ */ new Set();
16967
- const ordered = [];
16968
- let remaining = items;
16969
- while (remaining.length > 0) {
16970
- const next = [];
16971
- let progress = false;
16972
- for (const item of remaining) {
16973
- if (depsOf(item).every((d) => !produced.has(d) || emitted.has(d))) {
16974
- ordered.push(item);
16975
- emitted.add(idOf(item));
16976
- progress = true;
16977
- } else {
16978
- next.push(item);
16979
- }
16980
- }
16981
- if (!progress) {
16982
- throw new Error("topological sort: cycle or unsatisfiable dependency");
16983
- }
16984
- remaining = next;
16985
- }
16986
- return ordered;
16987
- }
16988
17669
  function extraWitnessSize(path) {
16989
17670
  return (path.extraWitness ?? []).reduce((sum, item) => sum + 1 + item.length, 0);
16990
17671
  }
@@ -17091,27 +17772,22 @@ async function computeExitLayout(opts, feeRate) {
17091
17772
  const { wallet, onchainWallet } = opts;
17092
17773
  const vtxos = await selectExitVtxos(opts);
17093
17774
  if (vtxos.length === 0) throw new Error("no vtxos to exit");
17775
+ const resolver = createExitChainResolver({
17776
+ indexer: wallet.indexerProvider,
17777
+ repository: wallet.virtualTxRepository,
17778
+ extraSources: wallet.exitDataCapture?.sources
17779
+ });
17094
17780
  const dag = await buildExitDag({
17095
17781
  vtxos,
17096
- indexer: wallet.indexerProvider,
17782
+ chain: resolver,
17097
17783
  onchain: wallet.onchainProvider
17098
17784
  });
17099
17785
  const pendingNodes = dag.filter((n) => !n.confirmed);
17100
17786
  const psbts = /* @__PURE__ */ new Map();
17101
17787
  if (pendingNodes.length > 0) {
17102
- const txids = pendingNodes.map((n) => n.txid);
17103
- let pageIndex = 0;
17104
- let hasMore = true;
17105
- while (hasMore) {
17106
- const { txs, page } = await wallet.indexerProvider.getVirtualTxs(txids, {
17107
- pageIndex,
17108
- pageSize: DEFAULT_PAGE_SIZE
17109
- });
17110
- for (const psbt of txs) {
17111
- psbts.set(Transaction.fromPSBT(base64.decode(psbt)).id, psbt);
17112
- }
17113
- hasMore = page ? txs.length === DEFAULT_PAGE_SIZE : false;
17114
- pageIndex++;
17788
+ const txs = await resolver.getVirtualTxs(pendingNodes.map((n) => n.txid));
17789
+ for (const psbt of txs) {
17790
+ psbts.set(Transaction.fromPSBT(base64.decode(psbt)).id, psbt);
17115
17791
  }
17116
17792
  }
17117
17793
  const childVsize = Number(
@@ -17754,6 +18430,6 @@ function isArkContract(str) {
17754
18430
  return str.startsWith(ARKCONTRACT_PREFIX + "=");
17755
18431
  }
17756
18432
 
17757
- export { ActivityRegistry, ArkNote, AssetManager, BIP322, Batch, ChainedTxType, ContractManager, ContractRepositoryImpl, ContractWatcher, DB_VERSION, DEFAULT_MESSAGE_TIMEOUTS, DelegateManagerImpl, DelegateNotConfiguredError, DelegatorManagerImpl, DelegatorNotConfiguredError, DescriptorSigningProviderMissingError, DustChangeError, ELECTRUM_TCP_HOST, ELECTRUM_WS_URL, ESPLORA_URL, ElectrumOnchainProvider, EsploraProvider, Estimator, HDDescriptorProvider, INTENT_TERMINAL_STATES, InMemoryContractRepository, InMemoryIntentRepository, InMemoryVirtualTxRepository, InMemoryWalletRepository, IndexedDBContractRepository, IndexedDBIntentRepository, IndexedDBVirtualTxRepository, IndexedDBWalletRepository, MESSAGE_BUS_INITIALIZING, MESSAGE_BUS_NOT_INITIALIZED, MIGRATION_KEY, MessageBus, MessageBusInitializingError, MessageBusNotInitializedError, MissingSigningDescriptorError, MnemonicIdentity, OnchainWallet, P2A, Ramps, ReadonlyAssetManager, ReadonlyDescriptorIdentity, ReadonlySingleKey, ReadonlyWallet, ReadonlyWalletError, RestDelegateProvider, RestDelegatorProvider, SeedIdentity, ServiceWorkerReadonlyWallet, ServiceWorkerTimeoutError, ServiceWorkerWallet, SingleKey, TxTree, TxType, TxWeightEstimator, UnilateralExit, Unroll, VtxoManager, Wallet2 as Wallet, WalletMessageHandler, WalletNotInitializedError, WalletRepositoryImpl, WsElectrumChainSource, assertIntentIdUnique, boardingResolver, buildForfeitTx, buildOffchainTx, classifyAgainstSignerSet, classifyContractSigner, closeDatabase, combineTapscriptSigs, contractFromArkContract, contractFromArkContractWithAddress, createDefaultActivityRegistry, decodeArkContract, deserializeAssets, deserializeExitPackage, deserializeUtxo, deserializeVtxo, encodeArkContract, extendVirtualCoinForContract, getMigrationStatus, getRandomId, hasBoardingTxExpired, intentMatchesFilter, intentPageBounds, isArkContract, isBatchSignable, isCooperativelyMigratable, isDiscoverable, isExpired, isRecoverable, isSpendable, isSubdust, isTerminalIntentState, isValidArkAddress, isVtxoExpiringSoon, isVtxoForScript, mergeChainedTxType, migrateWalletRepository, openDatabase, requiresMigration, rollbackMigration, saveVtxosForContract, scriptFromArkAddress, serializeAssets, serializeExitPackage, serializeUtxo, serializeVtxo, setupServiceWorker, signerSetFromInfo, toXOnlySignerHex, validateConnectorsTxGraph, validateVtxoTxGraph, verifyTapscriptSignatures, waitForIncomingFunds, warnAndFilterVtxosForScript };
17758
- //# sourceMappingURL=chunk-FMI2GKYO.js.map
17759
- //# sourceMappingURL=chunk-FMI2GKYO.js.map
18433
+ export { ActivityRegistry, ArkNote, AssetManager, BIP322, Batch, ChainedTxType, ContractManager, ContractRepositoryImpl, ContractWatcher, DB_VERSION, DEFAULT_MESSAGE_TIMEOUTS, DelegateManagerImpl, DelegateNotConfiguredError, DelegatorManagerImpl, DelegatorNotConfiguredError, DescriptorSigningProviderMissingError, DustChangeError, ELECTRUM_TCP_HOST, ELECTRUM_WS_URL, ESPLORA_URL, ElectrumOnchainProvider, EsploraProvider, Estimator, HDDescriptorProvider, INTENT_TERMINAL_STATES, InMemoryContractRepository, InMemoryIntentRepository, InMemoryVirtualTxRepository, InMemoryWalletRepository, IndexedDBContractRepository, IndexedDBIntentRepository, IndexedDBVirtualTxRepository, IndexedDBWalletRepository, MESSAGE_BUS_INITIALIZING, MESSAGE_BUS_NOT_INITIALIZED, MIGRATION_KEY, MessageBus, MessageBusInitializingError, MessageBusNotInitializedError, MissingSigningDescriptorError, MnemonicIdentity, OnchainWallet, P2A, Ramps, ReadonlyAssetManager, ReadonlyDescriptorIdentity, ReadonlySingleKey, ReadonlyWallet, ReadonlyWalletError, RestDelegateProvider, RestDelegatorProvider, SeedIdentity, ServiceWorkerReadonlyWallet, ServiceWorkerTimeoutError, ServiceWorkerWallet, SingleKey, TxTree, TxType, TxWeightEstimator, UnilateralExit, Unroll, VtxoManager, Wallet2 as Wallet, WalletMessageHandler, WalletNotInitializedError, WalletRepositoryImpl, WsElectrumChainSource, assertIntentIdUnique, boardingResolver, buildForfeitTx, buildOffchainTx, classifyAgainstSignerSet, classifyContractSigner, closeDatabase, combineTapscriptSigs, contractFromArkContract, contractFromArkContractWithAddress, createDefaultActivityRegistry, createExitChainResolver, decodeArkContract, deserializeAssets, deserializeExitPackage, deserializeUtxo, deserializeVtxo, encodeArkContract, extendVirtualCoinForContract, getMigrationStatus, getRandomId, hasBoardingTxExpired, intentMatchesFilter, intentPageBounds, isArkContract, isBatchSignable, isCooperativelyMigratable, isDiscoverable, isExpired, isRecoverable, isRetryableProviderError, isSpendable, isSubdust, isTerminalIntentState, isValidArkAddress, isVtxoExpiringSoon, isVtxoForScript, mergeChainedTxType, migrateWalletRepository, openDatabase, requiresMigration, rollbackMigration, saveVtxosForContract, scriptFromArkAddress, serializeAssets, serializeExitPackage, serializeUtxo, serializeVtxo, setupServiceWorker, signerSetFromInfo, toXOnlySignerHex, validateConnectorsTxGraph, validateVtxoTxGraph, verifyTapscriptSignatures, waitForIncomingFunds, warnAndFilterVtxosForScript };
18434
+ //# sourceMappingURL=chunk-TGRJ5WAX.js.map
18435
+ //# sourceMappingURL=chunk-TGRJ5WAX.js.map