@arkade-os/sdk 0.4.10 → 0.4.12

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.
@@ -101,6 +101,20 @@ export interface SubscriptionHeartbeat {
101
101
  export interface SubscriptionEvent extends SubscriptionResponse {
102
102
  type: "event";
103
103
  }
104
+ export type GetVtxosOptions = PaginationOptions & {
105
+ spendableOnly?: boolean;
106
+ spentOnly?: boolean;
107
+ recoverableOnly?: boolean;
108
+ pendingOnly?: boolean;
109
+ after?: number;
110
+ before?: number;
111
+ } & ({
112
+ scripts: string[];
113
+ outpoints?: never;
114
+ } | {
115
+ outpoints: Outpoint[];
116
+ scripts?: never;
117
+ });
104
118
  export interface IndexerProvider {
105
119
  getVtxoTree(batchOutpoint: Outpoint, opts?: PaginationOptions): Promise<{
106
120
  vtxoTree: Tx[];
@@ -128,13 +142,7 @@ export interface IndexerProvider {
128
142
  page?: PageResponse;
129
143
  }>;
130
144
  getVtxoChain(vtxoOutpoint: Outpoint, opts?: PaginationOptions): Promise<VtxoChain>;
131
- getVtxos(opts?: PaginationOptions & {
132
- scripts?: string[];
133
- outpoints?: Outpoint[];
134
- spendableOnly?: boolean;
135
- spentOnly?: boolean;
136
- recoverableOnly?: boolean;
137
- }): Promise<{
145
+ getVtxos(opts?: GetVtxosOptions): Promise<{
138
146
  vtxos: VirtualCoin[];
139
147
  page?: PageResponse;
140
148
  }>;
@@ -180,13 +188,7 @@ export declare class RestIndexerProvider implements IndexerProvider {
180
188
  page?: PageResponse;
181
189
  }>;
182
190
  getVtxoChain(vtxoOutpoint: Outpoint, opts?: PaginationOptions): Promise<VtxoChain>;
183
- getVtxos(opts?: PaginationOptions & {
184
- scripts?: string[];
185
- outpoints?: Outpoint[];
186
- spendableOnly?: boolean;
187
- spentOnly?: boolean;
188
- recoverableOnly?: boolean;
189
- }): Promise<{
191
+ getVtxos(opts?: GetVtxosOptions): Promise<{
190
192
  vtxos: VirtualCoin[];
191
193
  page?: PageResponse;
192
194
  }>;
@@ -0,0 +1,58 @@
1
+ import { WalletRepository, WalletState } from "../repositories/walletRepository";
2
+ /** Lag behind real-time to avoid racing with indexer writes. */
3
+ export declare const SAFETY_LAG_MS = 30000;
4
+ /** Overlap window so boundary VTXOs are never missed. */
5
+ export declare const OVERLAP_MS = 60000;
6
+ type SyncCursors = Record<string, number>;
7
+ /**
8
+ * Atomically read, mutate, and persist wallet state.
9
+ * All callers that modify wallet state should go through this helper
10
+ * to avoid lost-update races between interleaved async operations.
11
+ */
12
+ export declare function updateWalletState(repo: WalletRepository, updater: (state: WalletState) => WalletState): Promise<void>;
13
+ /**
14
+ * Read the high-water mark for a single script.
15
+ * Returns `undefined` when the script has never been synced (bootstrap case).
16
+ */
17
+ export declare function getSyncCursor(repo: WalletRepository, script: string): Promise<number | undefined>;
18
+ /**
19
+ * Read cursors for every previously-synced script.
20
+ */
21
+ export declare function getAllSyncCursors(repo: WalletRepository): Promise<SyncCursors>;
22
+ /**
23
+ * Advance the cursor for one script after a successful delta sync.
24
+ * `cursor` should be the `before` cutoff used in the request.
25
+ */
26
+ export declare function advanceSyncCursor(repo: WalletRepository, script: string, cursor: number): Promise<void>;
27
+ /**
28
+ * Advance cursors for multiple scripts in a single write.
29
+ */
30
+ export declare function advanceSyncCursors(repo: WalletRepository, updates: Record<string, number>): Promise<void>;
31
+ /**
32
+ * Remove sync cursors, forcing a full re-bootstrap on next sync.
33
+ * When `scripts` is provided, only those cursors are cleared.
34
+ */
35
+ export declare function clearSyncCursors(repo: WalletRepository, scripts?: string[]): Promise<void>;
36
+ /**
37
+ * Compute the `after` lower-bound for a delta sync query.
38
+ * Returns `undefined` when the script has no cursor (bootstrap needed).
39
+ *
40
+ * No upper bound (`before`) is applied to the query so that freshly
41
+ * created VTXOs are never excluded. The safety lag is applied only
42
+ * when advancing the cursor (see {@link cursorCutoff}).
43
+ */
44
+ export declare function computeSyncWindow(cursor: number | undefined): {
45
+ after: number;
46
+ } | undefined;
47
+ /**
48
+ * The safe high-water mark for cursor advancement.
49
+ * Lags behind real-time by {@link SAFETY_LAG_MS} so that VTXOs still
50
+ * being indexed are re-queried on the next sync.
51
+ *
52
+ * When `requestStartedAt` is provided the cutoff is frozen to the
53
+ * request start rather than wall-clock at commit time, preventing
54
+ * long-running paginated fetches from advancing the cursor past the
55
+ * data they actually observed.
56
+ */
57
+ export declare function cursorCutoff(requestStartedAt?: number): number;
58
+ export {};
@@ -230,6 +230,11 @@ export type ResponseIsContractManagerWatching = ResponseEnvelope & {
230
230
  };
231
231
  export type RequestRefreshVtxos = RequestEnvelope & {
232
232
  type: "REFRESH_VTXOS";
233
+ payload?: {
234
+ scripts?: string[];
235
+ after?: number;
236
+ before?: number;
237
+ };
233
238
  };
234
239
  export type ResponseRefreshVtxos = ResponseEnvelope & {
235
240
  type: "REFRESH_VTXOS_SUCCESS";
@@ -474,8 +479,15 @@ export declare class WalletMessageHandler implements MessageHandler<WalletUpdate
474
479
  private getSpendableVtxos;
475
480
  private onWalletInitialized;
476
481
  /**
477
- * Force a full VTXO refresh from the indexer, then re-run bootstrap.
478
- * Used by RELOAD_WALLET to ensure fresh data.
482
+ * Refresh VTXOs, boarding UTXOs, and transaction history from cache.
483
+ * Shared by onWalletInitialized (full bootstrap) and reloadWallet
484
+ * (post-refresh), avoiding duplicate subscriptions and VtxoManager restarts.
485
+ */
486
+ private refreshCachedData;
487
+ /**
488
+ * Force a full VTXO refresh from the indexer, then refresh cached data.
489
+ * Used by RELOAD_WALLET to ensure fresh data without re-subscribing
490
+ * to incoming funds or restarting the VtxoManager.
479
491
  */
480
492
  private reloadWallet;
481
493
  private handleSettle;
@@ -171,6 +171,7 @@ export declare class VtxoManager implements AsyncDisposable, IVtxoManager {
171
171
  private knownBoardingUtxos;
172
172
  private sweptBoardingUtxos;
173
173
  private pollInProgress;
174
+ private pollDone?;
174
175
  private disposed;
175
176
  private consecutivePollFailures;
176
177
  private startupPollTimeoutId?;
@@ -296,7 +297,7 @@ export declare class VtxoManager implements AsyncDisposable, IVtxoManager {
296
297
  * }
297
298
  * ```
298
299
  */
299
- getExpiredBoardingUtxos(): Promise<ExtendedCoin[]>;
300
+ getExpiredBoardingUtxos(prefetchedUtxos?: ExtendedCoin[]): Promise<ExtendedCoin[]>;
300
301
  /**
301
302
  * Sweep expired boarding UTXOs back to a fresh boarding address via
302
303
  * the unilateral exit path (on-chain self-spend).
@@ -328,7 +329,7 @@ export declare class VtxoManager implements AsyncDisposable, IVtxoManager {
328
329
  * }
329
330
  * ```
330
331
  */
331
- sweepExpiredBoardingUtxos(): Promise<string>;
332
+ sweepExpiredBoardingUtxos(prefetchedUtxos?: ExtendedCoin[]): Promise<string>;
332
333
  /** Asserts sweep capability and returns the typed wallet. */
333
334
  private getSweepWallet;
334
335
  /** Decodes the boarding tapscript exit path to extract the CSV timelock. */
@@ -43,6 +43,7 @@ export declare class ReadonlyWallet implements IReadonlyWallet {
43
43
  private _contractManagerInitializing?;
44
44
  protected readonly watcherConfig?: ReadonlyWalletConfig["watcherConfig"];
45
45
  private readonly _assetManager;
46
+ private _syncVtxosInflight?;
46
47
  get assetManager(): IReadonlyAssetManager;
47
48
  protected constructor(identity: ReadonlyIdentity, network: Network, onchainProvider: OnchainProvider, indexerProvider: IndexerProvider, arkServerPublicKey: Bytes, offchainTapscript: DefaultVtxo.Script | DelegateVtxo.Script, boardingTapscript: DefaultVtxo.Script, dustAmount: bigint, walletRepository: WalletRepository, contractRepository: ContractRepository, delegatorProvider?: DelegatorProvider | undefined, watcherConfig?: ReadonlyWalletConfig["watcherConfig"]);
48
49
  /**
@@ -76,6 +77,22 @@ export declare class ReadonlyWallet implements IReadonlyWallet {
76
77
  getBalance(): Promise<WalletBalance>;
77
78
  getVtxos(filter?: GetVtxosFilter): Promise<ExtendedVirtualCoin[]>;
78
79
  getTransactionHistory(): Promise<ArkTransaction[]>;
80
+ /**
81
+ * Delta-sync wallet VTXOs: fetch only changed VTXOs since the last
82
+ * cursor, or do a full bootstrap when no cursor exists. Upserts
83
+ * the result into the cache and advances the sync cursors.
84
+ *
85
+ * Concurrent calls are deduplicated: if a sync is already in flight,
86
+ * subsequent callers receive the same promise instead of triggering
87
+ * a second network round-trip.
88
+ */
89
+ private syncVtxos;
90
+ private doSyncVtxos;
91
+ /**
92
+ * Clear all VTXO sync cursors, forcing a full re-bootstrap on next sync.
93
+ * Useful for recovery after indexer reprocessing or debugging.
94
+ */
95
+ clearSyncCursors(): Promise<void>;
79
96
  getBoardingTxs(): Promise<{
80
97
  boardingTxs: ArkTransaction[];
81
98
  commitmentsToIgnore: Set<string>;
@@ -233,6 +250,7 @@ export declare class Wallet extends ReadonlyWallet implements IWallet {
233
250
  makeGetPendingTxIntentSignature(coins: ExtendedVirtualCoin[]): Promise<SignedIntent<Intent.GetPendingTxMessage>>;
234
251
  /**
235
252
  * Finalizes pending transactions by retrieving them from the server and finalizing each one.
253
+ * Skips the server check entirely when no send was interrupted (no pending tx flag set).
236
254
  * @param vtxos - Optional list of VTXOs to use instead of retrieving them from the server
237
255
  * @returns Array of transaction IDs that were finalized
238
256
  */
@@ -240,6 +258,8 @@ export declare class Wallet extends ReadonlyWallet implements IWallet {
240
258
  finalized: string[];
241
259
  pending: string[];
242
260
  }>;
261
+ private hasPendingTxFlag;
262
+ private setPendingTxFlag;
243
263
  /**
244
264
  * Send BTC and/or assets to one or more recipients.
245
265
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkade-os/sdk",
3
- "version": "0.4.10",
3
+ "version": "0.4.12",
4
4
  "description": "Bitcoin wallet SDK with Taproot and Ark integration",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",
@@ -80,7 +80,7 @@
80
80
  "registry": "https://registry.npmjs.org/"
81
81
  },
82
82
  "dependencies": {
83
- "@kukks/bitcoin-descriptors": "3.1.0",
83
+ "@kukks/bitcoin-descriptors": "3.2.3",
84
84
  "@marcbachmann/cel-js": "7.3.1",
85
85
  "@noble/curves": "2.0.0",
86
86
  "@noble/secp256k1": "3.0.0",