@arkade-os/sdk 0.3.7 → 0.3.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/README.md +78 -1
- package/dist/cjs/identity/singleKey.js +33 -1
- package/dist/cjs/index.js +17 -2
- package/dist/cjs/intent/index.js +31 -2
- package/dist/cjs/providers/ark.js +9 -3
- package/dist/cjs/providers/indexer.js +2 -2
- package/dist/cjs/wallet/batch.js +183 -0
- package/dist/cjs/wallet/index.js +15 -0
- package/dist/cjs/wallet/serviceWorker/request.js +0 -2
- package/dist/cjs/wallet/serviceWorker/wallet.js +98 -34
- package/dist/cjs/wallet/serviceWorker/worker.js +169 -69
- package/dist/cjs/wallet/utils.js +2 -2
- package/dist/cjs/wallet/vtxo-manager.js +5 -0
- package/dist/cjs/wallet/wallet.js +399 -356
- package/dist/esm/identity/singleKey.js +31 -0
- package/dist/esm/index.js +12 -7
- package/dist/esm/intent/index.js +31 -2
- package/dist/esm/providers/ark.js +9 -3
- package/dist/esm/providers/indexer.js +2 -2
- package/dist/esm/wallet/batch.js +180 -0
- package/dist/esm/wallet/index.js +14 -0
- package/dist/esm/wallet/serviceWorker/request.js +0 -2
- package/dist/esm/wallet/serviceWorker/wallet.js +96 -33
- package/dist/esm/wallet/serviceWorker/worker.js +171 -71
- package/dist/esm/wallet/utils.js +2 -2
- package/dist/esm/wallet/vtxo-manager.js +6 -1
- package/dist/esm/wallet/wallet.js +400 -359
- package/dist/types/identity/index.d.ts +5 -3
- package/dist/types/identity/singleKey.d.ts +20 -1
- package/dist/types/index.d.ts +11 -8
- package/dist/types/intent/index.d.ts +19 -2
- package/dist/types/providers/ark.d.ts +9 -8
- package/dist/types/providers/indexer.d.ts +2 -2
- package/dist/types/wallet/batch.d.ts +87 -0
- package/dist/types/wallet/index.d.ts +75 -16
- package/dist/types/wallet/serviceWorker/request.d.ts +5 -1
- package/dist/types/wallet/serviceWorker/wallet.d.ts +46 -15
- package/dist/types/wallet/serviceWorker/worker.d.ts +6 -3
- package/dist/types/wallet/utils.d.ts +8 -3
- package/dist/types/wallet/wallet.d.ts +96 -35
- package/package.json +123 -113
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference lib="webworker" />
|
|
2
|
-
import { SingleKey } from '../../identity/singleKey.js';
|
|
3
|
-
import { isRecoverable, isSpendable, isSubdust, } from '../index.js';
|
|
4
|
-
import { Wallet } from '../wallet.js';
|
|
2
|
+
import { ReadonlySingleKey, SingleKey } from '../../identity/singleKey.js';
|
|
3
|
+
import { isExpired, isRecoverable, isSpendable, isSubdust, } from '../index.js';
|
|
4
|
+
import { ReadonlyWallet, Wallet } from '../wallet.js';
|
|
5
5
|
import { Request } from './request.js';
|
|
6
6
|
import { Response } from './response.js';
|
|
7
7
|
import { RestArkProvider } from '../../providers/ark.js';
|
|
@@ -12,9 +12,70 @@ import { IndexedDBStorageAdapter } from '../../storage/indexedDB.js';
|
|
|
12
12
|
import { WalletRepositoryImpl, } from '../../repositories/walletRepository.js';
|
|
13
13
|
import { extendCoin, extendVirtualCoin } from '../utils.js';
|
|
14
14
|
import { DEFAULT_DB_NAME } from './utils.js';
|
|
15
|
+
class ReadonlyHandler {
|
|
16
|
+
constructor(wallet) {
|
|
17
|
+
this.wallet = wallet;
|
|
18
|
+
}
|
|
19
|
+
get offchainTapscript() {
|
|
20
|
+
return this.wallet.offchainTapscript;
|
|
21
|
+
}
|
|
22
|
+
get boardingTapscript() {
|
|
23
|
+
return this.wallet.boardingTapscript;
|
|
24
|
+
}
|
|
25
|
+
get onchainProvider() {
|
|
26
|
+
return this.wallet.onchainProvider;
|
|
27
|
+
}
|
|
28
|
+
get dustAmount() {
|
|
29
|
+
return this.wallet.dustAmount;
|
|
30
|
+
}
|
|
31
|
+
get identity() {
|
|
32
|
+
return this.wallet.identity;
|
|
33
|
+
}
|
|
34
|
+
notifyIncomingFunds(...args) {
|
|
35
|
+
return this.wallet.notifyIncomingFunds(...args);
|
|
36
|
+
}
|
|
37
|
+
getAddress() {
|
|
38
|
+
return this.wallet.getAddress();
|
|
39
|
+
}
|
|
40
|
+
getBoardingAddress() {
|
|
41
|
+
return this.wallet.getBoardingAddress();
|
|
42
|
+
}
|
|
43
|
+
getBoardingTxs() {
|
|
44
|
+
return this.wallet.getBoardingTxs();
|
|
45
|
+
}
|
|
46
|
+
async handleReload(_) {
|
|
47
|
+
const pending = await this.wallet.fetchPendingTxs();
|
|
48
|
+
return { pending, finalized: [] };
|
|
49
|
+
}
|
|
50
|
+
async handleSettle(..._) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
async handleSendBitcoin(..._) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
class Handler extends ReadonlyHandler {
|
|
58
|
+
constructor(wallet) {
|
|
59
|
+
super(wallet);
|
|
60
|
+
this.wallet = wallet;
|
|
61
|
+
}
|
|
62
|
+
async handleReload(vtxos) {
|
|
63
|
+
return this.wallet.finalizePendingTxs(vtxos.filter((vtxo) => vtxo.virtualStatus.state !== "swept" &&
|
|
64
|
+
vtxo.virtualStatus.state !== "settled"));
|
|
65
|
+
}
|
|
66
|
+
async handleSettle(...args) {
|
|
67
|
+
return this.wallet.settle(...args);
|
|
68
|
+
}
|
|
69
|
+
async handleSendBitcoin(...args) {
|
|
70
|
+
return this.wallet.sendBitcoin(...args);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
15
73
|
/**
|
|
16
|
-
* Worker is a class letting to interact with ServiceWorkerWallet
|
|
17
|
-
* it aims to be run in a service worker context
|
|
74
|
+
* Worker is a class letting to interact with ServiceWorkerWallet and ServiceWorkerReadonlyWallet from
|
|
75
|
+
* the client; it aims to be run in a service worker context.
|
|
76
|
+
*
|
|
77
|
+
* The messages requiring a Wallet rather than a ReadonlyWallet result in no-op
|
|
78
|
+
* without errors.
|
|
18
79
|
*/
|
|
19
80
|
export class Worker {
|
|
20
81
|
constructor(dbName = DEFAULT_DB_NAME, dbVersion = 1, messageCallback = () => { }) {
|
|
@@ -28,9 +89,9 @@ export class Worker {
|
|
|
28
89
|
* Get spendable vtxos for the current wallet address
|
|
29
90
|
*/
|
|
30
91
|
async getSpendableVtxos() {
|
|
31
|
-
if (!this.
|
|
92
|
+
if (!this.handler)
|
|
32
93
|
return [];
|
|
33
|
-
const address = await this.
|
|
94
|
+
const address = await this.handler.getAddress();
|
|
34
95
|
const allVtxos = await this.walletRepository.getVtxos(address);
|
|
35
96
|
return allVtxos.filter(isSpendable);
|
|
36
97
|
}
|
|
@@ -38,9 +99,9 @@ export class Worker {
|
|
|
38
99
|
* Get swept vtxos for the current wallet address
|
|
39
100
|
*/
|
|
40
101
|
async getSweptVtxos() {
|
|
41
|
-
if (!this.
|
|
102
|
+
if (!this.handler)
|
|
42
103
|
return [];
|
|
43
|
-
const address = await this.
|
|
104
|
+
const address = await this.handler.getAddress();
|
|
44
105
|
const allVtxos = await this.walletRepository.getVtxos(address);
|
|
45
106
|
return allVtxos.filter((vtxo) => vtxo.virtualStatus.state === "swept");
|
|
46
107
|
}
|
|
@@ -48,9 +109,9 @@ export class Worker {
|
|
|
48
109
|
* Get all vtxos categorized by type
|
|
49
110
|
*/
|
|
50
111
|
async getAllVtxos() {
|
|
51
|
-
if (!this.
|
|
112
|
+
if (!this.handler)
|
|
52
113
|
return { spendable: [], spent: [] };
|
|
53
|
-
const address = await this.
|
|
114
|
+
const address = await this.handler.getAddress();
|
|
54
115
|
const allVtxos = await this.walletRepository.getVtxos(address);
|
|
55
116
|
return {
|
|
56
117
|
spendable: allVtxos.filter(isSpendable),
|
|
@@ -61,17 +122,17 @@ export class Worker {
|
|
|
61
122
|
* Get all boarding utxos from wallet repository
|
|
62
123
|
*/
|
|
63
124
|
async getAllBoardingUtxos() {
|
|
64
|
-
if (!this.
|
|
125
|
+
if (!this.handler)
|
|
65
126
|
return [];
|
|
66
|
-
const address = await this.
|
|
127
|
+
const address = await this.handler.getBoardingAddress();
|
|
67
128
|
return await this.walletRepository.getUtxos(address);
|
|
68
129
|
}
|
|
69
130
|
async getTransactionHistory() {
|
|
70
|
-
if (!this.
|
|
131
|
+
if (!this.handler)
|
|
71
132
|
return [];
|
|
72
133
|
let txs = [];
|
|
73
134
|
try {
|
|
74
|
-
const { boardingTxs, commitmentsToIgnore: roundsToIgnore } = await this.
|
|
135
|
+
const { boardingTxs, commitmentsToIgnore: roundsToIgnore } = await this.handler.getBoardingTxs();
|
|
75
136
|
const { spendable, spent } = await this.getAllVtxos();
|
|
76
137
|
// convert VTXOs to offchain transactions
|
|
77
138
|
const offchainTxs = vtxosToTxs(spendable, spent, roundsToIgnore);
|
|
@@ -114,7 +175,7 @@ export class Worker {
|
|
|
114
175
|
await this.storage.clear();
|
|
115
176
|
// Reset in-memory caches by recreating the repository
|
|
116
177
|
this.walletRepository = new WalletRepositoryImpl(this.storage);
|
|
117
|
-
this.
|
|
178
|
+
this.handler = undefined;
|
|
118
179
|
this.arkProvider = undefined;
|
|
119
180
|
this.indexerProvider = undefined;
|
|
120
181
|
}
|
|
@@ -122,26 +183,34 @@ export class Worker {
|
|
|
122
183
|
await this.onWalletInitialized();
|
|
123
184
|
}
|
|
124
185
|
async onWalletInitialized() {
|
|
125
|
-
if (!this.
|
|
186
|
+
if (!this.handler ||
|
|
126
187
|
!this.arkProvider ||
|
|
127
188
|
!this.indexerProvider ||
|
|
128
|
-
!this.
|
|
129
|
-
!this.
|
|
189
|
+
!this.handler.offchainTapscript ||
|
|
190
|
+
!this.handler.boardingTapscript) {
|
|
130
191
|
return;
|
|
131
192
|
}
|
|
132
193
|
// Get public key script and set the initial vtxos state
|
|
133
|
-
const script = hex.encode(this.
|
|
194
|
+
const script = hex.encode(this.handler.offchainTapscript.pkScript);
|
|
134
195
|
const response = await this.indexerProvider.getVtxos({
|
|
135
196
|
scripts: [script],
|
|
136
197
|
});
|
|
137
|
-
const vtxos = response.vtxos.map((vtxo) => extendVirtualCoin(this.
|
|
198
|
+
const vtxos = response.vtxos.map((vtxo) => extendVirtualCoin(this.handler, vtxo));
|
|
199
|
+
try {
|
|
200
|
+
// recover pending transactions if possible
|
|
201
|
+
const { pending, finalized } = await this.handler.handleReload(vtxos);
|
|
202
|
+
console.info(`Recovered ${finalized.length}/${pending.length} pending transactions: ${finalized.join(", ")}`);
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
console.error("Error recovering pending transactions:", error);
|
|
206
|
+
}
|
|
138
207
|
// Get wallet address and save vtxos using unified repository
|
|
139
|
-
const address = await this.
|
|
208
|
+
const address = await this.handler.getAddress();
|
|
140
209
|
await this.walletRepository.saveVtxos(address, vtxos);
|
|
141
210
|
// Fetch boarding utxos and save using unified repository
|
|
142
|
-
const boardingAddress = await this.
|
|
143
|
-
const coins = await this.
|
|
144
|
-
await this.walletRepository.saveUtxos(boardingAddress, coins.map((utxo) => extendCoin(this.
|
|
211
|
+
const boardingAddress = await this.handler.getBoardingAddress();
|
|
212
|
+
const coins = await this.handler.onchainProvider.getCoins(boardingAddress);
|
|
213
|
+
await this.walletRepository.saveUtxos(boardingAddress, coins.map((utxo) => extendCoin(this.handler, utxo)));
|
|
145
214
|
// Get transaction history to cache boarding txs
|
|
146
215
|
const txs = await this.getTransactionHistory();
|
|
147
216
|
if (txs)
|
|
@@ -150,13 +219,13 @@ export class Worker {
|
|
|
150
219
|
if (this.incomingFundsSubscription)
|
|
151
220
|
this.incomingFundsSubscription();
|
|
152
221
|
// subscribe for incoming funds and notify all clients when new funds arrive
|
|
153
|
-
this.incomingFundsSubscription = await this.
|
|
222
|
+
this.incomingFundsSubscription = await this.handler.notifyIncomingFunds(async (funds) => {
|
|
154
223
|
if (funds.type === "vtxo") {
|
|
155
224
|
const newVtxos = funds.newVtxos.length > 0
|
|
156
|
-
? funds.newVtxos.map((vtxo) => extendVirtualCoin(this.
|
|
225
|
+
? funds.newVtxos.map((vtxo) => extendVirtualCoin(this.handler, vtxo))
|
|
157
226
|
: [];
|
|
158
227
|
const spentVtxos = funds.spentVtxos.length > 0
|
|
159
|
-
? funds.spentVtxos.map((vtxo) => extendVirtualCoin(this.
|
|
228
|
+
? funds.spentVtxos.map((vtxo) => extendVirtualCoin(this.handler, vtxo))
|
|
160
229
|
: [];
|
|
161
230
|
if ([...newVtxos, ...spentVtxos].length === 0)
|
|
162
231
|
return;
|
|
@@ -169,8 +238,8 @@ export class Worker {
|
|
|
169
238
|
await this.sendMessageToAllClients(Response.vtxoUpdate(newVtxos, spentVtxos));
|
|
170
239
|
}
|
|
171
240
|
if (funds.type === "utxo") {
|
|
172
|
-
const utxos = funds.coins.map((utxo) => extendCoin(this.
|
|
173
|
-
const boardingAddress = await this.
|
|
241
|
+
const utxos = funds.coins.map((utxo) => extendCoin(this.handler, utxo));
|
|
242
|
+
const boardingAddress = await this.handler?.getBoardingAddress();
|
|
174
243
|
// save utxos using unified repository
|
|
175
244
|
await this.walletRepository.clearUtxos(boardingAddress);
|
|
176
245
|
await this.walletRepository.saveUtxos(boardingAddress, utxos);
|
|
@@ -186,31 +255,46 @@ export class Worker {
|
|
|
186
255
|
}
|
|
187
256
|
}
|
|
188
257
|
async handleInitWallet(event) {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
event.source?.postMessage(Response.error(message.id, "Invalid INIT_WALLET message format"));
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
if (!message.privateKey) {
|
|
196
|
-
const err = "Missing privateKey";
|
|
197
|
-
event.source?.postMessage(Response.error(message.id, err));
|
|
198
|
-
console.error(err);
|
|
258
|
+
if (!Request.isInitWallet(event.data)) {
|
|
259
|
+
console.error("Invalid INIT_WALLET message format", event.data);
|
|
260
|
+
event.source?.postMessage(Response.error(event.data.id, "Invalid INIT_WALLET message format"));
|
|
199
261
|
return;
|
|
200
262
|
}
|
|
263
|
+
const message = event.data;
|
|
264
|
+
const { arkServerPublicKey, arkServerUrl } = message;
|
|
265
|
+
this.arkProvider = new RestArkProvider(arkServerUrl);
|
|
266
|
+
this.indexerProvider = new RestIndexerProvider(arkServerUrl);
|
|
201
267
|
try {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
268
|
+
if ("privateKey" in message.key &&
|
|
269
|
+
typeof message.key.privateKey === "string") {
|
|
270
|
+
const { key: { privateKey }, } = message;
|
|
271
|
+
const identity = SingleKey.fromHex(privateKey);
|
|
272
|
+
const wallet = await Wallet.create({
|
|
273
|
+
identity,
|
|
274
|
+
arkServerUrl,
|
|
275
|
+
arkServerPublicKey,
|
|
276
|
+
storage: this.storage, // Use unified storage for wallet too
|
|
277
|
+
});
|
|
278
|
+
this.handler = new Handler(wallet);
|
|
279
|
+
}
|
|
280
|
+
else if ("publicKey" in message.key &&
|
|
281
|
+
typeof message.key.publicKey === "string") {
|
|
282
|
+
const { key: { publicKey }, } = message;
|
|
283
|
+
const identity = ReadonlySingleKey.fromPublicKey(hex.decode(publicKey));
|
|
284
|
+
const wallet = await ReadonlyWallet.create({
|
|
285
|
+
identity,
|
|
286
|
+
arkServerUrl,
|
|
287
|
+
arkServerPublicKey,
|
|
288
|
+
storage: this.storage, // Use unified storage for wallet too
|
|
289
|
+
});
|
|
290
|
+
this.handler = new ReadonlyHandler(wallet);
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
const err = "Missing privateKey or publicKey in key object";
|
|
294
|
+
event.source?.postMessage(Response.error(message.id, err));
|
|
295
|
+
console.error(err);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
214
298
|
}
|
|
215
299
|
catch (error) {
|
|
216
300
|
console.error("Error initializing wallet:", error);
|
|
@@ -218,7 +302,10 @@ export class Worker {
|
|
|
218
302
|
? error.message
|
|
219
303
|
: "Unknown error occurred";
|
|
220
304
|
event.source?.postMessage(Response.error(message.id, errorMessage));
|
|
305
|
+
return;
|
|
221
306
|
}
|
|
307
|
+
event.source?.postMessage(Response.walletInitialized(message.id));
|
|
308
|
+
await this.onWalletInitialized();
|
|
222
309
|
}
|
|
223
310
|
async handleSettle(event) {
|
|
224
311
|
const message = event.data;
|
|
@@ -228,15 +315,20 @@ export class Worker {
|
|
|
228
315
|
return;
|
|
229
316
|
}
|
|
230
317
|
try {
|
|
231
|
-
if (!this.
|
|
318
|
+
if (!this.handler) {
|
|
232
319
|
console.error("Wallet not initialized");
|
|
233
320
|
event.source?.postMessage(Response.error(message.id, "Wallet not initialized"));
|
|
234
321
|
return;
|
|
235
322
|
}
|
|
236
|
-
const txid = await this.
|
|
323
|
+
const txid = await this.handler.handleSettle(message.params, (e) => {
|
|
237
324
|
event.source?.postMessage(Response.settleEvent(message.id, e));
|
|
238
325
|
});
|
|
239
|
-
|
|
326
|
+
if (txid) {
|
|
327
|
+
event.source?.postMessage(Response.settleSuccess(message.id, txid));
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
event.source?.postMessage(Response.error(message.id, "Operation not supported in readonly mode"));
|
|
331
|
+
}
|
|
240
332
|
}
|
|
241
333
|
catch (error) {
|
|
242
334
|
console.error("Error settling:", error);
|
|
@@ -253,14 +345,19 @@ export class Worker {
|
|
|
253
345
|
event.source?.postMessage(Response.error(message.id, "Invalid SEND_BITCOIN message format"));
|
|
254
346
|
return;
|
|
255
347
|
}
|
|
256
|
-
if (!this.
|
|
348
|
+
if (!this.handler) {
|
|
257
349
|
console.error("Wallet not initialized");
|
|
258
350
|
event.source?.postMessage(Response.error(message.id, "Wallet not initialized"));
|
|
259
351
|
return;
|
|
260
352
|
}
|
|
261
353
|
try {
|
|
262
|
-
const txid = await this.
|
|
263
|
-
|
|
354
|
+
const txid = await this.handler.handleSendBitcoin(message.params);
|
|
355
|
+
if (txid) {
|
|
356
|
+
event.source?.postMessage(Response.sendBitcoinSuccess(message.id, txid));
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
event.source?.postMessage(Response.error(message.id, "Operation not supported in readonly mode"));
|
|
360
|
+
}
|
|
264
361
|
}
|
|
265
362
|
catch (error) {
|
|
266
363
|
console.error("Error sending bitcoin:", error);
|
|
@@ -277,13 +374,13 @@ export class Worker {
|
|
|
277
374
|
event.source?.postMessage(Response.error(message.id, "Invalid GET_ADDRESS message format"));
|
|
278
375
|
return;
|
|
279
376
|
}
|
|
280
|
-
if (!this.
|
|
377
|
+
if (!this.handler) {
|
|
281
378
|
console.error("Wallet not initialized");
|
|
282
379
|
event.source?.postMessage(Response.error(message.id, "Wallet not initialized"));
|
|
283
380
|
return;
|
|
284
381
|
}
|
|
285
382
|
try {
|
|
286
|
-
const address = await this.
|
|
383
|
+
const address = await this.handler.getAddress();
|
|
287
384
|
event.source?.postMessage(Response.address(message.id, address));
|
|
288
385
|
}
|
|
289
386
|
catch (error) {
|
|
@@ -301,13 +398,13 @@ export class Worker {
|
|
|
301
398
|
event.source?.postMessage(Response.error(message.id, "Invalid GET_BOARDING_ADDRESS message format"));
|
|
302
399
|
return;
|
|
303
400
|
}
|
|
304
|
-
if (!this.
|
|
401
|
+
if (!this.handler) {
|
|
305
402
|
console.error("Wallet not initialized");
|
|
306
403
|
event.source?.postMessage(Response.error(message.id, "Wallet not initialized"));
|
|
307
404
|
return;
|
|
308
405
|
}
|
|
309
406
|
try {
|
|
310
|
-
const address = await this.
|
|
407
|
+
const address = await this.handler.getBoardingAddress();
|
|
311
408
|
event.source?.postMessage(Response.boardingAddress(message.id, address));
|
|
312
409
|
}
|
|
313
410
|
catch (error) {
|
|
@@ -325,7 +422,7 @@ export class Worker {
|
|
|
325
422
|
event.source?.postMessage(Response.error(message.id, "Invalid GET_BALANCE message format"));
|
|
326
423
|
return;
|
|
327
424
|
}
|
|
328
|
-
if (!this.
|
|
425
|
+
if (!this.handler) {
|
|
329
426
|
console.error("Wallet not initialized");
|
|
330
427
|
event.source?.postMessage(Response.error(message.id, "Wallet not initialized"));
|
|
331
428
|
return;
|
|
@@ -394,14 +491,14 @@ export class Worker {
|
|
|
394
491
|
event.source?.postMessage(Response.error(message.id, "Invalid GET_VTXOS message format"));
|
|
395
492
|
return;
|
|
396
493
|
}
|
|
397
|
-
if (!this.
|
|
494
|
+
if (!this.handler) {
|
|
398
495
|
console.error("Wallet not initialized");
|
|
399
496
|
event.source?.postMessage(Response.error(message.id, "Wallet not initialized"));
|
|
400
497
|
return;
|
|
401
498
|
}
|
|
402
499
|
try {
|
|
403
500
|
const vtxos = await this.getSpendableVtxos();
|
|
404
|
-
const dustAmount = this.
|
|
501
|
+
const dustAmount = this.handler.dustAmount;
|
|
405
502
|
const includeRecoverable = message.filter?.withRecoverable ?? false;
|
|
406
503
|
const filteredVtxos = includeRecoverable
|
|
407
504
|
? vtxos
|
|
@@ -412,6 +509,9 @@ export class Worker {
|
|
|
412
509
|
if (isRecoverable(v)) {
|
|
413
510
|
return false;
|
|
414
511
|
}
|
|
512
|
+
if (isExpired(v)) {
|
|
513
|
+
return false;
|
|
514
|
+
}
|
|
415
515
|
return true;
|
|
416
516
|
});
|
|
417
517
|
event.source?.postMessage(Response.vtxos(message.id, filteredVtxos));
|
|
@@ -431,7 +531,7 @@ export class Worker {
|
|
|
431
531
|
event.source?.postMessage(Response.error(message.id, "Invalid GET_BOARDING_UTXOS message format"));
|
|
432
532
|
return;
|
|
433
533
|
}
|
|
434
|
-
if (!this.
|
|
534
|
+
if (!this.handler) {
|
|
435
535
|
console.error("Wallet not initialized");
|
|
436
536
|
event.source?.postMessage(Response.error(message.id, "Wallet not initialized"));
|
|
437
537
|
return;
|
|
@@ -455,7 +555,7 @@ export class Worker {
|
|
|
455
555
|
event.source?.postMessage(Response.error(message.id, "Invalid GET_TRANSACTION_HISTORY message format"));
|
|
456
556
|
return;
|
|
457
557
|
}
|
|
458
|
-
if (!this.
|
|
558
|
+
if (!this.handler) {
|
|
459
559
|
console.error("Wallet not initialized");
|
|
460
560
|
event.source?.postMessage(Response.error(message.id, "Wallet not initialized"));
|
|
461
561
|
return;
|
|
@@ -479,10 +579,10 @@ export class Worker {
|
|
|
479
579
|
event.source?.postMessage(Response.error(message.id, "Invalid GET_STATUS message format"));
|
|
480
580
|
return;
|
|
481
581
|
}
|
|
482
|
-
const pubKey = this.
|
|
483
|
-
? await this.
|
|
582
|
+
const pubKey = this.handler
|
|
583
|
+
? await this.handler.identity.xOnlyPublicKey()
|
|
484
584
|
: undefined;
|
|
485
|
-
event.source?.postMessage(Response.walletStatus(message.id, this.
|
|
585
|
+
event.source?.postMessage(Response.walletStatus(message.id, this.handler !== undefined, pubKey));
|
|
486
586
|
}
|
|
487
587
|
async handleMessage(event) {
|
|
488
588
|
this.messageCallback(event);
|
|
@@ -561,7 +661,7 @@ export class Worker {
|
|
|
561
661
|
event.source?.postMessage(Response.error(message.id, "Invalid RELOAD_WALLET message format"));
|
|
562
662
|
return;
|
|
563
663
|
}
|
|
564
|
-
if (!this.
|
|
664
|
+
if (!this.handler) {
|
|
565
665
|
console.error("Wallet not initialized");
|
|
566
666
|
event.source?.postMessage(Response.walletReloaded(message.id, false));
|
|
567
667
|
return;
|
package/dist/esm/wallet/utils.js
CHANGED
|
@@ -2,7 +2,7 @@ export function extendVirtualCoin(wallet, vtxo) {
|
|
|
2
2
|
return {
|
|
3
3
|
...vtxo,
|
|
4
4
|
forfeitTapLeafScript: wallet.offchainTapscript.forfeit(),
|
|
5
|
-
intentTapLeafScript: wallet.offchainTapscript.
|
|
5
|
+
intentTapLeafScript: wallet.offchainTapscript.forfeit(),
|
|
6
6
|
tapTree: wallet.offchainTapscript.encode(),
|
|
7
7
|
};
|
|
8
8
|
}
|
|
@@ -10,7 +10,7 @@ export function extendCoin(wallet, utxo) {
|
|
|
10
10
|
return {
|
|
11
11
|
...utxo,
|
|
12
12
|
forfeitTapLeafScript: wallet.boardingTapscript.forfeit(),
|
|
13
|
-
intentTapLeafScript: wallet.boardingTapscript.
|
|
13
|
+
intentTapLeafScript: wallet.boardingTapscript.forfeit(),
|
|
14
14
|
tapTree: wallet.boardingTapscript.encode(),
|
|
15
15
|
};
|
|
16
16
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isRecoverable, isSubdust } from './index.js';
|
|
1
|
+
import { isExpired, isRecoverable, isSpendable, isSubdust, } from './index.js';
|
|
2
2
|
export const DEFAULT_THRESHOLD_MS = 3 * 24 * 60 * 60 * 1000; // 3 days
|
|
3
3
|
/**
|
|
4
4
|
* Default renewal configuration values
|
|
@@ -26,6 +26,10 @@ function getRecoverableVtxos(vtxos, dustAmount) {
|
|
|
26
26
|
if (isRecoverable(vtxo)) {
|
|
27
27
|
return true;
|
|
28
28
|
}
|
|
29
|
+
// also include vtxos that are not swept but expired
|
|
30
|
+
if (isSpendable(vtxo) && isExpired(vtxo)) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
29
33
|
// Recover preconfirmed subdust to consolidate small amounts
|
|
30
34
|
if (vtxo.virtualStatus.state === "preconfirmed" &&
|
|
31
35
|
isSubdust(vtxo, dustAmount)) {
|
|
@@ -100,6 +104,7 @@ export function isVtxoExpiringSoon(vtxo, thresholdMs // in milliseconds
|
|
|
100
104
|
export function getExpiringAndRecoverableVtxos(vtxos, thresholdMs, dustAmount) {
|
|
101
105
|
return vtxos.filter((vtxo) => isVtxoExpiringSoon(vtxo, thresholdMs) ||
|
|
102
106
|
isRecoverable(vtxo) ||
|
|
107
|
+
(isSpendable(vtxo) && isExpired(vtxo)) ||
|
|
103
108
|
isSubdust(vtxo, dustAmount));
|
|
104
109
|
}
|
|
105
110
|
/**
|