@arkade-os/sdk 0.4.15 → 0.4.17

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 (197) hide show
  1. package/README.md +102 -96
  2. package/dist/cjs/arkfee/estimator.js +1 -1
  3. package/dist/cjs/arkfee/types.js +2 -1
  4. package/dist/cjs/arknote/index.js +43 -4
  5. package/dist/cjs/bip322/index.js +1 -1
  6. package/dist/cjs/contracts/arkcontract.js +1 -1
  7. package/dist/cjs/contracts/contractManager.js +60 -28
  8. package/dist/cjs/contracts/contractWatcher.js +29 -22
  9. package/dist/cjs/contracts/handlers/default.js +1 -1
  10. package/dist/cjs/contracts/handlers/delegate.js +1 -1
  11. package/dist/cjs/contracts/handlers/helpers.js +1 -1
  12. package/dist/cjs/extension/asset/assetGroup.js +92 -5
  13. package/dist/cjs/extension/asset/assetId.js +67 -3
  14. package/dist/cjs/extension/asset/assetInput.js +18 -0
  15. package/dist/cjs/extension/asset/assetOutput.js +15 -0
  16. package/dist/cjs/extension/asset/assetRef.js +66 -0
  17. package/dist/cjs/extension/asset/metadata.js +15 -0
  18. package/dist/cjs/extension/asset/packet.js +4 -1
  19. package/dist/cjs/extension/index.js +1 -1
  20. package/dist/cjs/forfeit.js +14 -0
  21. package/dist/cjs/identity/seedIdentity.js +2 -2
  22. package/dist/cjs/identity/singleKey.js +4 -0
  23. package/dist/cjs/intent/index.js +28 -12
  24. package/dist/cjs/providers/ark.js +3 -2
  25. package/dist/cjs/providers/delegator.js +20 -1
  26. package/dist/cjs/providers/expoArk.js +2 -2
  27. package/dist/cjs/providers/indexer.js +2 -2
  28. package/dist/cjs/providers/onchain.js +2 -1
  29. package/dist/cjs/repositories/realm/schemas.js +2 -2
  30. package/dist/cjs/repositories/realm/types.js +1 -1
  31. package/dist/cjs/script/address.js +37 -6
  32. package/dist/cjs/script/base.js +70 -1
  33. package/dist/cjs/script/default.js +3 -0
  34. package/dist/cjs/script/delegate.js +4 -0
  35. package/dist/cjs/script/tapscript.js +17 -2
  36. package/dist/cjs/script/vhtlc.js +35 -27
  37. package/dist/cjs/storage/fileSystem.js +1 -1
  38. package/dist/cjs/storage/inMemory.js +1 -1
  39. package/dist/cjs/storage/indexedDB.js +1 -1
  40. package/dist/cjs/storage/localStorage.js +1 -1
  41. package/dist/cjs/tree/validation.js +1 -1
  42. package/dist/cjs/utils/arkTransaction.js +5 -5
  43. package/dist/cjs/utils/bip21.js +16 -3
  44. package/dist/cjs/utils/syncCursors.js +4 -4
  45. package/dist/cjs/utils/transaction.js +1 -1
  46. package/dist/cjs/utils/transactionHistory.js +11 -11
  47. package/dist/cjs/utils/unknownFields.js +3 -3
  48. package/dist/cjs/wallet/asset-manager.js +4 -4
  49. package/dist/cjs/wallet/batch.js +5 -5
  50. package/dist/cjs/wallet/delegator.js +9 -8
  51. package/dist/cjs/wallet/expo/background.js +3 -3
  52. package/dist/cjs/wallet/expo/wallet.js +7 -7
  53. package/dist/cjs/wallet/index.js +43 -0
  54. package/dist/cjs/wallet/onchain.js +43 -5
  55. package/dist/cjs/wallet/ramps.js +44 -14
  56. package/dist/cjs/wallet/serviceWorker/wallet-message-handler.js +22 -22
  57. package/dist/cjs/wallet/serviceWorker/wallet.js +28 -24
  58. package/dist/cjs/wallet/unroll.js +12 -8
  59. package/dist/cjs/wallet/utils.js +1 -1
  60. package/dist/cjs/wallet/vtxo-manager.js +122 -82
  61. package/dist/cjs/wallet/wallet.js +140 -77
  62. package/dist/cjs/worker/expo/asyncStorageTaskQueue.js +1 -1
  63. package/dist/cjs/worker/expo/processors/contractPollProcessor.js +2 -2
  64. package/dist/cjs/worker/expo/taskRunner.js +3 -3
  65. package/dist/cjs/worker/messageBus.js +3 -0
  66. package/dist/esm/arkfee/estimator.js +1 -1
  67. package/dist/esm/arkfee/types.js +2 -1
  68. package/dist/esm/arknote/index.js +43 -4
  69. package/dist/esm/bip322/index.js +1 -1
  70. package/dist/esm/contracts/arkcontract.js +1 -1
  71. package/dist/esm/contracts/contractManager.js +60 -28
  72. package/dist/esm/contracts/contractWatcher.js +29 -22
  73. package/dist/esm/contracts/handlers/default.js +1 -1
  74. package/dist/esm/contracts/handlers/delegate.js +1 -1
  75. package/dist/esm/contracts/handlers/helpers.js +1 -1
  76. package/dist/esm/extension/asset/assetGroup.js +92 -5
  77. package/dist/esm/extension/asset/assetId.js +67 -3
  78. package/dist/esm/extension/asset/assetInput.js +18 -0
  79. package/dist/esm/extension/asset/assetOutput.js +15 -0
  80. package/dist/esm/extension/asset/assetRef.js +66 -0
  81. package/dist/esm/extension/asset/metadata.js +15 -0
  82. package/dist/esm/extension/asset/packet.js +4 -1
  83. package/dist/esm/extension/index.js +1 -1
  84. package/dist/esm/forfeit.js +14 -0
  85. package/dist/esm/identity/seedIdentity.js +2 -2
  86. package/dist/esm/identity/singleKey.js +4 -0
  87. package/dist/esm/index.js +1 -1
  88. package/dist/esm/intent/index.js +28 -12
  89. package/dist/esm/providers/ark.js +3 -2
  90. package/dist/esm/providers/delegator.js +20 -1
  91. package/dist/esm/providers/expoArk.js +2 -2
  92. package/dist/esm/providers/indexer.js +2 -2
  93. package/dist/esm/providers/onchain.js +2 -1
  94. package/dist/esm/repositories/realm/schemas.js +2 -2
  95. package/dist/esm/repositories/realm/types.js +1 -1
  96. package/dist/esm/script/address.js +37 -6
  97. package/dist/esm/script/base.js +70 -1
  98. package/dist/esm/script/default.js +3 -0
  99. package/dist/esm/script/delegate.js +4 -0
  100. package/dist/esm/script/tapscript.js +17 -2
  101. package/dist/esm/script/vhtlc.js +35 -27
  102. package/dist/esm/storage/fileSystem.js +1 -1
  103. package/dist/esm/storage/inMemory.js +1 -1
  104. package/dist/esm/storage/indexedDB.js +1 -1
  105. package/dist/esm/storage/localStorage.js +1 -1
  106. package/dist/esm/tree/validation.js +1 -1
  107. package/dist/esm/utils/arkTransaction.js +5 -5
  108. package/dist/esm/utils/bip21.js +16 -3
  109. package/dist/esm/utils/syncCursors.js +4 -4
  110. package/dist/esm/utils/transaction.js +1 -1
  111. package/dist/esm/utils/transactionHistory.js +11 -11
  112. package/dist/esm/utils/unknownFields.js +3 -3
  113. package/dist/esm/wallet/asset-manager.js +4 -4
  114. package/dist/esm/wallet/batch.js +5 -5
  115. package/dist/esm/wallet/delegator.js +9 -8
  116. package/dist/esm/wallet/expo/background.js +3 -3
  117. package/dist/esm/wallet/expo/wallet.js +7 -7
  118. package/dist/esm/wallet/index.js +43 -0
  119. package/dist/esm/wallet/onchain.js +43 -5
  120. package/dist/esm/wallet/ramps.js +44 -14
  121. package/dist/esm/wallet/serviceWorker/wallet-message-handler.js +22 -22
  122. package/dist/esm/wallet/serviceWorker/wallet.js +28 -24
  123. package/dist/esm/wallet/unroll.js +12 -8
  124. package/dist/esm/wallet/utils.js +1 -1
  125. package/dist/esm/wallet/vtxo-manager.js +121 -81
  126. package/dist/esm/wallet/wallet.js +140 -77
  127. package/dist/esm/worker/expo/asyncStorageTaskQueue.js +1 -1
  128. package/dist/esm/worker/expo/processors/contractPollProcessor.js +2 -2
  129. package/dist/esm/worker/expo/taskRunner.js +3 -3
  130. package/dist/esm/worker/messageBus.js +3 -0
  131. package/dist/types/arkfee/estimator.d.ts +1 -1
  132. package/dist/types/arkfee/types.d.ts +2 -1
  133. package/dist/types/arknote/index.d.ts +44 -4
  134. package/dist/types/bip322/index.d.ts +1 -1
  135. package/dist/types/contracts/arkcontract.d.ts +1 -1
  136. package/dist/types/contracts/contractManager.d.ts +39 -65
  137. package/dist/types/contracts/contractWatcher.d.ts +39 -18
  138. package/dist/types/contracts/handlers/default.d.ts +1 -1
  139. package/dist/types/contracts/handlers/delegate.d.ts +1 -1
  140. package/dist/types/contracts/handlers/helpers.d.ts +1 -1
  141. package/dist/types/contracts/types.d.ts +36 -26
  142. package/dist/types/extension/asset/assetGroup.d.ts +92 -1
  143. package/dist/types/extension/asset/assetId.d.ts +67 -3
  144. package/dist/types/extension/asset/assetInput.d.ts +18 -0
  145. package/dist/types/extension/asset/assetOutput.d.ts +15 -0
  146. package/dist/types/extension/asset/assetRef.d.ts +66 -0
  147. package/dist/types/extension/asset/metadata.d.ts +15 -0
  148. package/dist/types/extension/asset/packet.d.ts +4 -1
  149. package/dist/types/extension/index.d.ts +1 -1
  150. package/dist/types/forfeit.d.ts +14 -0
  151. package/dist/types/identity/index.d.ts +16 -0
  152. package/dist/types/identity/seedIdentity.d.ts +8 -6
  153. package/dist/types/identity/singleKey.d.ts +4 -0
  154. package/dist/types/intent/index.d.ts +19 -6
  155. package/dist/types/providers/ark.d.ts +40 -2
  156. package/dist/types/providers/delegator.d.ts +54 -1
  157. package/dist/types/providers/expoArk.d.ts +2 -2
  158. package/dist/types/providers/indexer.d.ts +105 -2
  159. package/dist/types/providers/onchain.d.ts +62 -1
  160. package/dist/types/repositories/realm/schemas.d.ts +2 -2
  161. package/dist/types/repositories/realm/types.d.ts +2 -2
  162. package/dist/types/repositories/walletRepository.d.ts +16 -0
  163. package/dist/types/script/address.d.ts +35 -2
  164. package/dist/types/script/base.d.ts +66 -1
  165. package/dist/types/script/default.d.ts +3 -0
  166. package/dist/types/script/delegate.d.ts +4 -0
  167. package/dist/types/script/tapscript.d.ts +17 -2
  168. package/dist/types/script/vhtlc.d.ts +35 -27
  169. package/dist/types/storage/fileSystem.d.ts +1 -1
  170. package/dist/types/storage/inMemory.d.ts +1 -1
  171. package/dist/types/storage/index.d.ts +1 -1
  172. package/dist/types/storage/indexedDB.d.ts +1 -1
  173. package/dist/types/storage/localStorage.d.ts +1 -1
  174. package/dist/types/utils/arkTransaction.d.ts +3 -3
  175. package/dist/types/utils/bip21.d.ts +17 -0
  176. package/dist/types/utils/syncCursors.d.ts +4 -4
  177. package/dist/types/utils/transaction.d.ts +1 -1
  178. package/dist/types/utils/transactionHistory.d.ts +3 -3
  179. package/dist/types/utils/unknownFields.d.ts +5 -5
  180. package/dist/types/wallet/asset-manager.d.ts +3 -3
  181. package/dist/types/wallet/batch.d.ts +27 -7
  182. package/dist/types/wallet/delegator.d.ts +10 -0
  183. package/dist/types/wallet/expo/background.d.ts +4 -4
  184. package/dist/types/wallet/expo/wallet.d.ts +10 -10
  185. package/dist/types/wallet/index.d.ts +457 -25
  186. package/dist/types/wallet/onchain.d.ts +42 -4
  187. package/dist/types/wallet/ramps.d.ts +40 -10
  188. package/dist/types/wallet/serviceWorker/wallet-message-handler.d.ts +4 -4
  189. package/dist/types/wallet/serviceWorker/wallet.d.ts +71 -33
  190. package/dist/types/wallet/unroll.d.ts +8 -6
  191. package/dist/types/wallet/vtxo-manager.d.ts +146 -93
  192. package/dist/types/wallet/wallet.d.ts +91 -33
  193. package/dist/types/worker/expo/asyncStorageTaskQueue.d.ts +1 -1
  194. package/dist/types/worker/expo/processors/contractPollProcessor.d.ts +1 -1
  195. package/dist/types/worker/expo/taskRunner.d.ts +6 -6
  196. package/dist/types/worker/messageBus.d.ts +5 -3
  197. package/package.json +1 -1
@@ -34,6 +34,10 @@ import { ContractManager } from '../contracts/contractManager.js';
34
34
  import { contractHandlers } from '../contracts/handlers/index.js';
35
35
  import { timelockToSequence } from '../contracts/handlers/helpers.js';
36
36
  import { advanceSyncCursors, clearSyncCursors, computeSyncWindow, cursorCutoff, getAllSyncCursors, updateWalletState, } from '../utils/syncCursors.js';
37
+ // Hardcoded unilateral exit delay for mainnet (~7 days in seconds).
38
+ // Pinned here so that address derivation stays stable for existing mainnet
39
+ // wallets even after the server lowers the delay it advertises.
40
+ const MAINNET_UNILATERAL_EXIT_DELAY = 605184n;
37
41
  /**
38
42
  * Type guard function to check if an identity has a toReadonly method.
39
43
  */
@@ -108,12 +112,12 @@ export class ReadonlyWallet {
108
112
  const serverIsMainnet = info.network === "bitcoin";
109
113
  if (identityIsMainnet && !serverIsMainnet) {
110
114
  throw new Error(`Network mismatch: identity uses mainnet derivation (coin type 0) ` +
111
- `but Ark server is on ${info.network}. ` +
115
+ `but the Arkade server is on ${info.network}. ` +
112
116
  `Create identity with { isMainnet: false } to use testnet derivation.`);
113
117
  }
114
118
  if (!identityIsMainnet && serverIsMainnet) {
115
119
  throw new Error(`Network mismatch: identity uses testnet derivation (coin type 1) ` +
116
- `but Ark server is on mainnet. ` +
120
+ `but the Arkade server is on mainnet. ` +
117
121
  `Create identity with { isMainnet: true } or omit isMainnet (defaults to mainnet).`);
118
122
  }
119
123
  }
@@ -129,10 +133,16 @@ export class ReadonlyWallet {
129
133
  throw new Error("invalid exitTimelock");
130
134
  }
131
135
  }
136
+ // On mainnet, pin the unilateral exit delay to the historical value so
137
+ // that addresses derived by existing wallets remain stable even if the
138
+ // server starts advertising a shorter delay.
139
+ const unilateralExitDelay = info.network === "bitcoin"
140
+ ? MAINNET_UNILATERAL_EXIT_DELAY
141
+ : info.unilateralExitDelay;
132
142
  // create unilateral exit timelock
133
143
  const exitTimelock = config.exitTimelock ?? {
134
- value: info.unilateralExitDelay,
135
- type: info.unilateralExitDelay < 512n ? "blocks" : "seconds",
144
+ value: unilateralExitDelay,
145
+ type: unilateralExitDelay < 512n ? "blocks" : "seconds",
136
146
  };
137
147
  // validate boarding timelock passed in config if any
138
148
  if (config.boardingTimelock) {
@@ -185,6 +195,12 @@ export class ReadonlyWallet {
185
195
  delegatorProvider: config.delegatorProvider,
186
196
  };
187
197
  }
198
+ /**
199
+ * Create a readonly wallet for querying balances, addresses, and history.
200
+ *
201
+ * @param config - Readonly wallet configuration
202
+ * @returns A readonly wallet instance
203
+ */
188
204
  static async create(config) {
189
205
  const pubkey = await config.identity.xOnlyPublicKey();
190
206
  if (!pubkey) {
@@ -203,12 +219,17 @@ export class ReadonlyWallet {
203
219
  get defaultContractScript() {
204
220
  return hex.encode(this.offchainTapscript.pkScript);
205
221
  }
222
+ /** Returns the wallet's Arkade address. */
206
223
  async getAddress() {
207
224
  return this.arkAddress.encode();
208
225
  }
226
+ /** Returns the onchain boarding address used to move funds into Arkade. */
209
227
  async getBoardingAddress() {
210
228
  return this.boardingTapscript.onchainAddress(this.network);
211
229
  }
230
+ /**
231
+ * Return the wallet's combined onchain and offchain balances.
232
+ */
212
233
  async getBalance() {
213
234
  const [boardingUtxos, vtxos] = await Promise.all([
214
235
  this.getBoardingUtxos(),
@@ -240,7 +261,7 @@ export class ReadonlyWallet {
240
261
  .reduce((sum, coin) => sum + coin.value, 0);
241
262
  const totalBoarding = confirmed + unconfirmed;
242
263
  const totalOffchain = settled + preconfirmed + recoverable;
243
- // aggregate asset balances from spendable vtxos
264
+ // aggregate asset balances from spendable virtual outputs
244
265
  const assetBalances = new Map();
245
266
  for (const vtxo of vtxos) {
246
267
  if (!isSpendable(vtxo))
@@ -270,15 +291,16 @@ export class ReadonlyWallet {
270
291
  assets,
271
292
  };
272
293
  }
294
+ /**
295
+ * Return virtual outputs tracked by the wallet.
296
+ *
297
+ * @param filter - Optional flags controlling whether recoverable or unrolled VTXOs are included
298
+ */
273
299
  async getVtxos(filter) {
274
- const { isDelta, fetchedExtended, address } = await this.syncVtxos();
275
300
  const f = filter ?? { withRecoverable: true, withUnrolled: false };
276
- // For delta syncs, read the full merged set from cache so old
277
- // VTXOs that weren't in the delta are still returned.
278
- const vtxos = isDelta
279
- ? await this.walletRepository.getVtxos(address)
280
- : fetchedExtended;
281
- return vtxos.filter((vtxo) => {
301
+ const contractManager = await this.getContractManager();
302
+ const contractsWithVtxos = await contractManager.getContractsWithVtxos();
303
+ return contractsWithVtxos.flatMap(({ vtxos }) => vtxos.filter((vtxo) => {
282
304
  if (isSpendable(vtxo)) {
283
305
  if (!f.withRecoverable &&
284
306
  (isRecoverable(vtxo) || isExpired(vtxo))) {
@@ -287,10 +309,13 @@ export class ReadonlyWallet {
287
309
  return true;
288
310
  }
289
311
  return !!(f.withUnrolled && vtxo.isUnrolled);
290
- });
312
+ }));
291
313
  }
314
+ /**
315
+ * Return wallet transaction history derived from Arkade state and boarding transactions.
316
+ */
292
317
  async getTransactionHistory() {
293
- // Delta-sync VTXOs into cache, then build history from the cache.
318
+ // Delta-sync virtual outputs into cache, then build history from the cache.
294
319
  const { isDelta, fetchedExtended, address } = await this.syncVtxos();
295
320
  const allVtxos = isDelta
296
321
  ? await this.walletRepository.getVtxos(address)
@@ -302,7 +327,7 @@ export class ReadonlyWallet {
302
327
  return buildTransactionHistory(allVtxos, boardingTxs, commitmentsToIgnore, getTxCreatedAt);
303
328
  }
304
329
  /**
305
- * Delta-sync wallet VTXOs: fetch only changed VTXOs since the last
330
+ * Delta-sync wallet virtual outputs: fetch only changed virtual outputs since the last
306
331
  * cursor, or do a full bootstrap when no cursor exists. Upserts
307
332
  * the result into the cache and advances the sync cursors.
308
333
  *
@@ -375,21 +400,21 @@ export class ReadonlyWallet {
375
400
  allVtxos.push(...response.vtxos);
376
401
  }
377
402
  }
378
- // Extend every fetched VTXO and upsert into the cache.
403
+ // Extend every fetched virtual output and upsert into the cache.
379
404
  const fetchedExtended = [];
380
405
  for (const vtxo of allVtxos) {
381
406
  const extended = extendWithScript(vtxo);
382
407
  if (extended)
383
408
  fetchedExtended.push(extended);
384
409
  }
385
- // Save VTXOs first, then advance cursors only on success.
410
+ // Save virtual outputs first, then advance cursors only on success.
386
411
  const cutoff = cursorCutoff(requestStartedAt);
387
412
  await this.walletRepository.saveVtxos(address, fetchedExtended);
388
413
  await advanceSyncCursors(this.walletRepository, Object.fromEntries(allScripts.map((s) => [s, cutoff])));
389
414
  // Delta-sync reconciliation: full re-fetch for delta scripts.
390
415
  //
391
- // The delta fetch (above) only returns VTXOs changed after the
392
- // cursor, so it can miss preconfirmed VTXOs that were consumed
416
+ // The delta fetch (above) only returns virtual outputs changed after the
417
+ // cursor, so it can miss preconfirmed virtual outputs that were consumed
393
418
  // by a round between syncs. Rather than layering targeted
394
419
  // queries (pendingOnly, spendableOnly) with pagination guards
395
420
  // and set algebra, we perform a single unfiltered re-fetch for
@@ -397,8 +422,8 @@ export class ReadonlyWallet {
397
422
  // gives us complete, authoritative state in one call and keeps
398
423
  // the reconciliation logic simple.
399
424
  //
400
- // Any cached non-spent VTXO that is absent from the full
401
- // result set is marked spent; any VTXO whose state changed
425
+ // Any cached non-spent virtual output that is absent from the full
426
+ // result set is marked spent; any virtual output whose state changed
402
427
  // (e.g. preconfirmed → settled) is updated in place.
403
428
  if (hasDelta) {
404
429
  const { vtxos: fullVtxos, page: fullPage } = await this.indexerProvider.getVtxos({
@@ -407,7 +432,7 @@ export class ReadonlyWallet {
407
432
  // Reconciliation is best-effort: if the response is
408
433
  // paginated we don't have a complete picture, so we skip
409
434
  // rather than act on partial data. Wallets with enough
410
- // VTXOs to exceed a single page rely solely on the
435
+ // virtual outputs to exceed a single page rely solely on the
411
436
  // cursor-based delta mechanism for state updates.
412
437
  const fullSetComplete = !fullPage || fullPage.total <= 1;
413
438
  if (fullSetComplete) {
@@ -424,7 +449,7 @@ export class ReadonlyWallet {
424
449
  const outpoint = `${cached.txid}:${cached.vout}`;
425
450
  const fresh = fullOutpoints.get(outpoint);
426
451
  if (!fresh) {
427
- // Server no longer knows about this VTXO
452
+ // Server no longer knows about this virtual output
428
453
  // it was spent between syncs.
429
454
  reconciledExtended.push({
430
455
  ...cached,
@@ -457,12 +482,15 @@ export class ReadonlyWallet {
457
482
  };
458
483
  }
459
484
  /**
460
- * Clear all VTXO sync cursors, forcing a full re-bootstrap on next sync.
485
+ * Clear all virtual output sync cursors, forcing a full re-bootstrap on next sync.
461
486
  * Useful for recovery after indexer reprocessing or debugging.
462
487
  */
463
488
  async clearSyncCursors() {
464
489
  await clearSyncCursors(this.walletRepository);
465
490
  }
491
+ /**
492
+ * Build a transaction history view for the wallet's boarding address.
493
+ */
466
494
  async getBoardingTxs() {
467
495
  const utxos = [];
468
496
  const commitmentsToIgnore = new Set();
@@ -533,16 +561,25 @@ export class ReadonlyWallet {
533
561
  commitmentsToIgnore,
534
562
  };
535
563
  }
564
+ /**
565
+ * Fetch and cache onchain inputs (UTXOs) received at the boarding address.
566
+ */
536
567
  async getBoardingUtxos() {
537
568
  const boardingAddress = await this.getBoardingAddress();
538
569
  const boardingUtxos = await this.onchainProvider.getCoins(boardingAddress);
539
570
  const utxos = boardingUtxos.map((utxo) => {
540
571
  return extendCoin(this, utxo);
541
572
  });
542
- // Save boardingUtxos using unified repository
573
+ // Save boarding inputs using unified repository
543
574
  await this.walletRepository.saveUtxos(boardingAddress, utxos);
544
575
  return utxos;
545
576
  }
577
+ /**
578
+ * Subscribe to onchain and offchain notifications for newly received funds.
579
+ *
580
+ * @param eventCallback - Callback invoked when matching funds are detected
581
+ * @returns A function that stops the subscriptions
582
+ */
546
583
  async notifyIncomingFunds(eventCallback) {
547
584
  const arkAddress = await this.getAddress();
548
585
  const boardingAddress = await this.getBoardingAddress();
@@ -553,11 +590,11 @@ export class ReadonlyWallet {
553
590
  return tx.vout.findIndex((v) => v.scriptpubkey_address === boardingAddress);
554
591
  };
555
592
  onchainStopFunc = await this.onchainProvider.watchAddresses([boardingAddress], (txs) => {
556
- // find all utxos belonging to our boarding address
593
+ // find all onchain outputs belonging to our boarding address
557
594
  const coins = txs
558
595
  // filter txs where address is in output
559
596
  .filter((tx) => findVoutOnTx(tx) !== -1)
560
- // return utxo as Coin
597
+ // return boarding input as Coin
561
598
  .map((tx) => {
562
599
  const { txid, status } = tx;
563
600
  const vout = findVoutOnTx(tx);
@@ -582,8 +619,8 @@ export class ReadonlyWallet {
582
619
  };
583
620
  // Handle subscription updates asynchronously without blocking.
584
621
  // Note: subscription covers all wallet scripts (default + delegate),
585
- // but we can't determine which script each VTXO belongs to from the
586
- // subscription event. VTXOs are extended with the current offchainTapscript;
622
+ // but we can't determine which script each virtual output belongs to from the
623
+ // subscription event. Virtual outputs are extended with the current offchainTapscript;
587
624
  // this is for notification/display only — not for spending.
588
625
  // For correct extension metadata, use getVtxos() which queries per-script.
589
626
  (async () => {
@@ -610,8 +647,9 @@ export class ReadonlyWallet {
610
647
  };
611
648
  return stopFunc;
612
649
  }
650
+ /** Fetch Arkade transaction ids that are still pending final settlement. */
613
651
  async fetchPendingTxs() {
614
- // get non-swept VTXOs, rely on the indexer only in case DB doesn't have the right state
652
+ // get non-swept virtual outputs, rely on the indexer only in case DB doesn't have the right state
615
653
  const scripts = await this.getWalletScripts();
616
654
  let { vtxos } = await this.indexerProvider.getVtxos({
617
655
  scripts,
@@ -652,7 +690,7 @@ export class ReadonlyWallet {
652
690
  }
653
691
  /**
654
692
  * Build a map of scriptHex → VtxoScript for all wallet contracts,
655
- * so VTXOs can be extended with the correct tapscript per contract.
693
+ * so virtual outputs can be extended with the correct tapscript per contract.
656
694
  */
657
695
  async getScriptMap() {
658
696
  const map = new Map();
@@ -741,7 +779,6 @@ export class ReadonlyWallet {
741
779
  indexerProvider: this.indexerProvider,
742
780
  contractRepository: this.contractRepository,
743
781
  walletRepository: this.walletRepository,
744
- getDefaultAddress: () => this.getAddress(),
745
782
  watcherConfig: this.watcherConfig,
746
783
  });
747
784
  // Register the wallet's current address as a contract
@@ -765,7 +802,7 @@ export class ReadonlyWallet {
765
802
  address: await this.getAddress(),
766
803
  state: "active",
767
804
  });
768
- // Also register the non-delegate version so old VTXOs remain visible
805
+ // Also register the non-delegate version so old virtual outputs remain visible
769
806
  const nonDelegateScript = new DefaultVtxo.Script({
770
807
  pubKey: delegateScript.options.pubKey,
771
808
  serverPubKey: delegateScript.options.serverPubKey,
@@ -803,6 +840,7 @@ export class ReadonlyWallet {
803
840
  }
804
841
  return manager;
805
842
  }
843
+ /** Dispose wallet-owned managers and release background resources. */
806
844
  async dispose() {
807
845
  const manager = this._contractManager ??
808
846
  (this._contractManagerInitializing
@@ -812,29 +850,30 @@ export class ReadonlyWallet {
812
850
  this._contractManager = undefined;
813
851
  this._contractManagerInitializing = undefined;
814
852
  }
853
+ /** Async-dispose hook that forwards to `dispose()`. */
815
854
  async [Symbol.asyncDispose]() {
816
855
  await this.dispose();
817
856
  }
818
857
  }
819
858
  /**
820
- * Main wallet implementation for Bitcoin transactions with Ark protocol support.
821
- * The wallet does not store any data locally and relies on Ark and onchain
822
- * providers to fetch UTXOs and VTXOs.
859
+ * Main wallet implementation for Bitcoin transactions with Arkade protocol support.
860
+ * The wallet does not store any data locally and relies on Arkade and onchain
861
+ * providers to fetch onchain and virtual outputs.
823
862
  *
824
863
  * @example
825
864
  * ```typescript
826
865
  * // Create a wallet with URL configuration
827
866
  * const wallet = await Wallet.create({
828
- * identity: SingleKey.fromHex('your_private_key'),
829
- * arkServerUrl: 'https://ark.example.com',
867
+ * identity: MnemonicIdentity.fromMnemonic('abandon abandon...'),
868
+ * arkServerUrl: 'https://arkade.computer',
830
869
  * esploraUrl: 'https://mempool.space/api'
831
870
  * });
832
871
  *
833
872
  * // Or with custom provider instances (e.g., for Expo/React Native)
834
873
  * const wallet = await Wallet.create({
835
- * identity: SingleKey.fromHex('your_private_key'),
836
- * arkProvider: new ExpoArkProvider('https://ark.example.com'),
837
- * indexerProvider: new ExpoIndexerProvider('https://ark.example.com'),
874
+ * identity: MnemonicIdentity.fromMnemonic('abandon abandon...'),
875
+ * arkProvider: new ExpoArkProvider('https://arkade.computer'),
876
+ * indexerProvider: new ExpoIndexerProvider('https://arkade.computer'),
838
877
  * esploraUrl: 'https://mempool.space/api'
839
878
  * });
840
879
  *
@@ -843,9 +882,9 @@ export class ReadonlyWallet {
843
882
  * const boardingAddress = await wallet.getBoardingAddress();
844
883
  *
845
884
  * // Send bitcoin
846
- * const txid = await wallet.sendBitcoin({
847
- * address: 'tb1...',
848
- * amount: 50000
885
+ * const txid = await wallet.send({
886
+ * address: 'ark1q...',
887
+ * amount: 50000,
849
888
  * });
850
889
  * ```
851
890
  */
@@ -874,7 +913,7 @@ export class Wallet extends ReadonlyWallet {
874
913
  this.forfeitOutputScript = forfeitOutputScript;
875
914
  this.forfeitPubkey = forfeitPubkey;
876
915
  /**
877
- * Async mutex that serializes all operations submitting VTXOs to the Ark
916
+ * Async mutex that serializes all operations submitting VTXOs to the Arkade
878
917
  * server (`settle`, `send`, `sendBitcoin`). This prevents VtxoManager's
879
918
  * background renewal from racing with user-initiated transactions for the
880
919
  * same VTXO inputs.
@@ -954,6 +993,19 @@ export class Wallet extends ReadonlyWallet {
954
993
  await super.dispose();
955
994
  }
956
995
  }
996
+ /**
997
+ * Create a full wallet and initialize its background managers.
998
+ *
999
+ * @param config - Wallet configuration
1000
+ * @returns A wallet ready to query balances and send transactions
1001
+ * @example
1002
+ * ```typescript
1003
+ * const wallet = await Wallet.create({
1004
+ * identity,
1005
+ * arkServerUrl: 'https://arkade.computer',
1006
+ * });
1007
+ * ```
1008
+ */
957
1009
  static async create(config) {
958
1010
  const pubkey = await config.identity.xOnlyPublicKey();
959
1011
  if (!pubkey) {
@@ -985,7 +1037,7 @@ export class Wallet extends ReadonlyWallet {
985
1037
  * @returns A readonly wallet with the same configuration but readonly identity
986
1038
  * @example
987
1039
  * ```typescript
988
- * const wallet = await Wallet.create({ identity: SingleKey.fromHex('...'), ... });
1040
+ * const wallet = await Wallet.create({ identity: MnemonicIdentity.fromMnemonic('abandon abandon...'), ... });
989
1041
  * const readonlyWallet = await wallet.toReadonly();
990
1042
  *
991
1043
  * // Can query balance and addresses
@@ -993,7 +1045,7 @@ export class Wallet extends ReadonlyWallet {
993
1045
  * const address = await readonlyWallet.getAddress();
994
1046
  *
995
1047
  * // But cannot send transactions (type error)
996
- * // readonlyWallet.sendBitcoin(...); // TypeScript error
1048
+ * // readonlyWallet.send(...); // TypeScript error
997
1049
  * ```
998
1050
  */
999
1051
  async toReadonly() {
@@ -1003,19 +1055,22 @@ export class Wallet extends ReadonlyWallet {
1003
1055
  : this.identity; // Identity extends ReadonlyIdentity, so this is safe
1004
1056
  return new ReadonlyWallet(readonlyIdentity, this.network, this.onchainProvider, this.indexerProvider, this.arkServerPublicKey, this.offchainTapscript, this.boardingTapscript, this.dustAmount, this.walletRepository, this.contractRepository, this.delegatorProvider, this.watcherConfig);
1005
1057
  }
1058
+ /** Returns the delegator manager when delegation support is configured. */
1006
1059
  async getDelegatorManager() {
1007
1060
  return this._delegatorManager;
1008
1061
  }
1009
1062
  /**
1010
- * @deprecated Use `send`
1011
- * @param params
1063
+ * Send bitcoin to an Arkade address.
1064
+ *
1065
+ * @deprecated Use `send`.
1066
+ * @param params - Send parameters
1012
1067
  */
1013
1068
  async sendBitcoin(params) {
1014
1069
  if (params.amount <= 0) {
1015
1070
  throw new Error("Amount must be positive");
1016
1071
  }
1017
1072
  if (!isValidArkAddress(params.address)) {
1018
- throw new Error("Invalid Ark address " + params.address);
1073
+ throw new Error("Invalid Arkade address " + params.address);
1019
1074
  }
1020
1075
  if (params.selectedVtxos && params.selectedVtxos.length > 0) {
1021
1076
  return this._withTxLock(async () => {
@@ -1060,6 +1115,13 @@ export class Wallet extends ReadonlyWallet {
1060
1115
  amount: params.amount,
1061
1116
  });
1062
1117
  }
1118
+ /**
1119
+ * Settle boarding inputs and/or virtual outputs into a finalized mainnet transaction.
1120
+ *
1121
+ * @param params - Optional settlement inputs and outputs. When omitted, the wallet settles all eligible funds.
1122
+ * @param eventCallback - Optional callback invoked for settlement stream events.
1123
+ * @returns The finalized Arkade transaction id
1124
+ */
1063
1125
  async settle(params, eventCallback) {
1064
1126
  return this._withTxLock(() => this._settleImpl(params, eventCallback));
1065
1127
  }
@@ -1077,7 +1139,7 @@ export class Wallet extends ReadonlyWallet {
1077
1139
  }
1078
1140
  }
1079
1141
  }
1080
- // if no params are provided, use all non expired boarding utxos and offchain vtxos as inputs
1142
+ // if no params are provided, use all non-expired boarding inputs and offchain virtual outputs as inputs
1081
1143
  // and send all to the offchain address
1082
1144
  if (!params) {
1083
1145
  const { fees } = await this.arkProvider.getInfo();
@@ -1098,7 +1160,7 @@ export class Wallet extends ReadonlyWallet {
1098
1160
  amount: BigInt(utxo.value),
1099
1161
  });
1100
1162
  if (inputFee.value >= utxo.value) {
1101
- // skip if fees are greater than the utxo value
1163
+ // skip if fees are greater than the boarding input value
1102
1164
  continue;
1103
1165
  }
1104
1166
  filteredBoardingUtxos.push(utxo);
@@ -1119,7 +1181,7 @@ export class Wallet extends ReadonlyWallet {
1119
1181
  : new Date(),
1120
1182
  });
1121
1183
  if (inputFee.value >= vtxo.value) {
1122
- // skip if fees are greater than the vtxo value
1184
+ // skip if fees are greater than the virtual output value
1123
1185
  continue;
1124
1186
  }
1125
1187
  filteredVtxos.push(vtxo);
@@ -1210,7 +1272,7 @@ export class Wallet extends ReadonlyWallet {
1210
1272
  const assetPacket = createAssetPacket(assetInputs, recipients);
1211
1273
  outputs.push(Extension.create([assetPacket]).txOut());
1212
1274
  }
1213
- // session holds the state of the musig2 signing process of the vtxo tree
1275
+ // session holds the state of the musig2 signing process of the virtual output tree
1214
1276
  let session;
1215
1277
  const signingPublicKeys = [];
1216
1278
  if (hasOffchainOutputs) {
@@ -1261,7 +1323,7 @@ export class Wallet extends ReadonlyWallet {
1261
1323
  for (const input of inputs) {
1262
1324
  // check if the input is an offchain "virtual" coin
1263
1325
  const vtxo = vtxos.find((vtxo) => vtxo.txid === input.txid && vtxo.vout === input.vout);
1264
- // boarding utxo, we need to sign the settlement tx
1326
+ // boarding input, we need to sign the settlement tx
1265
1327
  if (!vtxo) {
1266
1328
  for (let i = 0; i < settlementPsbt.inputsLength; i++) {
1267
1329
  const settlementInput = settlementPsbt.getInput(i);
@@ -1339,11 +1401,12 @@ export class Wallet extends ReadonlyWallet {
1339
1401
  }
1340
1402
  }
1341
1403
  /**
1342
- * @implements Batch.Handler interface.
1404
+ * Create a batch event handler for settlement flows.
1405
+ *
1343
1406
  * @param intentId - The intent ID.
1344
- * @param inputs - The inputs of the intent.
1345
- * @param session - The musig2 signing session, if not provided, the signing will be skipped.
1346
- * @param expectedRecipients - Expected recipients to validate in the vtxo tree.
1407
+ * @param inputs - Inputs used by the intent.
1408
+ * @param expectedRecipients - Expected recipients to validate in the virtual output tree.
1409
+ * @param session - Optional musig2 signing session. When omitted, signing steps are skipped.
1347
1410
  */
1348
1411
  createBatchHandler(intentId, inputs, expectedRecipients, session) {
1349
1412
  let sweepTapTreeRoot;
@@ -1357,7 +1420,7 @@ export class Wallet extends ReadonlyWallet {
1357
1420
  for (const idHash of event.intentIdHashes) {
1358
1421
  if (idHash === intentIdHashStr) {
1359
1422
  if (!this.arkProvider) {
1360
- throw new Error("Ark provider not configured");
1423
+ throw new Error("Arkade provider not configured");
1361
1424
  }
1362
1425
  await this.arkProvider.confirmRegistration(intentId);
1363
1426
  skip = false;
@@ -1390,10 +1453,10 @@ export class Wallet extends ReadonlyWallet {
1390
1453
  // not a cosigner, skip the signing
1391
1454
  return { skip: true };
1392
1455
  }
1393
- // validate the unsigned vtxo tree
1456
+ // validate the unsigned virtual output tree
1394
1457
  const commitmentTx = Transaction.fromPSBT(base64.decode(event.unsignedCommitmentTx));
1395
1458
  validateVtxoTxGraph(vtxoTree, commitmentTx, sweepTapTreeRoot);
1396
- // validate that all expected receivers are in the vtxo tree with correct amounts and assets
1459
+ // validate that all expected receivers are in the virtual output tree with correct amounts and assets
1397
1460
  if (expectedRecipients && expectedRecipients.length > 0) {
1398
1461
  validateBatchRecipients(commitmentTx, vtxoTree.leaves(), expectedRecipients, this.network);
1399
1462
  }
@@ -1494,7 +1557,7 @@ export class Wallet extends ReadonlyWallet {
1494
1557
  /**
1495
1558
  * Finalizes pending transactions by retrieving them from the server and finalizing each one.
1496
1559
  * Skips the server check entirely when no send was interrupted (no pending tx flag set).
1497
- * @param vtxos - Optional list of VTXOs to use instead of retrieving them from the server
1560
+ * @param vtxos - Optional list of virtual outputs to use instead of retrieving them from the server
1498
1561
  * @returns Array of transaction IDs that were finalized
1499
1562
  */
1500
1563
  async finalizePendingTxs(vtxos) {
@@ -1593,13 +1656,13 @@ export class Wallet extends ReadonlyWallet {
1593
1656
  /**
1594
1657
  * Send BTC and/or assets to one or more recipients.
1595
1658
  *
1596
- * @param recipients - Array of recipients with their addresses, BTC amounts, and assets
1597
- * @returns Promise resolving to the ark transaction ID
1659
+ * @param args - Recipients with their addresses, BTC amounts, and assets
1660
+ * @returns Promise resolving to the Arkade transaction ID
1598
1661
  *
1599
1662
  * @example
1600
1663
  * ```typescript
1601
1664
  * const txid = await wallet.send({
1602
- * address: 'ark1...',
1665
+ * address: 'ark1q...',
1603
1666
  * amount: 1000, // (optional, default to dust) btc amount to send to the output
1604
1667
  * assets: [{ assetId: 'abc123...', amount: 50 }] // (optional) list of assets to send
1605
1668
  * });
@@ -1747,8 +1810,8 @@ export class Wallet extends ReadonlyWallet {
1747
1810
  }
1748
1811
  /**
1749
1812
  * Build an offchain transaction from the given inputs and outputs,
1750
- * sign it, submit to the ark provider, and finalize.
1751
- * @returns The ark transaction id and server-signed checkpoint PSBTs (for bookkeeping)
1813
+ * sign it, submit to the Arkade provider, and finalize.
1814
+ * @returns The Arkade transaction id and server-signed checkpoint PSBTs (for bookkeeping)
1752
1815
  */
1753
1816
  async buildAndSubmitOffchainTx(inputs, outputs) {
1754
1817
  const offchainTx = buildOffchainTx(inputs.map((input) => {
@@ -1807,7 +1870,7 @@ export class Wallet extends ReadonlyWallet {
1807
1870
  }
1808
1871
  return { arkTxid, signedCheckpointTxs };
1809
1872
  }
1810
- // mark vtxo spent and save change vtxo if any
1873
+ // mark virtual outputs as spent, save change outputs if any
1811
1874
  async updateDbAfterOffchainTx(inputs, arkTxid, signedCheckpointTxs, sentAmount, changeAmount, changeVout, changeAssets) {
1812
1875
  try {
1813
1876
  const spentVtxos = [];
@@ -1855,7 +1918,7 @@ export class Wallet extends ReadonlyWallet {
1855
1918
  }
1856
1919
  const createdAt = Date.now();
1857
1920
  const addr = this.arkAddress.encode();
1858
- // Only save a change VTXO for preconfirmed coins (those with a batchExpiry).
1921
+ // Only save a change virtual output for preconfirmed coins (those with a batchExpiry).
1859
1922
  // Inputs without a batchExpiry are already settled/unrolled and don't need tracking.
1860
1923
  let changeVtxo;
1861
1924
  if (changeAmount > 0n && batchExpiry !== Number.MAX_SAFE_INTEGER) {
@@ -1899,7 +1962,7 @@ export class Wallet extends ReadonlyWallet {
1899
1962
  console.warn("error saving offchain tx to repository", e);
1900
1963
  }
1901
1964
  }
1902
- // mark vtxo spent & settled, remove boarding utxo
1965
+ // mark virtual outputs as spent/settled, remove boarding inputs
1903
1966
  async updateDbAfterSettle(inputs, commitmentTxid) {
1904
1967
  try {
1905
1968
  const addr = this.arkAddress.encode();
@@ -1910,7 +1973,7 @@ export class Wallet extends ReadonlyWallet {
1910
1973
  const isVtxo = (input) => "virtualStatus" in input;
1911
1974
  for (const input of inputs) {
1912
1975
  if (isVtxo(input)) {
1913
- // vtxo = mark it settled
1976
+ // virtual output = mark it settled
1914
1977
  const vtxo = extendVirtualCoin(this, input);
1915
1978
  if (vtxo.arkTxId) {
1916
1979
  inputArkTxIds.add(vtxo.arkTxId);
@@ -1926,7 +1989,7 @@ export class Wallet extends ReadonlyWallet {
1926
1989
  });
1927
1990
  }
1928
1991
  else {
1929
- // boarding utxo = remove it
1992
+ // boarding input = remove it
1930
1993
  boardingUtxoToRemove.add(`${input.txid}:${input.vout}`);
1931
1994
  }
1932
1995
  }
@@ -1950,13 +2013,13 @@ export class Wallet extends ReadonlyWallet {
1950
2013
  }
1951
2014
  Wallet.MIN_FEE_RATE = 1; // sats/vbyte
1952
2015
  /**
1953
- * Select virtual coins to reach a target amount, prioritizing those closer to expiry
1954
- * @param coins List of virtual coins to select from
2016
+ * Select virtual outputs to reach a target amount, prioritizing those closer to expiry
2017
+ * @param coins List of virtual outputs to select from
1955
2018
  * @param targetAmount Target amount to reach in satoshis
1956
- * @returns Selected coins and change amount
2019
+ * @returns Selected virtual outputs and change amount
1957
2020
  */
1958
2021
  export function selectVirtualCoins(coins, targetAmount) {
1959
- // Sort VTXOs by expiry (ascending) and amount (descending)
2022
+ // Sort virtual outputs by expiry (ascending) and amount (descending)
1960
2023
  const sortedCoins = [...coins].sort((a, b) => {
1961
2024
  // First sort by expiry if available
1962
2025
  const expiryA = a.virtualStatus.batchExpiry || Number.MAX_SAFE_INTEGER;
@@ -49,7 +49,7 @@ export class AsyncStorageTaskQueue {
49
49
  // ── Config persistence (for background handler rehydration) ──────
50
50
  /**
51
51
  * Persist a config blob alongside the queue data.
52
- * Used by {@link ExpoWallet.setup} to store the wallet parameters
52
+ * Used by @see ExpoWallet.setup to store the wallet parameters
53
53
  * that the background handler needs to reconstruct providers.
54
54
  */
55
55
  async persistConfig(config) {
@@ -3,7 +3,7 @@ export const CONTRACT_POLL_TASK_TYPE = "contract-poll";
3
3
  * Polls the indexer for the latest VTXO state of every contract and
4
4
  * persists the results to the wallet repository.
5
5
  *
6
- * Replicates the polling subset of {@link ContractManager.initialize}:
6
+ * Replicates the polling subset of @see ContractManager.initialize:
7
7
  * 1. Load all contracts from the contract repository.
8
8
  * 2. Mark expired active contracts as inactive.
9
9
  * 3. Paginated fetch of spendable VTXOs from the indexer.
@@ -26,7 +26,7 @@ export const contractPollProcessor = {
26
26
  contract.state = "inactive";
27
27
  await contractRepository.saveContract(contract);
28
28
  }
29
- // Paginated fetch of spendable VTXOs
29
+ // Paginated fetch of spendable virtual outputs
30
30
  const pageSize = 100;
31
31
  let pageIndex = 0;
32
32
  let hasMore = true;
@@ -4,7 +4,7 @@ import { getRandomId, extendVirtualCoin, extendVtxoFromContract, } from '../../w
4
4
  *
5
5
  * For each task in the inbox:
6
6
  * 1. Find the processor whose `taskType` matches `task.type`.
7
- * 2. Execute it, producing a {@link TaskResult}.
7
+ * 2. Execute it, producing a @see TaskResult.
8
8
  * 3. Push the result to the outbox and remove the task from the inbox.
9
9
  *
10
10
  * Tasks with no matching processor produce a `"noop"` result.
@@ -53,8 +53,8 @@ export async function runTasks(queue, processors, deps) {
53
53
  return results;
54
54
  }
55
55
  /**
56
- * Build the {@link TaskDependencies} needed by task processors
57
- * (e.g. {@link import("./processors").contractPollProcessor}).
56
+ * Build the @see TaskDependencies needed by task processors
57
+ * (e.g. `src/worker/expo/processors/contractPollProcessor.ts`)
58
58
  *
59
59
  * This is the same construction that `defineExpoBackgroundTask` does
60
60
  * internally, extracted so that consumers with custom schedulers