@arkade-os/sdk 0.4.7 → 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/identity/seedIdentity.js +2 -2
- package/dist/cjs/index.js +9 -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 +249 -36
- package/dist/cjs/wallet/serviceWorker/wallet.js +286 -34
- package/dist/cjs/wallet/vtxo-manager.js +123 -86
- package/dist/cjs/wallet/wallet.js +140 -68
- package/dist/cjs/worker/errors.js +17 -0
- package/dist/cjs/worker/messageBus.js +14 -2
- package/dist/esm/contracts/contractManager.js +59 -11
- package/dist/esm/contracts/contractWatcher.js +21 -2
- package/dist/esm/identity/seedIdentity.js +2 -2
- package/dist/esm/index.js +3 -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 +245 -35
- package/dist/esm/wallet/serviceWorker/wallet.js +286 -34
- package/dist/esm/wallet/vtxo-manager.js +123 -86
- package/dist/esm/wallet/wallet.js +140 -68
- package/dist/esm/worker/errors.js +12 -0
- package/dist/esm/worker/messageBus.js +14 -2
- package/dist/types/contracts/contractManager.d.ts +10 -0
- package/dist/types/identity/seedIdentity.d.ts +5 -2
- package/dist/types/index.d.ts +5 -4
- 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 +101 -7
- package/dist/types/wallet/serviceWorker/wallet.d.ts +16 -0
- package/dist/types/wallet/vtxo-manager.d.ts +29 -2
- package/dist/types/wallet/wallet.d.ts +10 -0
- package/dist/types/worker/errors.d.ts +6 -0
- package/dist/types/worker/messageBus.d.ts +6 -0
- package/package.json +1 -1
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
import { RestIndexerProvider } from '../../providers/indexer.js';
|
|
2
2
|
import { isExpired, isRecoverable, isSpendable, isSubdust, } from '../index.js';
|
|
3
3
|
import { extendCoin, extendVirtualCoin } from '../utils.js';
|
|
4
|
+
import { buildTransactionHistory } from '../../utils/transactionHistory.js';
|
|
5
|
+
export class WalletNotInitializedError extends Error {
|
|
6
|
+
constructor() {
|
|
7
|
+
super("Wallet handler not initialized");
|
|
8
|
+
this.name = "WalletNotInitializedError";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export class ReadonlyWalletError extends Error {
|
|
12
|
+
constructor() {
|
|
13
|
+
super("Read-only wallet: operation requires signing");
|
|
14
|
+
this.name = "ReadonlyWalletError";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export class DelegatorNotConfiguredError extends Error {
|
|
18
|
+
constructor() {
|
|
19
|
+
super("Delegator not configured");
|
|
20
|
+
this.name = "DelegatorNotConfiguredError";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
4
23
|
export const DEFAULT_MESSAGE_TAG = "WALLET_UPDATER";
|
|
5
24
|
export class WalletMessageHandler {
|
|
6
25
|
/**
|
|
@@ -21,7 +40,31 @@ export class WalletMessageHandler {
|
|
|
21
40
|
this.walletRepository = repositories.walletRepository;
|
|
22
41
|
}
|
|
23
42
|
async stop() {
|
|
24
|
-
|
|
43
|
+
if (this.incomingFundsSubscription) {
|
|
44
|
+
this.incomingFundsSubscription();
|
|
45
|
+
this.incomingFundsSubscription = undefined;
|
|
46
|
+
}
|
|
47
|
+
if (this.contractEventsSubscription) {
|
|
48
|
+
this.contractEventsSubscription();
|
|
49
|
+
this.contractEventsSubscription = undefined;
|
|
50
|
+
}
|
|
51
|
+
// Dispose the wallet to stop VtxoManager background tasks
|
|
52
|
+
// (auto-renewal, boarding UTXO polling) and ContractWatcher.
|
|
53
|
+
try {
|
|
54
|
+
if (this.wallet) {
|
|
55
|
+
await this.wallet.dispose();
|
|
56
|
+
}
|
|
57
|
+
else if (this.readonlyWallet) {
|
|
58
|
+
await this.readonlyWallet.dispose();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch (_) {
|
|
62
|
+
// best-effort teardown
|
|
63
|
+
}
|
|
64
|
+
this.wallet = undefined;
|
|
65
|
+
this.readonlyWallet = undefined;
|
|
66
|
+
this.arkProvider = undefined;
|
|
67
|
+
this.indexerProvider = undefined;
|
|
25
68
|
}
|
|
26
69
|
async tick(_now) {
|
|
27
70
|
const results = await Promise.allSettled(this.onNextTick.map((fn) => fn()));
|
|
@@ -44,7 +87,7 @@ export class WalletMessageHandler {
|
|
|
44
87
|
}
|
|
45
88
|
requireWallet() {
|
|
46
89
|
if (!this.wallet) {
|
|
47
|
-
throw new
|
|
90
|
+
throw new ReadonlyWalletError();
|
|
48
91
|
}
|
|
49
92
|
return this.wallet;
|
|
50
93
|
}
|
|
@@ -66,7 +109,7 @@ export class WalletMessageHandler {
|
|
|
66
109
|
if (!this.readonlyWallet) {
|
|
67
110
|
return this.tagged({
|
|
68
111
|
id,
|
|
69
|
-
error: new
|
|
112
|
+
error: new WalletNotInitializedError(),
|
|
70
113
|
});
|
|
71
114
|
}
|
|
72
115
|
try {
|
|
@@ -127,7 +170,8 @@ export class WalletMessageHandler {
|
|
|
127
170
|
});
|
|
128
171
|
}
|
|
129
172
|
case "GET_TRANSACTION_HISTORY": {
|
|
130
|
-
const
|
|
173
|
+
const allVtxos = await this.getVtxosFromRepo();
|
|
174
|
+
const transactions = (await this.buildTransactionHistoryFromCache(allVtxos)) ?? [];
|
|
131
175
|
return this.tagged({
|
|
132
176
|
id,
|
|
133
177
|
type: "TRANSACTION_HISTORY",
|
|
@@ -154,7 +198,7 @@ export class WalletMessageHandler {
|
|
|
154
198
|
});
|
|
155
199
|
}
|
|
156
200
|
case "RELOAD_WALLET": {
|
|
157
|
-
await this.
|
|
201
|
+
await this.reloadWallet();
|
|
158
202
|
return this.tagged({
|
|
159
203
|
id,
|
|
160
204
|
type: "RELOAD_SUCCESS",
|
|
@@ -240,6 +284,14 @@ export class WalletMessageHandler {
|
|
|
240
284
|
payload: { isWatching },
|
|
241
285
|
});
|
|
242
286
|
}
|
|
287
|
+
case "REFRESH_VTXOS": {
|
|
288
|
+
const manager = await this.readonlyWallet.getContractManager();
|
|
289
|
+
await manager.refreshVtxos();
|
|
290
|
+
return this.tagged({
|
|
291
|
+
id,
|
|
292
|
+
type: "REFRESH_VTXOS_SUCCESS",
|
|
293
|
+
});
|
|
294
|
+
}
|
|
243
295
|
case "SEND": {
|
|
244
296
|
const { recipients } = message.payload;
|
|
245
297
|
const txid = await this.wallet.send(...recipients);
|
|
@@ -294,7 +346,7 @@ export class WalletMessageHandler {
|
|
|
294
346
|
const wallet = this.requireWallet();
|
|
295
347
|
const delegatorManager = await wallet.getDelegatorManager();
|
|
296
348
|
if (!delegatorManager) {
|
|
297
|
-
throw new
|
|
349
|
+
throw new DelegatorNotConfiguredError();
|
|
298
350
|
}
|
|
299
351
|
const info = await delegatorManager.getDelegateInfo();
|
|
300
352
|
return this.tagged({
|
|
@@ -303,6 +355,83 @@ export class WalletMessageHandler {
|
|
|
303
355
|
payload: { info },
|
|
304
356
|
});
|
|
305
357
|
}
|
|
358
|
+
case "RECOVER_VTXOS": {
|
|
359
|
+
const wallet = this.requireWallet();
|
|
360
|
+
const vtxoManager = await wallet.getVtxoManager();
|
|
361
|
+
const txid = await vtxoManager.recoverVtxos((e) => {
|
|
362
|
+
this.scheduleForNextTick(() => this.tagged({
|
|
363
|
+
id,
|
|
364
|
+
type: "RECOVER_VTXOS_EVENT",
|
|
365
|
+
payload: e,
|
|
366
|
+
}));
|
|
367
|
+
});
|
|
368
|
+
return this.tagged({
|
|
369
|
+
id,
|
|
370
|
+
type: "RECOVER_VTXOS_SUCCESS",
|
|
371
|
+
payload: { txid },
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
case "GET_RECOVERABLE_BALANCE": {
|
|
375
|
+
const wallet = this.requireWallet();
|
|
376
|
+
const vtxoManager = await wallet.getVtxoManager();
|
|
377
|
+
const balance = await vtxoManager.getRecoverableBalance();
|
|
378
|
+
return this.tagged({
|
|
379
|
+
id,
|
|
380
|
+
type: "RECOVERABLE_BALANCE",
|
|
381
|
+
payload: {
|
|
382
|
+
recoverable: balance.recoverable.toString(),
|
|
383
|
+
subdust: balance.subdust.toString(),
|
|
384
|
+
includesSubdust: balance.includesSubdust,
|
|
385
|
+
vtxoCount: balance.vtxoCount,
|
|
386
|
+
},
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
case "GET_EXPIRING_VTXOS": {
|
|
390
|
+
const wallet = this.requireWallet();
|
|
391
|
+
const vtxoManager = await wallet.getVtxoManager();
|
|
392
|
+
const vtxos = await vtxoManager.getExpiringVtxos(message.payload.thresholdMs);
|
|
393
|
+
return this.tagged({
|
|
394
|
+
id,
|
|
395
|
+
type: "EXPIRING_VTXOS",
|
|
396
|
+
payload: { vtxos },
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
case "RENEW_VTXOS": {
|
|
400
|
+
const wallet = this.requireWallet();
|
|
401
|
+
const vtxoManager = await wallet.getVtxoManager();
|
|
402
|
+
const txid = await vtxoManager.renewVtxos((e) => {
|
|
403
|
+
this.scheduleForNextTick(() => this.tagged({
|
|
404
|
+
id,
|
|
405
|
+
type: "RENEW_VTXOS_EVENT",
|
|
406
|
+
payload: e,
|
|
407
|
+
}));
|
|
408
|
+
});
|
|
409
|
+
return this.tagged({
|
|
410
|
+
id,
|
|
411
|
+
type: "RENEW_VTXOS_SUCCESS",
|
|
412
|
+
payload: { txid },
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
case "GET_EXPIRED_BOARDING_UTXOS": {
|
|
416
|
+
const wallet = this.requireWallet();
|
|
417
|
+
const vtxoManager = await wallet.getVtxoManager();
|
|
418
|
+
const utxos = await vtxoManager.getExpiredBoardingUtxos();
|
|
419
|
+
return this.tagged({
|
|
420
|
+
id,
|
|
421
|
+
type: "EXPIRED_BOARDING_UTXOS",
|
|
422
|
+
payload: { utxos },
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
case "SWEEP_EXPIRED_BOARDING_UTXOS": {
|
|
426
|
+
const wallet = this.requireWallet();
|
|
427
|
+
const vtxoManager = await wallet.getVtxoManager();
|
|
428
|
+
const txid = await vtxoManager.sweepExpiredBoardingUtxos();
|
|
429
|
+
return this.tagged({
|
|
430
|
+
id,
|
|
431
|
+
type: "SWEEP_EXPIRED_BOARDING_UTXOS_SUCCESS",
|
|
432
|
+
payload: { txid },
|
|
433
|
+
});
|
|
434
|
+
}
|
|
306
435
|
default:
|
|
307
436
|
console.error("Unknown message type", message);
|
|
308
437
|
throw new Error("Unknown message");
|
|
@@ -319,10 +448,9 @@ export class WalletMessageHandler {
|
|
|
319
448
|
await this.onWalletInitialized();
|
|
320
449
|
}
|
|
321
450
|
async handleGetBalance() {
|
|
322
|
-
const [boardingUtxos,
|
|
451
|
+
const [boardingUtxos, allVtxos] = await Promise.all([
|
|
323
452
|
this.getAllBoardingUtxos(),
|
|
324
|
-
this.
|
|
325
|
-
this.getSweptVtxos(),
|
|
453
|
+
this.getVtxosFromRepo(),
|
|
326
454
|
]);
|
|
327
455
|
// boarding
|
|
328
456
|
let confirmed = 0;
|
|
@@ -335,7 +463,9 @@ export class WalletMessageHandler {
|
|
|
335
463
|
unconfirmed += utxo.value;
|
|
336
464
|
}
|
|
337
465
|
}
|
|
338
|
-
// offchain
|
|
466
|
+
// offchain — split spendable vs swept from single repo read
|
|
467
|
+
const spendableVtxos = allVtxos.filter(isSpendable);
|
|
468
|
+
const sweptVtxos = allVtxos.filter((vtxo) => vtxo.virtualStatus.state === "swept");
|
|
339
469
|
let settled = 0;
|
|
340
470
|
let preconfirmed = 0;
|
|
341
471
|
let recoverable = 0;
|
|
@@ -385,23 +515,12 @@ export class WalletMessageHandler {
|
|
|
385
515
|
return this.readonlyWallet.getBoardingUtxos();
|
|
386
516
|
}
|
|
387
517
|
/**
|
|
388
|
-
* Get spendable vtxos
|
|
518
|
+
* Get spendable vtxos from the repository
|
|
389
519
|
*/
|
|
390
520
|
async getSpendableVtxos() {
|
|
391
|
-
|
|
392
|
-
return [];
|
|
393
|
-
const vtxos = await this.readonlyWallet.getVtxos();
|
|
521
|
+
const vtxos = await this.getVtxosFromRepo();
|
|
394
522
|
return vtxos.filter(isSpendable);
|
|
395
523
|
}
|
|
396
|
-
/**
|
|
397
|
-
* Get swept vtxos for the current wallet address
|
|
398
|
-
*/
|
|
399
|
-
async getSweptVtxos() {
|
|
400
|
-
if (!this.readonlyWallet)
|
|
401
|
-
return [];
|
|
402
|
-
const vtxos = await this.readonlyWallet.getVtxos();
|
|
403
|
-
return vtxos.filter((vtxo) => vtxo.virtualStatus.state === "swept");
|
|
404
|
-
}
|
|
405
524
|
async onWalletInitialized() {
|
|
406
525
|
if (!this.readonlyWallet ||
|
|
407
526
|
!this.arkProvider ||
|
|
@@ -409,10 +528,11 @@ export class WalletMessageHandler {
|
|
|
409
528
|
!this.walletRepository) {
|
|
410
529
|
return;
|
|
411
530
|
}
|
|
412
|
-
//
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
531
|
+
// Initialize contract manager FIRST — this populates the repository
|
|
532
|
+
// with full VTXO history for all contracts (one indexer call per contract)
|
|
533
|
+
await this.ensureContractEventBroadcasting();
|
|
534
|
+
// Read VTXOs from repository (now populated by contract manager)
|
|
535
|
+
const vtxos = await this.getVtxosFromRepo();
|
|
416
536
|
if (this.wallet) {
|
|
417
537
|
try {
|
|
418
538
|
// recover pending transactions if possible
|
|
@@ -424,15 +544,13 @@ export class WalletMessageHandler {
|
|
|
424
544
|
console.error("Error recovering pending transactions:", error);
|
|
425
545
|
}
|
|
426
546
|
}
|
|
427
|
-
// Get wallet address and save vtxos using unified repository
|
|
428
|
-
const address = await this.readonlyWallet.getAddress();
|
|
429
|
-
await this.walletRepository.saveVtxos(address, vtxos);
|
|
430
547
|
// Fetch boarding utxos and save using unified repository
|
|
431
548
|
const boardingAddress = await this.readonlyWallet.getBoardingAddress();
|
|
432
549
|
const coins = await this.readonlyWallet.onchainProvider.getCoins(boardingAddress);
|
|
433
550
|
await this.walletRepository.saveUtxos(boardingAddress, coins.map((utxo) => extendCoin(this.readonlyWallet, utxo)));
|
|
434
|
-
//
|
|
435
|
-
const
|
|
551
|
+
// Build transaction history from cached VTXOs (no indexer call)
|
|
552
|
+
const address = await this.readonlyWallet.getAddress();
|
|
553
|
+
const txs = await this.buildTransactionHistoryFromCache(vtxos);
|
|
436
554
|
if (txs)
|
|
437
555
|
await this.walletRepository.saveTransactions(address, txs);
|
|
438
556
|
// unsubscribe previous subscription if any
|
|
@@ -477,7 +595,28 @@ export class WalletMessageHandler {
|
|
|
477
595
|
}));
|
|
478
596
|
}
|
|
479
597
|
});
|
|
480
|
-
|
|
598
|
+
// Eagerly start the VtxoManager so its background tasks (auto-renewal,
|
|
599
|
+
// boarding UTXO polling/sweep) run inside the service worker without
|
|
600
|
+
// waiting for a client to send a vtxo-manager message first.
|
|
601
|
+
if (this.wallet) {
|
|
602
|
+
try {
|
|
603
|
+
await this.wallet.getVtxoManager();
|
|
604
|
+
}
|
|
605
|
+
catch (error) {
|
|
606
|
+
console.error("Error starting VtxoManager:", error);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Force a full VTXO refresh from the indexer, then re-run bootstrap.
|
|
612
|
+
* Used by RELOAD_WALLET to ensure fresh data.
|
|
613
|
+
*/
|
|
614
|
+
async reloadWallet() {
|
|
615
|
+
if (!this.readonlyWallet)
|
|
616
|
+
return;
|
|
617
|
+
const manager = await this.readonlyWallet.getContractManager();
|
|
618
|
+
await manager.refreshVtxos();
|
|
619
|
+
await this.onWalletInitialized();
|
|
481
620
|
}
|
|
482
621
|
async handleSettle(message) {
|
|
483
622
|
const wallet = this.requireWallet();
|
|
@@ -520,7 +659,7 @@ export class WalletMessageHandler {
|
|
|
520
659
|
const wallet = this.requireWallet();
|
|
521
660
|
const delegatorManager = await wallet.getDelegatorManager();
|
|
522
661
|
if (!delegatorManager) {
|
|
523
|
-
throw new
|
|
662
|
+
throw new DelegatorNotConfiguredError();
|
|
524
663
|
}
|
|
525
664
|
const { vtxoOutpoints, destination, delegateAt } = message.payload;
|
|
526
665
|
const allVtxos = await wallet.getVtxos();
|
|
@@ -547,7 +686,7 @@ export class WalletMessageHandler {
|
|
|
547
686
|
}
|
|
548
687
|
async handleGetVtxos(message) {
|
|
549
688
|
if (!this.readonlyWallet) {
|
|
550
|
-
throw new
|
|
689
|
+
throw new WalletNotInitializedError();
|
|
551
690
|
}
|
|
552
691
|
const vtxos = await this.getSpendableVtxos();
|
|
553
692
|
const dustAmount = this.readonlyWallet.dustAmount;
|
|
@@ -602,6 +741,77 @@ export class WalletMessageHandler {
|
|
|
602
741
|
this.arkProvider = undefined;
|
|
603
742
|
this.indexerProvider = undefined;
|
|
604
743
|
}
|
|
744
|
+
/**
|
|
745
|
+
* Read all VTXOs from the repository, aggregated across all contract
|
|
746
|
+
* addresses and the wallet's primary address, with deduplication.
|
|
747
|
+
*/
|
|
748
|
+
async getVtxosFromRepo() {
|
|
749
|
+
if (!this.walletRepository || !this.readonlyWallet)
|
|
750
|
+
return [];
|
|
751
|
+
const seen = new Set();
|
|
752
|
+
const allVtxos = [];
|
|
753
|
+
const addVtxos = (vtxos) => {
|
|
754
|
+
for (const vtxo of vtxos) {
|
|
755
|
+
const key = `${vtxo.txid}:${vtxo.vout}`;
|
|
756
|
+
if (!seen.has(key)) {
|
|
757
|
+
seen.add(key);
|
|
758
|
+
allVtxos.push(vtxo);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
};
|
|
762
|
+
// Aggregate VTXOs from all contract addresses
|
|
763
|
+
const manager = await this.readonlyWallet.getContractManager();
|
|
764
|
+
const contracts = await manager.getContracts();
|
|
765
|
+
for (const contract of contracts) {
|
|
766
|
+
const vtxos = await this.walletRepository.getVtxos(contract.address);
|
|
767
|
+
addVtxos(vtxos);
|
|
768
|
+
}
|
|
769
|
+
// Also check the wallet's primary address
|
|
770
|
+
const walletAddress = await this.readonlyWallet.getAddress();
|
|
771
|
+
const walletVtxos = await this.walletRepository.getVtxos(walletAddress);
|
|
772
|
+
addVtxos(walletVtxos);
|
|
773
|
+
return allVtxos;
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* Build transaction history from cached VTXOs without hitting the indexer.
|
|
777
|
+
* Falls back to indexer only for uncached transaction timestamps.
|
|
778
|
+
*/
|
|
779
|
+
async buildTransactionHistoryFromCache(vtxos) {
|
|
780
|
+
if (!this.readonlyWallet)
|
|
781
|
+
return null;
|
|
782
|
+
const { boardingTxs, commitmentsToIgnore } = await this.readonlyWallet.getBoardingTxs();
|
|
783
|
+
// Build a lookup for cached VTXO timestamps, keyed by txid.
|
|
784
|
+
// Multiple VTXOs can share a txid (different vouts) — we keep the
|
|
785
|
+
// earliest createdAt so the history ordering is stable.
|
|
786
|
+
const vtxoCreatedAt = new Map();
|
|
787
|
+
for (const vtxo of vtxos) {
|
|
788
|
+
const existing = vtxoCreatedAt.get(vtxo.txid);
|
|
789
|
+
const ts = vtxo.createdAt.getTime();
|
|
790
|
+
if (existing === undefined || ts < existing) {
|
|
791
|
+
vtxoCreatedAt.set(vtxo.txid, ts);
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
// getTxCreatedAt resolves the creation timestamp of a transaction.
|
|
795
|
+
// buildTransactionHistory calls this for spent-offchain VTXOs with
|
|
796
|
+
// no change outputs to determine the time of the sending tx.
|
|
797
|
+
// Returns undefined on miss so buildTransactionHistory uses its
|
|
798
|
+
// own fallback (vtxo.createdAt + 1) rather than epoch 0.
|
|
799
|
+
// The vout:0 lookup in the indexer fallback mirrors the pre-existing
|
|
800
|
+
// convention in ReadonlyWallet.getTransactionHistory().
|
|
801
|
+
const getTxCreatedAt = async (txid) => {
|
|
802
|
+
const cached = vtxoCreatedAt.get(txid);
|
|
803
|
+
if (cached !== undefined)
|
|
804
|
+
return cached;
|
|
805
|
+
if (this.indexerProvider) {
|
|
806
|
+
const res = await this.indexerProvider.getVtxos({
|
|
807
|
+
outpoints: [{ txid, vout: 0 }],
|
|
808
|
+
});
|
|
809
|
+
return res.vtxos[0]?.createdAt.getTime();
|
|
810
|
+
}
|
|
811
|
+
return undefined;
|
|
812
|
+
};
|
|
813
|
+
return buildTransactionHistory(vtxos, boardingTxs, commitmentsToIgnore, getTxCreatedAt);
|
|
814
|
+
}
|
|
605
815
|
async ensureContractEventBroadcasting() {
|
|
606
816
|
if (!this.readonlyWallet)
|
|
607
817
|
return;
|