@arkade-os/sdk 0.3.8 → 0.3.10

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 (41) hide show
  1. package/README.md +78 -1
  2. package/dist/cjs/identity/singleKey.js +33 -1
  3. package/dist/cjs/index.js +17 -2
  4. package/dist/cjs/intent/index.js +31 -2
  5. package/dist/cjs/providers/ark.js +15 -5
  6. package/dist/cjs/providers/indexer.js +2 -2
  7. package/dist/cjs/wallet/batch.js +183 -0
  8. package/dist/cjs/wallet/index.js +15 -0
  9. package/dist/cjs/wallet/serviceWorker/request.js +0 -2
  10. package/dist/cjs/wallet/serviceWorker/wallet.js +98 -34
  11. package/dist/cjs/wallet/serviceWorker/worker.js +163 -72
  12. package/dist/cjs/wallet/utils.js +2 -2
  13. package/dist/cjs/wallet/vtxo-manager.js +5 -0
  14. package/dist/cjs/wallet/wallet.js +358 -360
  15. package/dist/esm/identity/singleKey.js +31 -0
  16. package/dist/esm/index.js +12 -7
  17. package/dist/esm/intent/index.js +31 -2
  18. package/dist/esm/providers/ark.js +15 -5
  19. package/dist/esm/providers/indexer.js +2 -2
  20. package/dist/esm/wallet/batch.js +180 -0
  21. package/dist/esm/wallet/index.js +14 -0
  22. package/dist/esm/wallet/serviceWorker/request.js +0 -2
  23. package/dist/esm/wallet/serviceWorker/wallet.js +96 -33
  24. package/dist/esm/wallet/serviceWorker/worker.js +165 -74
  25. package/dist/esm/wallet/utils.js +2 -2
  26. package/dist/esm/wallet/vtxo-manager.js +6 -1
  27. package/dist/esm/wallet/wallet.js +359 -363
  28. package/dist/types/identity/index.d.ts +5 -3
  29. package/dist/types/identity/singleKey.d.ts +20 -1
  30. package/dist/types/index.d.ts +11 -8
  31. package/dist/types/intent/index.d.ts +19 -2
  32. package/dist/types/providers/ark.d.ts +9 -8
  33. package/dist/types/providers/indexer.d.ts +2 -2
  34. package/dist/types/wallet/batch.d.ts +87 -0
  35. package/dist/types/wallet/index.d.ts +76 -16
  36. package/dist/types/wallet/serviceWorker/request.d.ts +5 -1
  37. package/dist/types/wallet/serviceWorker/wallet.d.ts +46 -15
  38. package/dist/types/wallet/serviceWorker/worker.d.ts +6 -3
  39. package/dist/types/wallet/utils.d.ts +8 -3
  40. package/dist/types/wallet/wallet.d.ts +87 -36
  41. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ServiceWorkerWallet = void 0;
3
+ exports.ServiceWorkerWallet = exports.ServiceWorkerReadonlyWallet = void 0;
4
4
  const response_1 = require("./response");
5
5
  const base_1 = require("@scure/base");
6
6
  const indexedDB_1 = require("../../storage/indexedDB");
@@ -16,7 +16,16 @@ class UnexpectedResponseError extends Error {
16
16
  this.name = "UnexpectedResponseError";
17
17
  }
18
18
  }
19
- class ServiceWorkerWallet {
19
+ const createCommon = (options) => {
20
+ // Default to IndexedDB for service worker context
21
+ const storage = new indexedDB_1.IndexedDBStorageAdapter(options.dbName || utils_1.DEFAULT_DB_NAME, options.dbVersion);
22
+ // Create repositories
23
+ return {
24
+ walletRepo: new walletRepository_1.WalletRepositoryImpl(storage),
25
+ contractRepo: new contractRepository_1.ContractRepositoryImpl(storage),
26
+ };
27
+ };
28
+ class ServiceWorkerReadonlyWallet {
20
29
  constructor(serviceWorker, identity, walletRepository, contractRepository) {
21
30
  this.serviceWorker = serviceWorker;
22
31
  this.identity = identity;
@@ -24,27 +33,17 @@ class ServiceWorkerWallet {
24
33
  this.contractRepository = contractRepository;
25
34
  }
26
35
  static async create(options) {
27
- // Default to IndexedDB for service worker context
28
- const storage = new indexedDB_1.IndexedDBStorageAdapter(options.dbName || utils_1.DEFAULT_DB_NAME, options.dbVersion);
29
- // Create repositories
30
- const walletRepo = new walletRepository_1.WalletRepositoryImpl(storage);
31
- const contractRepo = new contractRepository_1.ContractRepositoryImpl(storage);
32
- // Extract identity and check if it can expose private key
33
- const identity = isPrivateKeyIdentity(options.identity)
34
- ? options.identity
35
- : null;
36
- if (!identity) {
37
- throw new Error("ServiceWorkerWallet.create() requires a Identity that can expose a single private key");
38
- }
39
- // Extract private key for service worker initialization
40
- const privateKey = identity.toHex();
36
+ const { walletRepo, contractRepo } = createCommon(options);
41
37
  // Create the wallet instance
42
- const wallet = new ServiceWorkerWallet(options.serviceWorker, identity, walletRepo, contractRepo);
38
+ const wallet = new ServiceWorkerReadonlyWallet(options.serviceWorker, options.identity, walletRepo, contractRepo);
39
+ const publicKey = await options.identity
40
+ .compressedPublicKey()
41
+ .then(base_1.hex.encode);
43
42
  // Initialize the service worker with the config
44
43
  const initMessage = {
45
44
  type: "INIT_WALLET",
46
45
  id: getRandomId(),
47
- privateKey,
46
+ key: { publicKey },
48
47
  arkServerUrl: options.arkServerUrl,
49
48
  arkServerPublicKey: options.arkServerPublicKey,
50
49
  };
@@ -59,14 +58,14 @@ class ServiceWorkerWallet {
59
58
  * @example
60
59
  * ```typescript
61
60
  * // One-liner setup - handles everything automatically!
62
- * const wallet = await ServiceWorkerWallet.setup({
61
+ * const wallet = await ServiceWorkerReadonlyWallet.setup({
63
62
  * serviceWorkerPath: '/service-worker.js',
64
63
  * arkServerUrl: 'https://mutinynet.arkade.sh'
65
64
  * });
66
65
  *
67
- * // With custom identity
68
- * const identity = SingleKey.fromHex('your_private_key_hex');
69
- * const wallet = await ServiceWorkerWallet.setup({
66
+ * // With custom readonly identity
67
+ * const identity = ReadonlySingleKey.fromPublicKey('your_public_key_hex');
68
+ * const wallet = await ServiceWorkerReadonlyWallet.setup({
70
69
  * serviceWorkerPath: '/service-worker.js',
71
70
  * arkServerUrl: 'https://mutinynet.arkade.sh',
72
71
  * identity
@@ -77,7 +76,7 @@ class ServiceWorkerWallet {
77
76
  // Register and setup the service worker
78
77
  const serviceWorker = await (0, utils_1.setupServiceWorker)(options.serviceWorkerPath);
79
78
  // Use the existing create method
80
- return ServiceWorkerWallet.create({
79
+ return ServiceWorkerReadonlyWallet.create({
81
80
  ...options,
82
81
  serviceWorker,
83
82
  });
@@ -229,6 +228,82 @@ class ServiceWorkerWallet {
229
228
  throw new Error(`Failed to get vtxos: ${error}`);
230
229
  }
231
230
  }
231
+ async reload() {
232
+ const message = {
233
+ type: "RELOAD_WALLET",
234
+ id: getRandomId(),
235
+ };
236
+ const response = await this.sendMessage(message);
237
+ if (response_1.Response.isWalletReloaded(response)) {
238
+ return response.success;
239
+ }
240
+ throw new UnexpectedResponseError(response);
241
+ }
242
+ }
243
+ exports.ServiceWorkerReadonlyWallet = ServiceWorkerReadonlyWallet;
244
+ class ServiceWorkerWallet extends ServiceWorkerReadonlyWallet {
245
+ constructor(serviceWorker, identity, walletRepository, contractRepository) {
246
+ super(serviceWorker, identity, walletRepository, contractRepository);
247
+ this.serviceWorker = serviceWorker;
248
+ this.identity = identity;
249
+ this.walletRepository = walletRepository;
250
+ this.contractRepository = contractRepository;
251
+ }
252
+ static async create(options) {
253
+ const { walletRepo, contractRepo } = createCommon(options);
254
+ // Extract identity and check if it can expose private key
255
+ const identity = isPrivateKeyIdentity(options.identity)
256
+ ? options.identity
257
+ : null;
258
+ if (!identity) {
259
+ throw new Error("ServiceWorkerWallet.create() requires a Identity that can expose a single private key");
260
+ }
261
+ // Extract private key for service worker initialization
262
+ const privateKey = identity.toHex();
263
+ // Create the wallet instance
264
+ const wallet = new ServiceWorkerWallet(options.serviceWorker, identity, walletRepo, contractRepo);
265
+ // Initialize the service worker with the config
266
+ const initMessage = {
267
+ type: "INIT_WALLET",
268
+ id: getRandomId(),
269
+ key: { privateKey },
270
+ arkServerUrl: options.arkServerUrl,
271
+ arkServerPublicKey: options.arkServerPublicKey,
272
+ };
273
+ // Initialize the service worker
274
+ await wallet.sendMessage(initMessage);
275
+ return wallet;
276
+ }
277
+ /**
278
+ * Simplified setup method that handles service worker registration,
279
+ * identity creation, and wallet initialization automatically.
280
+ *
281
+ * @example
282
+ * ```typescript
283
+ * // One-liner setup - handles everything automatically!
284
+ * const wallet = await ServiceWorkerWallet.setup({
285
+ * serviceWorkerPath: '/service-worker.js',
286
+ * arkServerUrl: 'https://mutinynet.arkade.sh'
287
+ * });
288
+ *
289
+ * // With custom identity
290
+ * const identity = SingleKey.fromHex('your_private_key_hex');
291
+ * const wallet = await ServiceWorkerWallet.setup({
292
+ * serviceWorkerPath: '/service-worker.js',
293
+ * arkServerUrl: 'https://mutinynet.arkade.sh',
294
+ * identity
295
+ * });
296
+ * ```
297
+ */
298
+ static async setup(options) {
299
+ // Register and setup the service worker
300
+ const serviceWorker = await (0, utils_1.setupServiceWorker)(options.serviceWorkerPath);
301
+ // Use the existing create method
302
+ return ServiceWorkerWallet.create({
303
+ ...options,
304
+ serviceWorker,
305
+ });
306
+ }
232
307
  async sendBitcoin(params) {
233
308
  const message = {
234
309
  type: "SEND_BITCOIN",
@@ -286,17 +361,6 @@ class ServiceWorkerWallet {
286
361
  throw new Error(`Settlement failed: ${error}`);
287
362
  }
288
363
  }
289
- async reload() {
290
- const message = {
291
- type: "RELOAD_WALLET",
292
- id: getRandomId(),
293
- };
294
- const response = await this.sendMessage(message);
295
- if (response_1.Response.isWalletReloaded(response)) {
296
- return response.success;
297
- }
298
- throw new UnexpectedResponseError(response);
299
- }
300
364
  }
301
365
  exports.ServiceWorkerWallet = ServiceWorkerWallet;
302
366
  function getRandomId() {
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
+ /// <reference lib="webworker" />
2
3
  Object.defineProperty(exports, "__esModule", { value: true });
3
4
  exports.Worker = void 0;
4
- /// <reference lib="webworker" />
5
5
  const singleKey_1 = require("../../identity/singleKey");
6
6
  const __1 = require("..");
7
7
  const wallet_1 = require("../wallet");
@@ -15,9 +15,70 @@ const indexedDB_1 = require("../../storage/indexedDB");
15
15
  const walletRepository_1 = require("../../repositories/walletRepository");
16
16
  const utils_1 = require("../utils");
17
17
  const utils_2 = require("./utils");
18
+ class ReadonlyHandler {
19
+ constructor(wallet) {
20
+ this.wallet = wallet;
21
+ }
22
+ get offchainTapscript() {
23
+ return this.wallet.offchainTapscript;
24
+ }
25
+ get boardingTapscript() {
26
+ return this.wallet.boardingTapscript;
27
+ }
28
+ get onchainProvider() {
29
+ return this.wallet.onchainProvider;
30
+ }
31
+ get dustAmount() {
32
+ return this.wallet.dustAmount;
33
+ }
34
+ get identity() {
35
+ return this.wallet.identity;
36
+ }
37
+ notifyIncomingFunds(...args) {
38
+ return this.wallet.notifyIncomingFunds(...args);
39
+ }
40
+ getAddress() {
41
+ return this.wallet.getAddress();
42
+ }
43
+ getBoardingAddress() {
44
+ return this.wallet.getBoardingAddress();
45
+ }
46
+ getBoardingTxs() {
47
+ return this.wallet.getBoardingTxs();
48
+ }
49
+ async handleReload(_) {
50
+ const pending = await this.wallet.fetchPendingTxs();
51
+ return { pending, finalized: [] };
52
+ }
53
+ async handleSettle(..._) {
54
+ return undefined;
55
+ }
56
+ async handleSendBitcoin(..._) {
57
+ return undefined;
58
+ }
59
+ }
60
+ class Handler extends ReadonlyHandler {
61
+ constructor(wallet) {
62
+ super(wallet);
63
+ this.wallet = wallet;
64
+ }
65
+ async handleReload(vtxos) {
66
+ return this.wallet.finalizePendingTxs(vtxos.filter((vtxo) => vtxo.virtualStatus.state !== "swept" &&
67
+ vtxo.virtualStatus.state !== "settled"));
68
+ }
69
+ async handleSettle(...args) {
70
+ return this.wallet.settle(...args);
71
+ }
72
+ async handleSendBitcoin(...args) {
73
+ return this.wallet.sendBitcoin(...args);
74
+ }
75
+ }
18
76
  /**
19
- * Worker is a class letting to interact with ServiceWorkerWallet from the client
20
- * it aims to be run in a service worker context
77
+ * Worker is a class letting to interact with ServiceWorkerWallet and ServiceWorkerReadonlyWallet from
78
+ * the client; it aims to be run in a service worker context.
79
+ *
80
+ * The messages requiring a Wallet rather than a ReadonlyWallet result in no-op
81
+ * without errors.
21
82
  */
22
83
  class Worker {
23
84
  constructor(dbName = utils_2.DEFAULT_DB_NAME, dbVersion = 1, messageCallback = () => { }) {
@@ -31,9 +92,9 @@ class Worker {
31
92
  * Get spendable vtxos for the current wallet address
32
93
  */
33
94
  async getSpendableVtxos() {
34
- if (!this.wallet)
95
+ if (!this.handler)
35
96
  return [];
36
- const address = await this.wallet.getAddress();
97
+ const address = await this.handler.getAddress();
37
98
  const allVtxos = await this.walletRepository.getVtxos(address);
38
99
  return allVtxos.filter(__1.isSpendable);
39
100
  }
@@ -41,9 +102,9 @@ class Worker {
41
102
  * Get swept vtxos for the current wallet address
42
103
  */
43
104
  async getSweptVtxos() {
44
- if (!this.wallet)
105
+ if (!this.handler)
45
106
  return [];
46
- const address = await this.wallet.getAddress();
107
+ const address = await this.handler.getAddress();
47
108
  const allVtxos = await this.walletRepository.getVtxos(address);
48
109
  return allVtxos.filter((vtxo) => vtxo.virtualStatus.state === "swept");
49
110
  }
@@ -51,9 +112,9 @@ class Worker {
51
112
  * Get all vtxos categorized by type
52
113
  */
53
114
  async getAllVtxos() {
54
- if (!this.wallet)
115
+ if (!this.handler)
55
116
  return { spendable: [], spent: [] };
56
- const address = await this.wallet.getAddress();
117
+ const address = await this.handler.getAddress();
57
118
  const allVtxos = await this.walletRepository.getVtxos(address);
58
119
  return {
59
120
  spendable: allVtxos.filter(__1.isSpendable),
@@ -64,17 +125,17 @@ class Worker {
64
125
  * Get all boarding utxos from wallet repository
65
126
  */
66
127
  async getAllBoardingUtxos() {
67
- if (!this.wallet)
128
+ if (!this.handler)
68
129
  return [];
69
- const address = await this.wallet.getBoardingAddress();
130
+ const address = await this.handler.getBoardingAddress();
70
131
  return await this.walletRepository.getUtxos(address);
71
132
  }
72
133
  async getTransactionHistory() {
73
- if (!this.wallet)
134
+ if (!this.handler)
74
135
  return [];
75
136
  let txs = [];
76
137
  try {
77
- const { boardingTxs, commitmentsToIgnore: roundsToIgnore } = await this.wallet.getBoardingTxs();
138
+ const { boardingTxs, commitmentsToIgnore: roundsToIgnore } = await this.handler.getBoardingTxs();
78
139
  const { spendable, spent } = await this.getAllVtxos();
79
140
  // convert VTXOs to offchain transactions
80
141
  const offchainTxs = (0, transactionHistory_1.vtxosToTxs)(spendable, spent, roundsToIgnore);
@@ -117,7 +178,7 @@ class Worker {
117
178
  await this.storage.clear();
118
179
  // Reset in-memory caches by recreating the repository
119
180
  this.walletRepository = new walletRepository_1.WalletRepositoryImpl(this.storage);
120
- this.wallet = undefined;
181
+ this.handler = undefined;
121
182
  this.arkProvider = undefined;
122
183
  this.indexerProvider = undefined;
123
184
  }
@@ -125,35 +186,34 @@ class Worker {
125
186
  await this.onWalletInitialized();
126
187
  }
127
188
  async onWalletInitialized() {
128
- if (!this.wallet ||
189
+ if (!this.handler ||
129
190
  !this.arkProvider ||
130
191
  !this.indexerProvider ||
131
- !this.wallet.offchainTapscript ||
132
- !this.wallet.boardingTapscript) {
192
+ !this.handler.offchainTapscript ||
193
+ !this.handler.boardingTapscript) {
133
194
  return;
134
195
  }
135
196
  // Get public key script and set the initial vtxos state
136
- const script = base_1.hex.encode(this.wallet.offchainTapscript.pkScript);
197
+ const script = base_1.hex.encode(this.handler.offchainTapscript.pkScript);
137
198
  const response = await this.indexerProvider.getVtxos({
138
199
  scripts: [script],
139
200
  });
140
- const vtxos = response.vtxos.map((vtxo) => (0, utils_1.extendVirtualCoin)(this.wallet, vtxo));
201
+ const vtxos = response.vtxos.map((vtxo) => (0, utils_1.extendVirtualCoin)(this.handler, vtxo));
141
202
  try {
142
- // recover pending transactions
143
- const { finalized, pending } = await this.wallet.finalizePendingTxs(vtxos.filter((vtxo) => vtxo.virtualStatus.state !== "swept" &&
144
- vtxo.virtualStatus.state !== "settled"));
203
+ // recover pending transactions if possible
204
+ const { pending, finalized } = await this.handler.handleReload(vtxos);
145
205
  console.info(`Recovered ${finalized.length}/${pending.length} pending transactions: ${finalized.join(", ")}`);
146
206
  }
147
207
  catch (error) {
148
208
  console.error("Error recovering pending transactions:", error);
149
209
  }
150
210
  // Get wallet address and save vtxos using unified repository
151
- const address = await this.wallet.getAddress();
211
+ const address = await this.handler.getAddress();
152
212
  await this.walletRepository.saveVtxos(address, vtxos);
153
213
  // Fetch boarding utxos and save using unified repository
154
- const boardingAddress = await this.wallet.getBoardingAddress();
155
- const coins = await this.wallet.onchainProvider.getCoins(boardingAddress);
156
- await this.walletRepository.saveUtxos(boardingAddress, coins.map((utxo) => (0, utils_1.extendCoin)(this.wallet, utxo)));
214
+ const boardingAddress = await this.handler.getBoardingAddress();
215
+ const coins = await this.handler.onchainProvider.getCoins(boardingAddress);
216
+ await this.walletRepository.saveUtxos(boardingAddress, coins.map((utxo) => (0, utils_1.extendCoin)(this.handler, utxo)));
157
217
  // Get transaction history to cache boarding txs
158
218
  const txs = await this.getTransactionHistory();
159
219
  if (txs)
@@ -162,13 +222,13 @@ class Worker {
162
222
  if (this.incomingFundsSubscription)
163
223
  this.incomingFundsSubscription();
164
224
  // subscribe for incoming funds and notify all clients when new funds arrive
165
- this.incomingFundsSubscription = await this.wallet.notifyIncomingFunds(async (funds) => {
225
+ this.incomingFundsSubscription = await this.handler.notifyIncomingFunds(async (funds) => {
166
226
  if (funds.type === "vtxo") {
167
227
  const newVtxos = funds.newVtxos.length > 0
168
- ? funds.newVtxos.map((vtxo) => (0, utils_1.extendVirtualCoin)(this.wallet, vtxo))
228
+ ? funds.newVtxos.map((vtxo) => (0, utils_1.extendVirtualCoin)(this.handler, vtxo))
169
229
  : [];
170
230
  const spentVtxos = funds.spentVtxos.length > 0
171
- ? funds.spentVtxos.map((vtxo) => (0, utils_1.extendVirtualCoin)(this.wallet, vtxo))
231
+ ? funds.spentVtxos.map((vtxo) => (0, utils_1.extendVirtualCoin)(this.handler, vtxo))
172
232
  : [];
173
233
  if ([...newVtxos, ...spentVtxos].length === 0)
174
234
  return;
@@ -181,8 +241,8 @@ class Worker {
181
241
  await this.sendMessageToAllClients(response_1.Response.vtxoUpdate(newVtxos, spentVtxos));
182
242
  }
183
243
  if (funds.type === "utxo") {
184
- const utxos = funds.coins.map((utxo) => (0, utils_1.extendCoin)(this.wallet, utxo));
185
- const boardingAddress = await this.wallet?.getBoardingAddress();
244
+ const utxos = funds.coins.map((utxo) => (0, utils_1.extendCoin)(this.handler, utxo));
245
+ const boardingAddress = await this.handler?.getBoardingAddress();
186
246
  // save utxos using unified repository
187
247
  await this.walletRepository.clearUtxos(boardingAddress);
188
248
  await this.walletRepository.saveUtxos(boardingAddress, utxos);
@@ -198,31 +258,46 @@ class Worker {
198
258
  }
199
259
  }
200
260
  async handleInitWallet(event) {
201
- const message = event.data;
202
- if (!request_1.Request.isInitWallet(message)) {
203
- console.error("Invalid INIT_WALLET message format", message);
204
- event.source?.postMessage(response_1.Response.error(message.id, "Invalid INIT_WALLET message format"));
205
- return;
206
- }
207
- if (!message.privateKey) {
208
- const err = "Missing privateKey";
209
- event.source?.postMessage(response_1.Response.error(message.id, err));
210
- console.error(err);
261
+ if (!request_1.Request.isInitWallet(event.data)) {
262
+ console.error("Invalid INIT_WALLET message format", event.data);
263
+ event.source?.postMessage(response_1.Response.error(event.data.id, "Invalid INIT_WALLET message format"));
211
264
  return;
212
265
  }
266
+ const message = event.data;
267
+ const { arkServerPublicKey, arkServerUrl } = message;
268
+ this.arkProvider = new ark_1.RestArkProvider(arkServerUrl);
269
+ this.indexerProvider = new indexer_1.RestIndexerProvider(arkServerUrl);
213
270
  try {
214
- const { arkServerPublicKey, arkServerUrl, privateKey } = message;
215
- const identity = singleKey_1.SingleKey.fromHex(privateKey);
216
- this.arkProvider = new ark_1.RestArkProvider(arkServerUrl);
217
- this.indexerProvider = new indexer_1.RestIndexerProvider(arkServerUrl);
218
- this.wallet = await wallet_1.Wallet.create({
219
- identity,
220
- arkServerUrl,
221
- arkServerPublicKey,
222
- storage: this.storage, // Use unified storage for wallet too
223
- });
224
- event.source?.postMessage(response_1.Response.walletInitialized(message.id));
225
- await this.onWalletInitialized();
271
+ if ("privateKey" in message.key &&
272
+ typeof message.key.privateKey === "string") {
273
+ const { key: { privateKey }, } = message;
274
+ const identity = singleKey_1.SingleKey.fromHex(privateKey);
275
+ const wallet = await wallet_1.Wallet.create({
276
+ identity,
277
+ arkServerUrl,
278
+ arkServerPublicKey,
279
+ storage: this.storage, // Use unified storage for wallet too
280
+ });
281
+ this.handler = new Handler(wallet);
282
+ }
283
+ else if ("publicKey" in message.key &&
284
+ typeof message.key.publicKey === "string") {
285
+ const { key: { publicKey }, } = message;
286
+ const identity = singleKey_1.ReadonlySingleKey.fromPublicKey(base_1.hex.decode(publicKey));
287
+ const wallet = await wallet_1.ReadonlyWallet.create({
288
+ identity,
289
+ arkServerUrl,
290
+ arkServerPublicKey,
291
+ storage: this.storage, // Use unified storage for wallet too
292
+ });
293
+ this.handler = new ReadonlyHandler(wallet);
294
+ }
295
+ else {
296
+ const err = "Missing privateKey or publicKey in key object";
297
+ event.source?.postMessage(response_1.Response.error(message.id, err));
298
+ console.error(err);
299
+ return;
300
+ }
226
301
  }
227
302
  catch (error) {
228
303
  console.error("Error initializing wallet:", error);
@@ -230,7 +305,10 @@ class Worker {
230
305
  ? error.message
231
306
  : "Unknown error occurred";
232
307
  event.source?.postMessage(response_1.Response.error(message.id, errorMessage));
308
+ return;
233
309
  }
310
+ event.source?.postMessage(response_1.Response.walletInitialized(message.id));
311
+ await this.onWalletInitialized();
234
312
  }
235
313
  async handleSettle(event) {
236
314
  const message = event.data;
@@ -240,15 +318,20 @@ class Worker {
240
318
  return;
241
319
  }
242
320
  try {
243
- if (!this.wallet) {
321
+ if (!this.handler) {
244
322
  console.error("Wallet not initialized");
245
323
  event.source?.postMessage(response_1.Response.error(message.id, "Wallet not initialized"));
246
324
  return;
247
325
  }
248
- const txid = await this.wallet.settle(message.params, (e) => {
326
+ const txid = await this.handler.handleSettle(message.params, (e) => {
249
327
  event.source?.postMessage(response_1.Response.settleEvent(message.id, e));
250
328
  });
251
- event.source?.postMessage(response_1.Response.settleSuccess(message.id, txid));
329
+ if (txid) {
330
+ event.source?.postMessage(response_1.Response.settleSuccess(message.id, txid));
331
+ }
332
+ else {
333
+ event.source?.postMessage(response_1.Response.error(message.id, "Operation not supported in readonly mode"));
334
+ }
252
335
  }
253
336
  catch (error) {
254
337
  console.error("Error settling:", error);
@@ -265,14 +348,19 @@ class Worker {
265
348
  event.source?.postMessage(response_1.Response.error(message.id, "Invalid SEND_BITCOIN message format"));
266
349
  return;
267
350
  }
268
- if (!this.wallet) {
351
+ if (!this.handler) {
269
352
  console.error("Wallet not initialized");
270
353
  event.source?.postMessage(response_1.Response.error(message.id, "Wallet not initialized"));
271
354
  return;
272
355
  }
273
356
  try {
274
- const txid = await this.wallet.sendBitcoin(message.params);
275
- event.source?.postMessage(response_1.Response.sendBitcoinSuccess(message.id, txid));
357
+ const txid = await this.handler.handleSendBitcoin(message.params);
358
+ if (txid) {
359
+ event.source?.postMessage(response_1.Response.sendBitcoinSuccess(message.id, txid));
360
+ }
361
+ else {
362
+ event.source?.postMessage(response_1.Response.error(message.id, "Operation not supported in readonly mode"));
363
+ }
276
364
  }
277
365
  catch (error) {
278
366
  console.error("Error sending bitcoin:", error);
@@ -289,13 +377,13 @@ class Worker {
289
377
  event.source?.postMessage(response_1.Response.error(message.id, "Invalid GET_ADDRESS message format"));
290
378
  return;
291
379
  }
292
- if (!this.wallet) {
380
+ if (!this.handler) {
293
381
  console.error("Wallet not initialized");
294
382
  event.source?.postMessage(response_1.Response.error(message.id, "Wallet not initialized"));
295
383
  return;
296
384
  }
297
385
  try {
298
- const address = await this.wallet.getAddress();
386
+ const address = await this.handler.getAddress();
299
387
  event.source?.postMessage(response_1.Response.address(message.id, address));
300
388
  }
301
389
  catch (error) {
@@ -313,13 +401,13 @@ class Worker {
313
401
  event.source?.postMessage(response_1.Response.error(message.id, "Invalid GET_BOARDING_ADDRESS message format"));
314
402
  return;
315
403
  }
316
- if (!this.wallet) {
404
+ if (!this.handler) {
317
405
  console.error("Wallet not initialized");
318
406
  event.source?.postMessage(response_1.Response.error(message.id, "Wallet not initialized"));
319
407
  return;
320
408
  }
321
409
  try {
322
- const address = await this.wallet.getBoardingAddress();
410
+ const address = await this.handler.getBoardingAddress();
323
411
  event.source?.postMessage(response_1.Response.boardingAddress(message.id, address));
324
412
  }
325
413
  catch (error) {
@@ -337,7 +425,7 @@ class Worker {
337
425
  event.source?.postMessage(response_1.Response.error(message.id, "Invalid GET_BALANCE message format"));
338
426
  return;
339
427
  }
340
- if (!this.wallet) {
428
+ if (!this.handler) {
341
429
  console.error("Wallet not initialized");
342
430
  event.source?.postMessage(response_1.Response.error(message.id, "Wallet not initialized"));
343
431
  return;
@@ -406,14 +494,14 @@ class Worker {
406
494
  event.source?.postMessage(response_1.Response.error(message.id, "Invalid GET_VTXOS message format"));
407
495
  return;
408
496
  }
409
- if (!this.wallet) {
497
+ if (!this.handler) {
410
498
  console.error("Wallet not initialized");
411
499
  event.source?.postMessage(response_1.Response.error(message.id, "Wallet not initialized"));
412
500
  return;
413
501
  }
414
502
  try {
415
503
  const vtxos = await this.getSpendableVtxos();
416
- const dustAmount = this.wallet.dustAmount;
504
+ const dustAmount = this.handler.dustAmount;
417
505
  const includeRecoverable = message.filter?.withRecoverable ?? false;
418
506
  const filteredVtxos = includeRecoverable
419
507
  ? vtxos
@@ -424,6 +512,9 @@ class Worker {
424
512
  if ((0, __1.isRecoverable)(v)) {
425
513
  return false;
426
514
  }
515
+ if ((0, __1.isExpired)(v)) {
516
+ return false;
517
+ }
427
518
  return true;
428
519
  });
429
520
  event.source?.postMessage(response_1.Response.vtxos(message.id, filteredVtxos));
@@ -443,7 +534,7 @@ class Worker {
443
534
  event.source?.postMessage(response_1.Response.error(message.id, "Invalid GET_BOARDING_UTXOS message format"));
444
535
  return;
445
536
  }
446
- if (!this.wallet) {
537
+ if (!this.handler) {
447
538
  console.error("Wallet not initialized");
448
539
  event.source?.postMessage(response_1.Response.error(message.id, "Wallet not initialized"));
449
540
  return;
@@ -467,7 +558,7 @@ class Worker {
467
558
  event.source?.postMessage(response_1.Response.error(message.id, "Invalid GET_TRANSACTION_HISTORY message format"));
468
559
  return;
469
560
  }
470
- if (!this.wallet) {
561
+ if (!this.handler) {
471
562
  console.error("Wallet not initialized");
472
563
  event.source?.postMessage(response_1.Response.error(message.id, "Wallet not initialized"));
473
564
  return;
@@ -491,10 +582,10 @@ class Worker {
491
582
  event.source?.postMessage(response_1.Response.error(message.id, "Invalid GET_STATUS message format"));
492
583
  return;
493
584
  }
494
- const pubKey = this.wallet
495
- ? await this.wallet.identity.xOnlyPublicKey()
585
+ const pubKey = this.handler
586
+ ? await this.handler.identity.xOnlyPublicKey()
496
587
  : undefined;
497
- event.source?.postMessage(response_1.Response.walletStatus(message.id, this.wallet !== undefined, pubKey));
588
+ event.source?.postMessage(response_1.Response.walletStatus(message.id, this.handler !== undefined, pubKey));
498
589
  }
499
590
  async handleMessage(event) {
500
591
  this.messageCallback(event);
@@ -573,7 +664,7 @@ class Worker {
573
664
  event.source?.postMessage(response_1.Response.error(message.id, "Invalid RELOAD_WALLET message format"));
574
665
  return;
575
666
  }
576
- if (!this.wallet) {
667
+ if (!this.handler) {
577
668
  console.error("Wallet not initialized");
578
669
  event.source?.postMessage(response_1.Response.walletReloaded(message.id, false));
579
670
  return;
@@ -6,7 +6,7 @@ function extendVirtualCoin(wallet, vtxo) {
6
6
  return {
7
7
  ...vtxo,
8
8
  forfeitTapLeafScript: wallet.offchainTapscript.forfeit(),
9
- intentTapLeafScript: wallet.offchainTapscript.exit(),
9
+ intentTapLeafScript: wallet.offchainTapscript.forfeit(),
10
10
  tapTree: wallet.offchainTapscript.encode(),
11
11
  };
12
12
  }
@@ -14,7 +14,7 @@ function extendCoin(wallet, utxo) {
14
14
  return {
15
15
  ...utxo,
16
16
  forfeitTapLeafScript: wallet.boardingTapscript.forfeit(),
17
- intentTapLeafScript: wallet.boardingTapscript.exit(),
17
+ intentTapLeafScript: wallet.boardingTapscript.forfeit(),
18
18
  tapTree: wallet.boardingTapscript.encode(),
19
19
  };
20
20
  }