@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.
- 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 +15 -5
- 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 +163 -72
- package/dist/cjs/wallet/utils.js +2 -2
- package/dist/cjs/wallet/vtxo-manager.js +5 -0
- package/dist/cjs/wallet/wallet.js +358 -360
- 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 +15 -5
- 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 +165 -74
- package/dist/esm/wallet/utils.js +2 -2
- package/dist/esm/wallet/vtxo-manager.js +6 -1
- package/dist/esm/wallet/wallet.js +359 -363
- 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 +76 -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 +87 -36
- 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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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 =
|
|
69
|
-
* const wallet = await
|
|
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
|
|
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
|
|
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.
|
|
95
|
+
if (!this.handler)
|
|
35
96
|
return [];
|
|
36
|
-
const address = await this.
|
|
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.
|
|
105
|
+
if (!this.handler)
|
|
45
106
|
return [];
|
|
46
|
-
const address = await this.
|
|
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.
|
|
115
|
+
if (!this.handler)
|
|
55
116
|
return { spendable: [], spent: [] };
|
|
56
|
-
const address = await this.
|
|
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.
|
|
128
|
+
if (!this.handler)
|
|
68
129
|
return [];
|
|
69
|
-
const address = await this.
|
|
130
|
+
const address = await this.handler.getBoardingAddress();
|
|
70
131
|
return await this.walletRepository.getUtxos(address);
|
|
71
132
|
}
|
|
72
133
|
async getTransactionHistory() {
|
|
73
|
-
if (!this.
|
|
134
|
+
if (!this.handler)
|
|
74
135
|
return [];
|
|
75
136
|
let txs = [];
|
|
76
137
|
try {
|
|
77
|
-
const { boardingTxs, commitmentsToIgnore: roundsToIgnore } = await this.
|
|
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.
|
|
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.
|
|
189
|
+
if (!this.handler ||
|
|
129
190
|
!this.arkProvider ||
|
|
130
191
|
!this.indexerProvider ||
|
|
131
|
-
!this.
|
|
132
|
-
!this.
|
|
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.
|
|
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.
|
|
201
|
+
const vtxos = response.vtxos.map((vtxo) => (0, utils_1.extendVirtualCoin)(this.handler, vtxo));
|
|
141
202
|
try {
|
|
142
|
-
// recover pending transactions
|
|
143
|
-
const {
|
|
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.
|
|
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.
|
|
155
|
-
const coins = await this.
|
|
156
|
-
await this.walletRepository.saveUtxos(boardingAddress, coins.map((utxo) => (0, utils_1.extendCoin)(this.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
185
|
-
const boardingAddress = await this.
|
|
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
|
-
|
|
202
|
-
|
|
203
|
-
|
|
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
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
275
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
495
|
-
? await this.
|
|
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.
|
|
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.
|
|
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;
|
package/dist/cjs/wallet/utils.js
CHANGED
|
@@ -6,7 +6,7 @@ function extendVirtualCoin(wallet, vtxo) {
|
|
|
6
6
|
return {
|
|
7
7
|
...vtxo,
|
|
8
8
|
forfeitTapLeafScript: wallet.offchainTapscript.forfeit(),
|
|
9
|
-
intentTapLeafScript: wallet.offchainTapscript.
|
|
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.
|
|
17
|
+
intentTapLeafScript: wallet.boardingTapscript.forfeit(),
|
|
18
18
|
tapTree: wallet.boardingTapscript.encode(),
|
|
19
19
|
};
|
|
20
20
|
}
|