@arkade-os/sdk 0.4.8 → 0.4.9
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.
- package/dist/cjs/contracts/contractManager.js +59 -11
- package/dist/cjs/contracts/contractWatcher.js +21 -2
- package/dist/cjs/providers/expoIndexer.js +1 -0
- package/dist/cjs/providers/indexer.js +1 -0
- package/dist/cjs/utils/transactionHistory.js +2 -1
- package/dist/cjs/wallet/serviceWorker/wallet-message-handler.js +109 -29
- package/dist/cjs/wallet/serviceWorker/wallet.js +22 -0
- package/dist/cjs/wallet/vtxo-manager.js +81 -50
- package/dist/cjs/wallet/wallet.js +46 -34
- package/dist/cjs/worker/messageBus.js +7 -0
- package/dist/esm/contracts/contractManager.js +59 -11
- package/dist/esm/contracts/contractWatcher.js +21 -2
- package/dist/esm/providers/expoIndexer.js +1 -0
- package/dist/esm/providers/indexer.js +1 -0
- package/dist/esm/utils/transactionHistory.js +2 -1
- package/dist/esm/wallet/serviceWorker/wallet-message-handler.js +109 -29
- package/dist/esm/wallet/serviceWorker/wallet.js +22 -0
- package/dist/esm/wallet/vtxo-manager.js +81 -50
- package/dist/esm/wallet/wallet.js +46 -34
- package/dist/esm/worker/messageBus.js +7 -0
- package/dist/types/contracts/contractManager.d.ts +10 -0
- package/dist/types/repositories/serialization.d.ts +1 -0
- package/dist/types/utils/transactionHistory.d.ts +1 -1
- package/dist/types/wallet/index.d.ts +2 -0
- package/dist/types/wallet/serviceWorker/wallet-message-handler.d.ts +23 -6
- package/dist/types/wallet/serviceWorker/wallet.d.ts +9 -1
- package/dist/types/wallet/vtxo-manager.d.ts +5 -0
- package/dist/types/worker/messageBus.d.ts +6 -0
- package/package.json +1 -1
|
@@ -152,7 +152,12 @@ export class VtxoManager {
|
|
|
152
152
|
this.knownBoardingUtxos = new Set();
|
|
153
153
|
this.sweptBoardingUtxos = new Set();
|
|
154
154
|
this.pollInProgress = false;
|
|
155
|
+
this.disposed = false;
|
|
155
156
|
this.consecutivePollFailures = 0;
|
|
157
|
+
// Guards against renewal feedback loop: when renewVtxos() settles, the
|
|
158
|
+
// server emits new VTXOs → vtxo_received → renewVtxos() again → infinite loop.
|
|
159
|
+
this.renewalInProgress = false;
|
|
160
|
+
this.lastRenewalTimestamp = 0;
|
|
156
161
|
// Normalize: prefer settlementConfig, fall back to renewalConfig, default to enabled
|
|
157
162
|
if (settlementConfig !== undefined) {
|
|
158
163
|
this.settlementConfig = settlementConfig;
|
|
@@ -336,32 +341,43 @@ export class VtxoManager {
|
|
|
336
341
|
* ```
|
|
337
342
|
*/
|
|
338
343
|
async renewVtxos(eventCallback) {
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
344
|
+
if (this.renewalInProgress) {
|
|
345
|
+
throw new Error("Renewal already in progress");
|
|
346
|
+
}
|
|
347
|
+
this.renewalInProgress = true;
|
|
348
|
+
try {
|
|
349
|
+
// Get all VTXOs (including recoverable ones)
|
|
350
|
+
// Use default threshold to bypass settlementConfig gate (manual API should always work)
|
|
351
|
+
const vtxos = await this.getExpiringVtxos(this.settlementConfig !== false &&
|
|
352
|
+
this.settlementConfig?.vtxoThreshold !== undefined
|
|
353
|
+
? this.settlementConfig.vtxoThreshold * 1000
|
|
354
|
+
: DEFAULT_RENEWAL_CONFIG.thresholdMs);
|
|
355
|
+
if (vtxos.length === 0) {
|
|
356
|
+
throw new Error("No VTXOs available to renew");
|
|
357
|
+
}
|
|
358
|
+
const totalAmount = vtxos.reduce((sum, vtxo) => sum + vtxo.value, 0);
|
|
359
|
+
// Get dust amount from wallet
|
|
360
|
+
const dustAmount = getDustAmount(this.wallet);
|
|
361
|
+
// Check if total amount is above dust threshold
|
|
362
|
+
if (BigInt(totalAmount) < dustAmount) {
|
|
363
|
+
throw new Error(`Total amount ${totalAmount} is below dust threshold ${dustAmount}`);
|
|
364
|
+
}
|
|
365
|
+
const arkAddress = await this.wallet.getAddress();
|
|
366
|
+
const txid = await this.wallet.settle({
|
|
367
|
+
inputs: vtxos,
|
|
368
|
+
outputs: [
|
|
369
|
+
{
|
|
370
|
+
address: arkAddress,
|
|
371
|
+
amount: BigInt(totalAmount),
|
|
372
|
+
},
|
|
373
|
+
],
|
|
374
|
+
}, eventCallback);
|
|
375
|
+
this.lastRenewalTimestamp = Date.now();
|
|
376
|
+
return txid;
|
|
377
|
+
}
|
|
378
|
+
finally {
|
|
379
|
+
this.renewalInProgress = false;
|
|
354
380
|
}
|
|
355
|
-
const arkAddress = await this.wallet.getAddress();
|
|
356
|
-
return this.wallet.settle({
|
|
357
|
-
inputs: vtxos,
|
|
358
|
-
outputs: [
|
|
359
|
-
{
|
|
360
|
-
address: arkAddress,
|
|
361
|
-
amount: BigInt(totalAmount),
|
|
362
|
-
},
|
|
363
|
-
],
|
|
364
|
-
}, eventCallback);
|
|
365
381
|
}
|
|
366
382
|
// ========== Boarding UTXO Sweep Methods ==========
|
|
367
383
|
/**
|
|
@@ -529,7 +545,11 @@ export class VtxoManager {
|
|
|
529
545
|
}
|
|
530
546
|
// Start polling for boarding UTXOs independently of contract manager
|
|
531
547
|
// SSE setup. Use a short delay to let the wallet finish construction.
|
|
532
|
-
setTimeout(() =>
|
|
548
|
+
this.startupPollTimeoutId = setTimeout(() => {
|
|
549
|
+
if (this.disposed)
|
|
550
|
+
return;
|
|
551
|
+
this.startBoardingUtxoPoll();
|
|
552
|
+
}, 1000);
|
|
533
553
|
try {
|
|
534
554
|
const [delegatorManager, contractManager, destination] = await Promise.all([
|
|
535
555
|
this.wallet.getDelegatorManager(),
|
|
@@ -540,28 +560,33 @@ export class VtxoManager {
|
|
|
540
560
|
if (event.type !== "vtxo_received") {
|
|
541
561
|
return;
|
|
542
562
|
}
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
563
|
+
const msSinceLastRenewal = Date.now() - this.lastRenewalTimestamp;
|
|
564
|
+
const shouldRenew = !this.renewalInProgress &&
|
|
565
|
+
msSinceLastRenewal >= VtxoManager.RENEWAL_COOLDOWN_MS;
|
|
566
|
+
if (shouldRenew) {
|
|
567
|
+
this.renewVtxos().catch((e) => {
|
|
568
|
+
if (e instanceof Error) {
|
|
569
|
+
if (e.message.includes("No VTXOs available to renew")) {
|
|
570
|
+
// Not an error, just no VTXO eligible for renewal.
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
if (e.message.includes("is below dust threshold")) {
|
|
574
|
+
// Not an error, just below dust threshold.
|
|
575
|
+
// As more VTXOs are received, the threshold will be raised.
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
if (e.message.includes("VTXO_ALREADY_REGISTERED") ||
|
|
579
|
+
e.message.includes("duplicated input")) {
|
|
580
|
+
// VTXO is already being used in a concurrent
|
|
581
|
+
// user-initiated operation. Skip silently — the
|
|
582
|
+
// wallet's tx lock serializes these, but the
|
|
583
|
+
// renewal will retry on the next cycle.
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
548
586
|
}
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
return;
|
|
553
|
-
}
|
|
554
|
-
if (e.message.includes("VTXO_ALREADY_REGISTERED") ||
|
|
555
|
-
e.message.includes("duplicated input")) {
|
|
556
|
-
// VTXO is already being used in a concurrent
|
|
557
|
-
// user-initiated operation. Skip silently — the
|
|
558
|
-
// wallet's tx lock serializes these, but the
|
|
559
|
-
// renewal will retry on the next cycle.
|
|
560
|
-
return;
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
console.error("Error renewing VTXOs:", e);
|
|
564
|
-
});
|
|
587
|
+
console.error("Error renewing VTXOs:", e);
|
|
588
|
+
});
|
|
589
|
+
}
|
|
565
590
|
delegatorManager
|
|
566
591
|
?.delegate(event.vtxos, destination)
|
|
567
592
|
.catch((e) => {
|
|
@@ -601,7 +626,7 @@ export class VtxoManager {
|
|
|
601
626
|
this.pollBoardingUtxos();
|
|
602
627
|
}
|
|
603
628
|
schedulePoll() {
|
|
604
|
-
if (this.settlementConfig === false)
|
|
629
|
+
if (this.disposed || this.settlementConfig === false)
|
|
605
630
|
return;
|
|
606
631
|
const delay = this.getNextPollDelay();
|
|
607
632
|
this.pollTimeoutId = setTimeout(() => this.pollBoardingUtxos(), delay);
|
|
@@ -675,8 +700,8 @@ export class VtxoManager {
|
|
|
675
700
|
const expired = boardingUtxos.filter((utxo) => hasBoardingTxExpired(utxo, boardingTimelock, chainTipHeight));
|
|
676
701
|
expiredSet = new Set(expired.map((u) => `${u.txid}:${u.vout}`));
|
|
677
702
|
}
|
|
678
|
-
catch {
|
|
679
|
-
|
|
703
|
+
catch (e) {
|
|
704
|
+
throw e instanceof Error ? e : new Error(String(e));
|
|
680
705
|
}
|
|
681
706
|
const unsettledUtxos = boardingUtxos.filter((u) => !this.knownBoardingUtxos.has(`${u.txid}:${u.vout}`) &&
|
|
682
707
|
!expiredSet.has(`${u.txid}:${u.vout}`));
|
|
@@ -698,6 +723,11 @@ export class VtxoManager {
|
|
|
698
723
|
}
|
|
699
724
|
async dispose() {
|
|
700
725
|
this.disposePromise ?? (this.disposePromise = (async () => {
|
|
726
|
+
this.disposed = true;
|
|
727
|
+
if (this.startupPollTimeoutId) {
|
|
728
|
+
clearTimeout(this.startupPollTimeoutId);
|
|
729
|
+
this.startupPollTimeoutId = undefined;
|
|
730
|
+
}
|
|
701
731
|
if (this.pollTimeoutId) {
|
|
702
732
|
clearTimeout(this.pollTimeoutId);
|
|
703
733
|
this.pollTimeoutId = undefined;
|
|
@@ -713,3 +743,4 @@ export class VtxoManager {
|
|
|
713
743
|
}
|
|
714
744
|
}
|
|
715
745
|
VtxoManager.MAX_BACKOFF_MS = 5 * 60 * 1000; // 5 minutes
|
|
746
|
+
VtxoManager.RENEWAL_COOLDOWN_MS = 30000; // 30 seconds
|
|
@@ -273,27 +273,33 @@ export class ReadonlyWallet {
|
|
|
273
273
|
const scriptMap = await this.getScriptMap();
|
|
274
274
|
const f = filter ?? { withRecoverable: true, withUnrolled: false };
|
|
275
275
|
const allExtended = [];
|
|
276
|
-
//
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
if (
|
|
286
|
-
|
|
287
|
-
|
|
276
|
+
// Batch all scripts into a single indexer call
|
|
277
|
+
const allScripts = [...scriptMap.keys()];
|
|
278
|
+
const response = await this.indexerProvider.getVtxos({
|
|
279
|
+
scripts: allScripts,
|
|
280
|
+
});
|
|
281
|
+
for (const vtxo of response.vtxos) {
|
|
282
|
+
const vtxoScript = vtxo.script
|
|
283
|
+
? scriptMap.get(vtxo.script)
|
|
284
|
+
: undefined;
|
|
285
|
+
if (!vtxoScript)
|
|
286
|
+
continue;
|
|
287
|
+
if (isSpendable(vtxo)) {
|
|
288
|
+
if (!f.withRecoverable &&
|
|
289
|
+
(isRecoverable(vtxo) || isExpired(vtxo))) {
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
288
292
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
forfeitTapLeafScript: vtxoScript.forfeit(),
|
|
293
|
-
intentTapLeafScript: vtxoScript.forfeit(),
|
|
294
|
-
tapTree: vtxoScript.encode(),
|
|
295
|
-
});
|
|
293
|
+
else {
|
|
294
|
+
if (!f.withUnrolled || !vtxo.isUnrolled)
|
|
295
|
+
continue;
|
|
296
296
|
}
|
|
297
|
+
allExtended.push({
|
|
298
|
+
...vtxo,
|
|
299
|
+
forfeitTapLeafScript: vtxoScript.forfeit(),
|
|
300
|
+
intentTapLeafScript: vtxoScript.forfeit(),
|
|
301
|
+
tapTree: vtxoScript.encode(),
|
|
302
|
+
});
|
|
297
303
|
}
|
|
298
304
|
// Update cache with fresh data
|
|
299
305
|
await this.walletRepository.saveVtxos(address, allExtended);
|
|
@@ -305,7 +311,7 @@ export class ReadonlyWallet {
|
|
|
305
311
|
const { boardingTxs, commitmentsToIgnore } = await this.getBoardingTxs();
|
|
306
312
|
const getTxCreatedAt = (txid) => this.indexerProvider
|
|
307
313
|
.getVtxos({ outpoints: [{ txid, vout: 0 }] })
|
|
308
|
-
.then((res) => res.vtxos[0]?.createdAt.getTime()
|
|
314
|
+
.then((res) => res.vtxos[0]?.createdAt.getTime());
|
|
309
315
|
return buildTransactionHistory(response.vtxos, boardingTxs, commitmentsToIgnore, getTxCreatedAt);
|
|
310
316
|
}
|
|
311
317
|
async getBoardingTxs() {
|
|
@@ -1338,23 +1344,29 @@ export class Wallet extends ReadonlyWallet {
|
|
|
1338
1344
|
async finalizePendingTxs(vtxos) {
|
|
1339
1345
|
const MAX_INPUTS_PER_INTENT = 20;
|
|
1340
1346
|
if (!vtxos || vtxos.length === 0) {
|
|
1341
|
-
//
|
|
1347
|
+
// Batch all scripts into a single indexer call
|
|
1342
1348
|
const scriptMap = await this.getScriptMap();
|
|
1343
1349
|
const allExtended = [];
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1350
|
+
const allScripts = [...scriptMap.keys()];
|
|
1351
|
+
const { vtxos: fetchedVtxos } = await this.indexerProvider.getVtxos({
|
|
1352
|
+
scripts: allScripts,
|
|
1353
|
+
});
|
|
1354
|
+
for (const vtxo of fetchedVtxos) {
|
|
1355
|
+
const vtxoScript = vtxo.script
|
|
1356
|
+
? scriptMap.get(vtxo.script)
|
|
1357
|
+
: undefined;
|
|
1358
|
+
if (!vtxoScript)
|
|
1359
|
+
continue;
|
|
1360
|
+
if (vtxo.virtualStatus.state === "swept" ||
|
|
1361
|
+
vtxo.virtualStatus.state === "settled") {
|
|
1362
|
+
continue;
|
|
1357
1363
|
}
|
|
1364
|
+
allExtended.push({
|
|
1365
|
+
...vtxo,
|
|
1366
|
+
forfeitTapLeafScript: vtxoScript.forfeit(),
|
|
1367
|
+
intentTapLeafScript: vtxoScript.forfeit(),
|
|
1368
|
+
tapTree: vtxoScript.encode(),
|
|
1369
|
+
});
|
|
1358
1370
|
}
|
|
1359
1371
|
if (allExtended.length === 0) {
|
|
1360
1372
|
return { finalized: [], pending: [] };
|
|
@@ -149,8 +149,12 @@ export class MessageBus {
|
|
|
149
149
|
identity,
|
|
150
150
|
arkServerUrl: config.arkServer.url,
|
|
151
151
|
arkServerPublicKey: config.arkServer.publicKey,
|
|
152
|
+
indexerUrl: config.indexerUrl,
|
|
153
|
+
esploraUrl: config.esploraUrl,
|
|
152
154
|
storage,
|
|
153
155
|
delegatorProvider,
|
|
156
|
+
settlementConfig: config.settlementConfig,
|
|
157
|
+
watcherConfig: config.watcherConfig,
|
|
154
158
|
});
|
|
155
159
|
return { wallet, arkProvider, readonlyWallet: wallet };
|
|
156
160
|
}
|
|
@@ -160,8 +164,11 @@ export class MessageBus {
|
|
|
160
164
|
identity,
|
|
161
165
|
arkServerUrl: config.arkServer.url,
|
|
162
166
|
arkServerPublicKey: config.arkServer.publicKey,
|
|
167
|
+
indexerUrl: config.indexerUrl,
|
|
168
|
+
esploraUrl: config.esploraUrl,
|
|
163
169
|
storage,
|
|
164
170
|
delegatorProvider,
|
|
171
|
+
watcherConfig: config.watcherConfig,
|
|
165
172
|
});
|
|
166
173
|
return { readonlyWallet, arkProvider };
|
|
167
174
|
}
|
|
@@ -102,6 +102,11 @@ export interface IContractManager extends Disposable {
|
|
|
102
102
|
* @returns Unsubscribe function
|
|
103
103
|
*/
|
|
104
104
|
onContractEvent(callback: ContractEventCallback): () => void;
|
|
105
|
+
/**
|
|
106
|
+
* Force a full VTXO refresh from the indexer for all contracts.
|
|
107
|
+
* Populates the wallet repository with complete VTXO history.
|
|
108
|
+
*/
|
|
109
|
+
refreshVtxos(): Promise<void>;
|
|
105
110
|
/**
|
|
106
111
|
* Whether the underlying watcher is currently active.
|
|
107
112
|
*/
|
|
@@ -292,6 +297,11 @@ export declare class ContractManager implements IContractManager {
|
|
|
292
297
|
* ```
|
|
293
298
|
*/
|
|
294
299
|
onContractEvent(callback: ContractEventCallback): () => void;
|
|
300
|
+
/**
|
|
301
|
+
* Force a full VTXO refresh from the indexer for all contracts.
|
|
302
|
+
* Populates the wallet repository with complete VTXO history.
|
|
303
|
+
*/
|
|
304
|
+
refreshVtxos(): Promise<void>;
|
|
295
305
|
/**
|
|
296
306
|
* Check if currently watching.
|
|
297
307
|
*/
|
|
@@ -11,5 +11,5 @@ type ExtendedArkTransaction = ArkTransaction & {
|
|
|
11
11
|
* @param {Set<string>} commitmentsToIgnore - A set of commitment IDs that should be excluded from processing.
|
|
12
12
|
* @return {ExtendedArkTransaction[]} A sorted array of extended Ark transactions, representing the transaction history.
|
|
13
13
|
*/
|
|
14
|
-
export declare function buildTransactionHistory(vtxos: VirtualCoin[], allBoardingTxs: ArkTransaction[], commitmentsToIgnore: Set<string>, getTxCreatedAt?: (txid: string) => Promise<number>): Promise<ExtendedArkTransaction[]>;
|
|
14
|
+
export declare function buildTransactionHistory(vtxos: VirtualCoin[], allBoardingTxs: ArkTransaction[], commitmentsToIgnore: Set<string>, getTxCreatedAt?: (txid: string) => Promise<number | undefined>): Promise<ExtendedArkTransaction[]>;
|
|
15
15
|
export {};
|
|
@@ -220,6 +220,8 @@ export interface VirtualCoin extends Coin {
|
|
|
220
220
|
isUnrolled: boolean;
|
|
221
221
|
isSpent?: boolean;
|
|
222
222
|
assets?: Asset[];
|
|
223
|
+
/** The scriptPubKey (hex) locking this VTXO, as returned by the indexer. */
|
|
224
|
+
script?: string;
|
|
223
225
|
}
|
|
224
226
|
export declare enum TxType {
|
|
225
227
|
TxSent = "SENT",
|
|
@@ -228,6 +228,12 @@ export type ResponseIsContractManagerWatching = ResponseEnvelope & {
|
|
|
228
228
|
isWatching: boolean;
|
|
229
229
|
};
|
|
230
230
|
};
|
|
231
|
+
export type RequestRefreshVtxos = RequestEnvelope & {
|
|
232
|
+
type: "REFRESH_VTXOS";
|
|
233
|
+
};
|
|
234
|
+
export type ResponseRefreshVtxos = ResponseEnvelope & {
|
|
235
|
+
type: "REFRESH_VTXOS_SUCCESS";
|
|
236
|
+
};
|
|
231
237
|
export type RequestGetAllSpendingPaths = RequestEnvelope & {
|
|
232
238
|
type: "GET_ALL_SPENDING_PATHS";
|
|
233
239
|
payload: {
|
|
@@ -432,8 +438,8 @@ export type ResponseSweepExpiredBoardingUtxos = ResponseEnvelope & {
|
|
|
432
438
|
txid: string;
|
|
433
439
|
};
|
|
434
440
|
};
|
|
435
|
-
export type WalletUpdaterRequest = RequestInitWallet | RequestSettle | RequestSendBitcoin | RequestGetAddress | RequestGetBoardingAddress | RequestGetBalance | RequestGetVtxos | RequestGetBoardingUtxos | RequestGetTransactionHistory | RequestGetStatus | RequestClear | RequestReloadWallet | RequestSignTransaction | RequestCreateContract | RequestGetContracts | RequestGetContractsWithVtxos | RequestUpdateContract | RequestDeleteContract | RequestGetSpendablePaths | RequestGetAllSpendingPaths | RequestIsContractManagerWatching | RequestSend | RequestGetAssetDetails | RequestIssue | RequestReissue | RequestBurn | RequestDelegate | RequestGetDelegateInfo | RequestRecoverVtxos | RequestGetRecoverableBalance | RequestGetExpiringVtxos | RequestRenewVtxos | RequestGetExpiredBoardingUtxos | RequestSweepExpiredBoardingUtxos;
|
|
436
|
-
export type WalletUpdaterResponse = ResponseEnvelope & (ResponseInitWallet | ResponseSettle | ResponseSettleEvent | ResponseSendBitcoin | ResponseGetAddress | ResponseGetBoardingAddress | ResponseGetBalance | ResponseGetVtxos | ResponseGetBoardingUtxos | ResponseGetTransactionHistory | ResponseGetStatus | ResponseClear | ResponseReloadWallet | ResponseUtxoUpdate | ResponseVtxoUpdate | ResponseSignTransaction | ResponseCreateContract | ResponseGetContracts | ResponseGetContractsWithVtxos | ResponseUpdateContract | ResponseDeleteContract | ResponseGetSpendablePaths | ResponseGetAllSpendingPaths | ResponseIsContractManagerWatching | ResponseContractEvent | ResponseSend | ResponseGetAssetDetails | ResponseIssue | ResponseReissue | ResponseBurn | ResponseDelegate | ResponseGetDelegateInfo | ResponseRecoverVtxos | ResponseRecoverVtxosEvent | ResponseGetRecoverableBalance | ResponseGetExpiringVtxos | ResponseRenewVtxos | ResponseRenewVtxosEvent | ResponseGetExpiredBoardingUtxos | ResponseSweepExpiredBoardingUtxos);
|
|
441
|
+
export type WalletUpdaterRequest = RequestInitWallet | RequestSettle | RequestSendBitcoin | RequestGetAddress | RequestGetBoardingAddress | RequestGetBalance | RequestGetVtxos | RequestGetBoardingUtxos | RequestGetTransactionHistory | RequestGetStatus | RequestClear | RequestReloadWallet | RequestSignTransaction | RequestCreateContract | RequestGetContracts | RequestGetContractsWithVtxos | RequestUpdateContract | RequestDeleteContract | RequestGetSpendablePaths | RequestGetAllSpendingPaths | RequestIsContractManagerWatching | RequestRefreshVtxos | RequestSend | RequestGetAssetDetails | RequestIssue | RequestReissue | RequestBurn | RequestDelegate | RequestGetDelegateInfo | RequestRecoverVtxos | RequestGetRecoverableBalance | RequestGetExpiringVtxos | RequestRenewVtxos | RequestGetExpiredBoardingUtxos | RequestSweepExpiredBoardingUtxos;
|
|
442
|
+
export type WalletUpdaterResponse = ResponseEnvelope & (ResponseInitWallet | ResponseSettle | ResponseSettleEvent | ResponseSendBitcoin | ResponseGetAddress | ResponseGetBoardingAddress | ResponseGetBalance | ResponseGetVtxos | ResponseGetBoardingUtxos | ResponseGetTransactionHistory | ResponseGetStatus | ResponseClear | ResponseReloadWallet | ResponseUtxoUpdate | ResponseVtxoUpdate | ResponseSignTransaction | ResponseCreateContract | ResponseGetContracts | ResponseGetContractsWithVtxos | ResponseUpdateContract | ResponseDeleteContract | ResponseGetSpendablePaths | ResponseGetAllSpendingPaths | ResponseIsContractManagerWatching | ResponseRefreshVtxos | ResponseContractEvent | ResponseSend | ResponseGetAssetDetails | ResponseIssue | ResponseReissue | ResponseBurn | ResponseDelegate | ResponseGetDelegateInfo | ResponseRecoverVtxos | ResponseRecoverVtxosEvent | ResponseGetRecoverableBalance | ResponseGetExpiringVtxos | ResponseRenewVtxos | ResponseRenewVtxosEvent | ResponseGetExpiredBoardingUtxos | ResponseSweepExpiredBoardingUtxos);
|
|
437
443
|
export declare class WalletMessageHandler implements MessageHandler<WalletUpdaterRequest, WalletUpdaterResponse> {
|
|
438
444
|
readonly messageTag: string;
|
|
439
445
|
private wallet;
|
|
@@ -463,19 +469,30 @@ export declare class WalletMessageHandler implements MessageHandler<WalletUpdate
|
|
|
463
469
|
private handleGetBalance;
|
|
464
470
|
private getAllBoardingUtxos;
|
|
465
471
|
/**
|
|
466
|
-
* Get spendable vtxos
|
|
472
|
+
* Get spendable vtxos from the repository
|
|
467
473
|
*/
|
|
468
474
|
private getSpendableVtxos;
|
|
475
|
+
private onWalletInitialized;
|
|
469
476
|
/**
|
|
470
|
-
*
|
|
477
|
+
* Force a full VTXO refresh from the indexer, then re-run bootstrap.
|
|
478
|
+
* Used by RELOAD_WALLET to ensure fresh data.
|
|
471
479
|
*/
|
|
472
|
-
private
|
|
473
|
-
private onWalletInitialized;
|
|
480
|
+
private reloadWallet;
|
|
474
481
|
private handleSettle;
|
|
475
482
|
private handleSendBitcoin;
|
|
476
483
|
private handleSignTransaction;
|
|
477
484
|
private handleDelegate;
|
|
478
485
|
private handleGetVtxos;
|
|
479
486
|
private clear;
|
|
487
|
+
/**
|
|
488
|
+
* Read all VTXOs from the repository, aggregated across all contract
|
|
489
|
+
* addresses and the wallet's primary address, with deduplication.
|
|
490
|
+
*/
|
|
491
|
+
private getVtxosFromRepo;
|
|
492
|
+
/**
|
|
493
|
+
* Build transaction history from cached VTXOs without hitting the indexer.
|
|
494
|
+
* Falls back to indexer only for uncached transaction timestamps.
|
|
495
|
+
*/
|
|
496
|
+
private buildTransactionHistoryFromCache;
|
|
480
497
|
private ensureContractEventBroadcasting;
|
|
481
498
|
}
|
|
@@ -6,7 +6,8 @@ import { ContractRepository } from "../../repositories/contractRepository";
|
|
|
6
6
|
import { RequestInitWallet, ResponseGetStatus, WalletUpdaterRequest, WalletUpdaterResponse } from "./wallet-message-handler";
|
|
7
7
|
import type { IContractManager } from "../../contracts/contractManager";
|
|
8
8
|
import type { IDelegatorManager } from "../delegator";
|
|
9
|
-
import type { IVtxoManager } from "../vtxo-manager";
|
|
9
|
+
import type { IVtxoManager, SettlementConfig } from "../vtxo-manager";
|
|
10
|
+
import type { ContractWatcherConfig } from "../../contracts/contractWatcher";
|
|
10
11
|
type PrivateKeyIdentity = Identity & {
|
|
11
12
|
toHex(): string;
|
|
12
13
|
};
|
|
@@ -45,12 +46,15 @@ type PrivateKeyIdentity = Identity & {
|
|
|
45
46
|
interface ServiceWorkerWalletOptions {
|
|
46
47
|
arkServerPublicKey?: string;
|
|
47
48
|
arkServerUrl: string;
|
|
49
|
+
indexerUrl?: string;
|
|
48
50
|
esploraUrl?: string;
|
|
49
51
|
storage?: StorageConfig;
|
|
50
52
|
identity: ReadonlyIdentity | Identity;
|
|
51
53
|
delegatorUrl?: string;
|
|
52
54
|
walletUpdaterTag?: string;
|
|
53
55
|
messageBusTimeoutMs?: number;
|
|
56
|
+
settlementConfig?: SettlementConfig | false;
|
|
57
|
+
watcherConfig?: Partial<Omit<ContractWatcherConfig, "indexerProvider">>;
|
|
54
58
|
}
|
|
55
59
|
export type ServiceWorkerWalletCreateOptions = ServiceWorkerWalletOptions & {
|
|
56
60
|
serviceWorker: ServiceWorker;
|
|
@@ -70,7 +74,11 @@ type MessageBusInitConfig = {
|
|
|
70
74
|
publicKey?: string;
|
|
71
75
|
};
|
|
72
76
|
delegatorUrl?: string;
|
|
77
|
+
indexerUrl?: string;
|
|
78
|
+
esploraUrl?: string;
|
|
73
79
|
timeoutMs?: number;
|
|
80
|
+
settlementConfig?: SettlementConfig | false;
|
|
81
|
+
watcherConfig?: Partial<Omit<ContractWatcherConfig, "indexerProvider">>;
|
|
74
82
|
};
|
|
75
83
|
export declare class ServiceWorkerReadonlyWallet implements IReadonlyWallet {
|
|
76
84
|
readonly serviceWorker: ServiceWorker;
|
|
@@ -171,8 +171,13 @@ export declare class VtxoManager implements AsyncDisposable, IVtxoManager {
|
|
|
171
171
|
private knownBoardingUtxos;
|
|
172
172
|
private sweptBoardingUtxos;
|
|
173
173
|
private pollInProgress;
|
|
174
|
+
private disposed;
|
|
174
175
|
private consecutivePollFailures;
|
|
176
|
+
private startupPollTimeoutId?;
|
|
175
177
|
private static readonly MAX_BACKOFF_MS;
|
|
178
|
+
private renewalInProgress;
|
|
179
|
+
private lastRenewalTimestamp;
|
|
180
|
+
private static readonly RENEWAL_COOLDOWN_MS;
|
|
176
181
|
constructor(wallet: IWallet,
|
|
177
182
|
/** @deprecated Use settlementConfig instead */
|
|
178
183
|
renewalConfig?: RenewalConfig | undefined, settlementConfig?: SettlementConfig | false);
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { ArkProvider } from "../providers/ark";
|
|
2
2
|
import { ReadonlyWallet, Wallet } from "../wallet/wallet";
|
|
3
|
+
import type { SettlementConfig } from "../wallet/vtxo-manager";
|
|
4
|
+
import type { ContractWatcherConfig } from "../contracts/contractWatcher";
|
|
3
5
|
import { ContractRepository, WalletRepository } from "../repositories";
|
|
4
6
|
export type RequestEnvelope = {
|
|
5
7
|
tag: string;
|
|
@@ -70,6 +72,10 @@ type Initialize = {
|
|
|
70
72
|
publicKey?: string;
|
|
71
73
|
};
|
|
72
74
|
delegatorUrl?: string;
|
|
75
|
+
indexerUrl?: string;
|
|
76
|
+
esploraUrl?: string;
|
|
77
|
+
settlementConfig?: SettlementConfig | false;
|
|
78
|
+
watcherConfig?: Partial<Omit<ContractWatcherConfig, "indexerProvider">>;
|
|
73
79
|
};
|
|
74
80
|
};
|
|
75
81
|
export declare class MessageBus {
|