@arkade-os/sdk 0.1.4 → 0.2.0
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 +156 -174
- package/dist/cjs/arknote/index.js +61 -58
- package/dist/cjs/bip322/errors.js +13 -0
- package/dist/cjs/bip322/index.js +178 -0
- package/dist/cjs/forfeit.js +14 -25
- package/dist/cjs/identity/singleKey.js +68 -0
- package/dist/cjs/index.js +41 -17
- package/dist/cjs/providers/ark.js +253 -317
- package/dist/cjs/providers/indexer.js +525 -0
- package/dist/cjs/providers/onchain.js +193 -15
- package/dist/cjs/script/address.js +48 -17
- package/dist/cjs/script/base.js +120 -3
- package/dist/cjs/script/default.js +18 -4
- package/dist/cjs/script/tapscript.js +46 -14
- package/dist/cjs/script/vhtlc.js +27 -7
- package/dist/cjs/tree/signingSession.js +63 -106
- package/dist/cjs/tree/txTree.js +193 -0
- package/dist/cjs/tree/validation.js +79 -155
- package/dist/cjs/utils/anchor.js +35 -0
- package/dist/cjs/utils/arkTransaction.js +108 -0
- package/dist/cjs/utils/transactionHistory.js +84 -72
- package/dist/cjs/utils/txSizeEstimator.js +12 -0
- package/dist/cjs/utils/unknownFields.js +211 -0
- package/dist/cjs/wallet/index.js +12 -0
- package/dist/cjs/wallet/onchain.js +201 -0
- package/dist/cjs/wallet/ramps.js +95 -0
- package/dist/cjs/wallet/serviceWorker/db/vtxo/idb.js +32 -0
- package/dist/cjs/wallet/serviceWorker/request.js +15 -12
- package/dist/cjs/wallet/serviceWorker/response.js +22 -27
- package/dist/cjs/wallet/serviceWorker/utils.js +8 -0
- package/dist/cjs/wallet/serviceWorker/wallet.js +58 -34
- package/dist/cjs/wallet/serviceWorker/worker.js +117 -108
- package/dist/cjs/wallet/unroll.js +270 -0
- package/dist/cjs/wallet/wallet.js +701 -454
- package/dist/esm/arknote/index.js +61 -57
- package/dist/esm/bip322/errors.js +9 -0
- package/dist/esm/bip322/index.js +174 -0
- package/dist/esm/forfeit.js +15 -26
- package/dist/esm/identity/singleKey.js +64 -0
- package/dist/esm/index.js +30 -12
- package/dist/esm/providers/ark.js +252 -317
- package/dist/esm/providers/indexer.js +521 -0
- package/dist/esm/providers/onchain.js +193 -15
- package/dist/esm/script/address.js +48 -17
- package/dist/esm/script/base.js +120 -3
- package/dist/esm/script/default.js +18 -4
- package/dist/esm/script/tapscript.js +46 -14
- package/dist/esm/script/vhtlc.js +27 -7
- package/dist/esm/tree/signingSession.js +65 -108
- package/dist/esm/tree/txTree.js +189 -0
- package/dist/esm/tree/validation.js +75 -152
- package/dist/esm/utils/anchor.js +31 -0
- package/dist/esm/utils/arkTransaction.js +105 -0
- package/dist/esm/utils/transactionHistory.js +84 -72
- package/dist/esm/utils/txSizeEstimator.js +12 -0
- package/dist/esm/utils/unknownFields.js +173 -0
- package/dist/esm/wallet/index.js +9 -0
- package/dist/esm/wallet/onchain.js +196 -0
- package/dist/esm/wallet/ramps.js +91 -0
- package/dist/esm/wallet/serviceWorker/db/vtxo/idb.js +32 -0
- package/dist/esm/wallet/serviceWorker/request.js +15 -12
- package/dist/esm/wallet/serviceWorker/response.js +22 -27
- package/dist/esm/wallet/serviceWorker/utils.js +8 -0
- package/dist/esm/wallet/serviceWorker/wallet.js +59 -35
- package/dist/esm/wallet/serviceWorker/worker.js +117 -108
- package/dist/esm/wallet/unroll.js +267 -0
- package/dist/esm/wallet/wallet.js +674 -461
- package/dist/types/arknote/index.d.ts +40 -13
- package/dist/types/bip322/errors.d.ts +6 -0
- package/dist/types/bip322/index.d.ts +57 -0
- package/dist/types/forfeit.d.ts +2 -14
- package/dist/types/identity/singleKey.d.ts +27 -0
- package/dist/types/index.d.ts +23 -12
- package/dist/types/providers/ark.d.ts +114 -95
- package/dist/types/providers/indexer.d.ts +186 -0
- package/dist/types/providers/onchain.d.ts +41 -11
- package/dist/types/script/address.d.ts +26 -2
- package/dist/types/script/base.d.ts +13 -3
- package/dist/types/script/default.d.ts +22 -0
- package/dist/types/script/tapscript.d.ts +61 -5
- package/dist/types/script/vhtlc.d.ts +27 -0
- package/dist/types/tree/signingSession.d.ts +5 -5
- package/dist/types/tree/txTree.d.ts +28 -0
- package/dist/types/tree/validation.d.ts +15 -22
- package/dist/types/utils/anchor.d.ts +19 -0
- package/dist/types/utils/arkTransaction.d.ts +27 -0
- package/dist/types/utils/transactionHistory.d.ts +7 -1
- package/dist/types/utils/txSizeEstimator.d.ts +3 -0
- package/dist/types/utils/unknownFields.d.ts +83 -0
- package/dist/types/wallet/index.d.ts +51 -50
- package/dist/types/wallet/onchain.d.ts +49 -0
- package/dist/types/wallet/ramps.d.ts +32 -0
- package/dist/types/wallet/serviceWorker/db/vtxo/idb.d.ts +2 -0
- package/dist/types/wallet/serviceWorker/db/vtxo/index.d.ts +2 -0
- package/dist/types/wallet/serviceWorker/request.d.ts +14 -16
- package/dist/types/wallet/serviceWorker/response.d.ts +17 -19
- package/dist/types/wallet/serviceWorker/utils.d.ts +8 -0
- package/dist/types/wallet/serviceWorker/wallet.d.ts +36 -8
- package/dist/types/wallet/serviceWorker/worker.d.ts +7 -3
- package/dist/types/wallet/unroll.d.ts +102 -0
- package/dist/types/wallet/wallet.d.ts +71 -25
- package/package.json +14 -15
- package/dist/cjs/identity/inMemoryKey.js +0 -40
- package/dist/cjs/tree/vtxoTree.js +0 -231
- package/dist/cjs/utils/coinselect.js +0 -73
- package/dist/cjs/utils/psbt.js +0 -137
- package/dist/esm/identity/inMemoryKey.js +0 -36
- package/dist/esm/tree/vtxoTree.js +0 -191
- package/dist/esm/utils/coinselect.js +0 -69
- package/dist/esm/utils/psbt.js +0 -131
- package/dist/types/identity/inMemoryKey.d.ts +0 -12
- package/dist/types/tree/vtxoTree.d.ts +0 -33
- package/dist/types/utils/coinselect.d.ts +0 -21
- package/dist/types/utils/psbt.d.ts +0 -11
|
@@ -1,12 +1,37 @@
|
|
|
1
1
|
import { Response } from './response.js';
|
|
2
|
-
import { hex } from "@scure/base";
|
|
2
|
+
import { base64, hex } from "@scure/base";
|
|
3
|
+
import { SingleKey } from '../../identity/singleKey.js';
|
|
4
|
+
import { TreeSignerSession } from '../../tree/signingSession.js';
|
|
5
|
+
import { Transaction } from "@scure/btc-signer";
|
|
3
6
|
class UnexpectedResponseError extends Error {
|
|
4
7
|
constructor(response) {
|
|
5
8
|
super(`Unexpected response type. Got: ${JSON.stringify(response, null, 2)}`);
|
|
6
9
|
this.name = "UnexpectedResponseError";
|
|
7
10
|
}
|
|
8
11
|
}
|
|
9
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Service Worker-based wallet implementation for browser environments.
|
|
14
|
+
*
|
|
15
|
+
* This wallet uses a service worker as a backend to handle wallet logic,
|
|
16
|
+
* providing secure key storage and transaction signing in web applications.
|
|
17
|
+
* The service worker runs in a separate thread and can persist data between
|
|
18
|
+
* browser sessions.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* // Create and initialize the service worker wallet
|
|
23
|
+
* const serviceWorker = await setupServiceWorker("/service-worker.js");
|
|
24
|
+
* const wallet = new ServiceWorkerWallet(serviceWorker);
|
|
25
|
+
* await wallet.init({
|
|
26
|
+
* privateKey: 'your_private_key_hex',
|
|
27
|
+
* arkServerUrl: 'https://ark.example.com'
|
|
28
|
+
* });
|
|
29
|
+
*
|
|
30
|
+
* // Use like any other wallet
|
|
31
|
+
* const address = await wallet.getAddress();
|
|
32
|
+
* const balance = await wallet.getBalance();
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
10
35
|
export class ServiceWorkerWallet {
|
|
11
36
|
constructor(serviceWorker) {
|
|
12
37
|
this.serviceWorker = serviceWorker;
|
|
@@ -41,11 +66,14 @@ export class ServiceWorkerWallet {
|
|
|
41
66
|
type: "INIT_WALLET",
|
|
42
67
|
id: getRandomId(),
|
|
43
68
|
privateKey: config.privateKey,
|
|
44
|
-
|
|
45
|
-
arkServerUrl: config.arkServerUrl || "",
|
|
69
|
+
arkServerUrl: config.arkServerUrl,
|
|
46
70
|
arkServerPublicKey: config.arkServerPublicKey,
|
|
47
71
|
};
|
|
48
72
|
await this.sendMessage(message);
|
|
73
|
+
const privKeyBytes = hex.decode(config.privateKey);
|
|
74
|
+
// cache the identity xOnlyPublicKey
|
|
75
|
+
this.cachedXOnlyPublicKey =
|
|
76
|
+
SingleKey.fromPrivateKey(privKeyBytes).xOnlyPublicKey();
|
|
49
77
|
}
|
|
50
78
|
async clear() {
|
|
51
79
|
const message = {
|
|
@@ -53,6 +81,8 @@ export class ServiceWorkerWallet {
|
|
|
53
81
|
id: getRandomId(),
|
|
54
82
|
};
|
|
55
83
|
await this.sendMessage(message);
|
|
84
|
+
// clear the cached xOnlyPublicKey
|
|
85
|
+
this.cachedXOnlyPublicKey = undefined;
|
|
56
86
|
}
|
|
57
87
|
// send a message and wait for a response
|
|
58
88
|
async sendMessage(message) {
|
|
@@ -86,7 +116,7 @@ export class ServiceWorkerWallet {
|
|
|
86
116
|
try {
|
|
87
117
|
const response = await this.sendMessage(message);
|
|
88
118
|
if (Response.isAddress(response)) {
|
|
89
|
-
return response.
|
|
119
|
+
return response.address;
|
|
90
120
|
}
|
|
91
121
|
throw new UnexpectedResponseError(response);
|
|
92
122
|
}
|
|
@@ -94,20 +124,20 @@ export class ServiceWorkerWallet {
|
|
|
94
124
|
throw new Error(`Failed to get address: ${error}`);
|
|
95
125
|
}
|
|
96
126
|
}
|
|
97
|
-
async
|
|
127
|
+
async getBoardingAddress() {
|
|
98
128
|
const message = {
|
|
99
|
-
type: "
|
|
129
|
+
type: "GET_BOARDING_ADDRESS",
|
|
100
130
|
id: getRandomId(),
|
|
101
131
|
};
|
|
102
132
|
try {
|
|
103
133
|
const response = await this.sendMessage(message);
|
|
104
|
-
if (Response.
|
|
105
|
-
return response.
|
|
134
|
+
if (Response.isBoardingAddress(response)) {
|
|
135
|
+
return response.address;
|
|
106
136
|
}
|
|
107
137
|
throw new UnexpectedResponseError(response);
|
|
108
138
|
}
|
|
109
139
|
catch (error) {
|
|
110
|
-
throw new Error(`Failed to get address
|
|
140
|
+
throw new Error(`Failed to get boarding address: ${error}`);
|
|
111
141
|
}
|
|
112
142
|
}
|
|
113
143
|
async getBalance() {
|
|
@@ -126,26 +156,11 @@ export class ServiceWorkerWallet {
|
|
|
126
156
|
throw new Error(`Failed to get balance: ${error}`);
|
|
127
157
|
}
|
|
128
158
|
}
|
|
129
|
-
async
|
|
130
|
-
const message = {
|
|
131
|
-
type: "GET_COINS",
|
|
132
|
-
id: getRandomId(),
|
|
133
|
-
};
|
|
134
|
-
try {
|
|
135
|
-
const response = await this.sendMessage(message);
|
|
136
|
-
if (Response.isCoins(response)) {
|
|
137
|
-
return response.coins;
|
|
138
|
-
}
|
|
139
|
-
throw new UnexpectedResponseError(response);
|
|
140
|
-
}
|
|
141
|
-
catch (error) {
|
|
142
|
-
throw new Error(`Failed to get coins: ${error}`);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
async getVtxos() {
|
|
159
|
+
async getVtxos(filter) {
|
|
146
160
|
const message = {
|
|
147
161
|
type: "GET_VTXOS",
|
|
148
162
|
id: getRandomId(),
|
|
163
|
+
filter,
|
|
149
164
|
};
|
|
150
165
|
try {
|
|
151
166
|
const response = await this.sendMessage(message);
|
|
@@ -174,11 +189,10 @@ export class ServiceWorkerWallet {
|
|
|
174
189
|
throw new Error(`Failed to get boarding UTXOs: ${error}`);
|
|
175
190
|
}
|
|
176
191
|
}
|
|
177
|
-
async sendBitcoin(params
|
|
192
|
+
async sendBitcoin(params) {
|
|
178
193
|
const message = {
|
|
179
194
|
type: "SEND_BITCOIN",
|
|
180
195
|
params,
|
|
181
|
-
zeroFee,
|
|
182
196
|
id: getRandomId(),
|
|
183
197
|
};
|
|
184
198
|
try {
|
|
@@ -245,21 +259,31 @@ export class ServiceWorkerWallet {
|
|
|
245
259
|
throw new Error(`Failed to get transaction history: ${error}`);
|
|
246
260
|
}
|
|
247
261
|
}
|
|
248
|
-
|
|
262
|
+
xOnlyPublicKey() {
|
|
263
|
+
if (!this.cachedXOnlyPublicKey) {
|
|
264
|
+
throw new Error("Wallet not initialized");
|
|
265
|
+
}
|
|
266
|
+
return this.cachedXOnlyPublicKey;
|
|
267
|
+
}
|
|
268
|
+
signerSession() {
|
|
269
|
+
return TreeSignerSession.random();
|
|
270
|
+
}
|
|
271
|
+
async sign(tx, inputIndexes) {
|
|
249
272
|
const message = {
|
|
250
|
-
type: "
|
|
251
|
-
|
|
273
|
+
type: "SIGN",
|
|
274
|
+
tx: base64.encode(tx.toPSBT()),
|
|
275
|
+
inputIndexes,
|
|
252
276
|
id: getRandomId(),
|
|
253
277
|
};
|
|
254
278
|
try {
|
|
255
279
|
const response = await this.sendMessage(message);
|
|
256
|
-
if (response
|
|
257
|
-
return;
|
|
280
|
+
if (Response.isSignSuccess(response)) {
|
|
281
|
+
return Transaction.fromPSBT(base64.decode(response.tx));
|
|
258
282
|
}
|
|
259
283
|
throw new UnexpectedResponseError(response);
|
|
260
284
|
}
|
|
261
285
|
catch (error) {
|
|
262
|
-
throw new Error(`Failed to
|
|
286
|
+
throw new Error(`Failed to sign: ${error}`);
|
|
263
287
|
}
|
|
264
288
|
}
|
|
265
289
|
}
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
/// <reference lib="webworker" />
|
|
2
|
-
import {
|
|
2
|
+
import { SingleKey } from '../../identity/singleKey.js';
|
|
3
|
+
import { isSpendable, isSubdust } from '../index.js';
|
|
3
4
|
import { Wallet } from '../wallet.js';
|
|
4
5
|
import { Request } from './request.js';
|
|
5
6
|
import { Response } from './response.js';
|
|
6
7
|
import { RestArkProvider } from '../../providers/ark.js';
|
|
7
|
-
import { DefaultVtxo } from '../../script/default.js';
|
|
8
8
|
import { IndexedDBVtxoRepository } from './db/vtxo/idb.js';
|
|
9
9
|
import { vtxosToTxs } from '../../utils/transactionHistory.js';
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
import { RestIndexerProvider } from '../../providers/indexer.js';
|
|
11
|
+
import { base64, hex } from "@scure/base";
|
|
12
|
+
import { Transaction } from "@scure/btc-signer";
|
|
13
|
+
/**
|
|
14
|
+
* Worker is a class letting to interact with ServiceWorkerWallet from the client
|
|
15
|
+
* it aims to be run in a service worker context
|
|
16
|
+
*/
|
|
12
17
|
export class Worker {
|
|
13
18
|
constructor(vtxoRepository = new IndexedDBVtxoRepository(), messageCallback = () => { }) {
|
|
14
19
|
this.vtxoRepository = vtxoRepository;
|
|
@@ -36,41 +41,48 @@ export class Worker {
|
|
|
36
41
|
await this.vtxoRepository.close();
|
|
37
42
|
this.wallet = undefined;
|
|
38
43
|
this.arkProvider = undefined;
|
|
44
|
+
this.indexerProvider = undefined;
|
|
39
45
|
this.vtxoSubscription = undefined;
|
|
40
46
|
}
|
|
41
47
|
async onWalletInitialized() {
|
|
42
48
|
if (!this.wallet ||
|
|
43
49
|
!this.arkProvider ||
|
|
50
|
+
!this.indexerProvider ||
|
|
44
51
|
!this.wallet.offchainTapscript ||
|
|
45
52
|
!this.wallet.boardingTapscript) {
|
|
46
53
|
return;
|
|
47
54
|
}
|
|
48
55
|
// subscribe to address updates
|
|
49
|
-
const addressInfo = await this.wallet.getAddressInfo();
|
|
50
|
-
if (!addressInfo.offchain) {
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
56
|
await this.vtxoRepository.open();
|
|
54
|
-
// set the initial vtxos state
|
|
55
|
-
const { spendableVtxos, spentVtxos } = await this.arkProvider.getVirtualCoins(addressInfo.offchain.address);
|
|
56
57
|
const encodedOffchainTapscript = this.wallet.offchainTapscript.encode();
|
|
57
58
|
const forfeit = this.wallet.offchainTapscript.forfeit();
|
|
58
|
-
const
|
|
59
|
+
const exit = this.wallet.offchainTapscript.exit();
|
|
60
|
+
const script = hex.encode(this.wallet.offchainTapscript.pkScript);
|
|
61
|
+
// set the initial vtxos state
|
|
62
|
+
const response = await this.indexerProvider.getVtxos({
|
|
63
|
+
scripts: [script],
|
|
64
|
+
});
|
|
65
|
+
const vtxos = response.vtxos.map((vtxo) => ({
|
|
59
66
|
...vtxo,
|
|
60
|
-
|
|
61
|
-
|
|
67
|
+
forfeitTapLeafScript: forfeit,
|
|
68
|
+
intentTapLeafScript: exit,
|
|
69
|
+
tapTree: encodedOffchainTapscript,
|
|
62
70
|
}));
|
|
63
71
|
await this.vtxoRepository.addOrUpdate(vtxos);
|
|
64
|
-
this.processVtxoSubscription(
|
|
72
|
+
this.processVtxoSubscription({
|
|
73
|
+
script,
|
|
74
|
+
vtxoScript: this.wallet.offchainTapscript,
|
|
75
|
+
});
|
|
65
76
|
}
|
|
66
|
-
async processVtxoSubscription({
|
|
77
|
+
async processVtxoSubscription({ script, vtxoScript, }) {
|
|
67
78
|
try {
|
|
68
|
-
const
|
|
69
|
-
const
|
|
70
|
-
const tapLeafScript = vtxoScript.findLeaf(scripts.forfeit[0]);
|
|
79
|
+
const forfeitTapLeafScript = vtxoScript.forfeit();
|
|
80
|
+
const intentTapLeafScript = vtxoScript.exit();
|
|
71
81
|
const abortController = new AbortController();
|
|
72
|
-
const
|
|
82
|
+
const subscriptionId = await this.indexerProvider.subscribeForScripts([script]);
|
|
83
|
+
const subscription = this.indexerProvider.getSubscription(subscriptionId, abortController.signal);
|
|
73
84
|
this.vtxoSubscription = abortController;
|
|
85
|
+
const tapTree = vtxoScript.encode();
|
|
74
86
|
for await (const update of subscription) {
|
|
75
87
|
const vtxos = [...update.newVtxos, ...update.spentVtxos];
|
|
76
88
|
if (vtxos.length === 0) {
|
|
@@ -78,8 +90,9 @@ export class Worker {
|
|
|
78
90
|
}
|
|
79
91
|
const extendedVtxos = vtxos.map((vtxo) => ({
|
|
80
92
|
...vtxo,
|
|
81
|
-
|
|
82
|
-
|
|
93
|
+
forfeitTapLeafScript,
|
|
94
|
+
intentTapLeafScript,
|
|
95
|
+
tapTree,
|
|
83
96
|
}));
|
|
84
97
|
await this.vtxoRepository.addOrUpdate(extendedVtxos);
|
|
85
98
|
}
|
|
@@ -103,9 +116,9 @@ export class Worker {
|
|
|
103
116
|
}
|
|
104
117
|
try {
|
|
105
118
|
this.arkProvider = new RestArkProvider(message.arkServerUrl);
|
|
119
|
+
this.indexerProvider = new RestIndexerProvider(message.arkServerUrl);
|
|
106
120
|
this.wallet = await Wallet.create({
|
|
107
|
-
|
|
108
|
-
identity: InMemoryKey.fromHex(message.privateKey),
|
|
121
|
+
identity: SingleKey.fromHex(message.privateKey),
|
|
109
122
|
arkServerUrl: message.arkServerUrl,
|
|
110
123
|
arkServerPublicKey: message.arkServerPublicKey,
|
|
111
124
|
});
|
|
@@ -159,7 +172,7 @@ export class Worker {
|
|
|
159
172
|
return;
|
|
160
173
|
}
|
|
161
174
|
try {
|
|
162
|
-
const txid = await this.wallet.sendBitcoin(message.params
|
|
175
|
+
const txid = await this.wallet.sendBitcoin(message.params);
|
|
163
176
|
event.source?.postMessage(Response.sendBitcoinSuccess(message.id, txid));
|
|
164
177
|
}
|
|
165
178
|
catch (error) {
|
|
@@ -183,8 +196,8 @@ export class Worker {
|
|
|
183
196
|
return;
|
|
184
197
|
}
|
|
185
198
|
try {
|
|
186
|
-
const
|
|
187
|
-
event.source?.postMessage(Response.
|
|
199
|
+
const address = await this.wallet.getAddress();
|
|
200
|
+
event.source?.postMessage(Response.address(message.id, address));
|
|
188
201
|
}
|
|
189
202
|
catch (error) {
|
|
190
203
|
console.error("Error getting address:", error);
|
|
@@ -194,11 +207,11 @@ export class Worker {
|
|
|
194
207
|
event.source?.postMessage(Response.error(message.id, errorMessage));
|
|
195
208
|
}
|
|
196
209
|
}
|
|
197
|
-
async
|
|
210
|
+
async handleGetBoardingAddress(event) {
|
|
198
211
|
const message = event.data;
|
|
199
|
-
if (!Request.
|
|
200
|
-
console.error("Invalid
|
|
201
|
-
event.source?.postMessage(Response.error(message.id, "Invalid
|
|
212
|
+
if (!Request.isGetBoardingAddress(message)) {
|
|
213
|
+
console.error("Invalid GET_BOARDING_ADDRESS message format", message);
|
|
214
|
+
event.source?.postMessage(Response.error(message.id, "Invalid GET_BOARDING_ADDRESS message format"));
|
|
202
215
|
return;
|
|
203
216
|
}
|
|
204
217
|
if (!this.wallet) {
|
|
@@ -207,11 +220,11 @@ export class Worker {
|
|
|
207
220
|
return;
|
|
208
221
|
}
|
|
209
222
|
try {
|
|
210
|
-
const
|
|
211
|
-
event.source?.postMessage(Response.
|
|
223
|
+
const address = await this.wallet.getBoardingAddress();
|
|
224
|
+
event.source?.postMessage(Response.boardingAddress(message.id, address));
|
|
212
225
|
}
|
|
213
226
|
catch (error) {
|
|
214
|
-
console.error("Error getting address
|
|
227
|
+
console.error("Error getting boarding address:", error);
|
|
215
228
|
const errorMessage = error instanceof Error
|
|
216
229
|
? error.message
|
|
217
230
|
: "Unknown error occurred";
|
|
@@ -231,40 +244,52 @@ export class Worker {
|
|
|
231
244
|
return;
|
|
232
245
|
}
|
|
233
246
|
try {
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
.
|
|
237
|
-
.
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
247
|
+
const [boardingUtxos, spendableVtxos, sweptVtxos] = await Promise.all([
|
|
248
|
+
this.wallet.getBoardingUtxos(),
|
|
249
|
+
this.vtxoRepository.getSpendableVtxos(),
|
|
250
|
+
this.vtxoRepository.getSweptVtxos(),
|
|
251
|
+
]);
|
|
252
|
+
// boarding
|
|
253
|
+
let confirmed = 0;
|
|
254
|
+
let unconfirmed = 0;
|
|
255
|
+
for (const utxo of boardingUtxos) {
|
|
256
|
+
if (utxo.status.confirmed) {
|
|
257
|
+
confirmed += utxo.value;
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
unconfirmed += utxo.value;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// offchain
|
|
264
|
+
let settled = 0;
|
|
265
|
+
let preconfirmed = 0;
|
|
266
|
+
let recoverable = 0;
|
|
267
|
+
for (const vtxo of spendableVtxos) {
|
|
268
|
+
if (vtxo.virtualStatus.state === "settled") {
|
|
269
|
+
settled += vtxo.value;
|
|
270
|
+
}
|
|
271
|
+
else if (vtxo.virtualStatus.state === "preconfirmed") {
|
|
272
|
+
preconfirmed += vtxo.value;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
for (const vtxo of sweptVtxos) {
|
|
276
|
+
if (isSpendable(vtxo)) {
|
|
277
|
+
recoverable += vtxo.value;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
const totalBoarding = confirmed + unconfirmed;
|
|
281
|
+
const totalOffchain = settled + preconfirmed + recoverable;
|
|
255
282
|
event.source?.postMessage(Response.balance(message.id, {
|
|
256
|
-
|
|
257
|
-
confirmed
|
|
258
|
-
unconfirmed
|
|
259
|
-
total:
|
|
260
|
-
},
|
|
261
|
-
offchain: {
|
|
262
|
-
swept: offchainSweptBalance,
|
|
263
|
-
settled: offchainSettledBalance,
|
|
264
|
-
pending: offchainPendingBalance,
|
|
265
|
-
total: offchainTotal,
|
|
283
|
+
boarding: {
|
|
284
|
+
confirmed,
|
|
285
|
+
unconfirmed,
|
|
286
|
+
total: totalBoarding,
|
|
266
287
|
},
|
|
267
|
-
|
|
288
|
+
settled,
|
|
289
|
+
preconfirmed,
|
|
290
|
+
available: settled + preconfirmed,
|
|
291
|
+
recoverable,
|
|
292
|
+
total: totalBoarding + totalOffchain,
|
|
268
293
|
}));
|
|
269
294
|
}
|
|
270
295
|
catch (error) {
|
|
@@ -275,30 +300,6 @@ export class Worker {
|
|
|
275
300
|
event.source?.postMessage(Response.error(message.id, errorMessage));
|
|
276
301
|
}
|
|
277
302
|
}
|
|
278
|
-
async handleGetCoins(event) {
|
|
279
|
-
const message = event.data;
|
|
280
|
-
if (!Request.isGetCoins(message)) {
|
|
281
|
-
console.error("Invalid GET_COINS message format", message);
|
|
282
|
-
event.source?.postMessage(Response.error(message.id, "Invalid GET_COINS message format"));
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
if (!this.wallet) {
|
|
286
|
-
console.error("Wallet not initialized");
|
|
287
|
-
event.source?.postMessage(Response.error(message.id, "Wallet not initialized"));
|
|
288
|
-
return;
|
|
289
|
-
}
|
|
290
|
-
try {
|
|
291
|
-
const coins = await this.wallet.getCoins();
|
|
292
|
-
event.source?.postMessage(Response.coins(message.id, coins));
|
|
293
|
-
}
|
|
294
|
-
catch (error) {
|
|
295
|
-
console.error("Error getting coins:", error);
|
|
296
|
-
const errorMessage = error instanceof Error
|
|
297
|
-
? error.message
|
|
298
|
-
: "Unknown error occurred";
|
|
299
|
-
event.source?.postMessage(Response.error(message.id, errorMessage));
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
303
|
async handleGetVtxos(event) {
|
|
303
304
|
const message = event.data;
|
|
304
305
|
if (!Request.isGetVtxos(message)) {
|
|
@@ -312,7 +313,18 @@ export class Worker {
|
|
|
312
313
|
return;
|
|
313
314
|
}
|
|
314
315
|
try {
|
|
315
|
-
|
|
316
|
+
let vtxos = await this.vtxoRepository.getSpendableVtxos();
|
|
317
|
+
if (!message.filter?.withRecoverable) {
|
|
318
|
+
if (!this.wallet)
|
|
319
|
+
throw new Error("Wallet not initialized");
|
|
320
|
+
// exclude subdust is we don't want recoverable
|
|
321
|
+
vtxos = vtxos.filter((v) => !isSubdust(v, this.wallet.dustAmount));
|
|
322
|
+
}
|
|
323
|
+
if (message.filter?.withRecoverable) {
|
|
324
|
+
// get also swept and spendable vtxos
|
|
325
|
+
const sweptVtxos = await this.vtxoRepository.getSweptVtxos();
|
|
326
|
+
vtxos.push(...sweptVtxos.filter(isSpendable));
|
|
327
|
+
}
|
|
316
328
|
event.source?.postMessage(Response.vtxos(message.id, vtxos));
|
|
317
329
|
}
|
|
318
330
|
catch (error) {
|
|
@@ -360,7 +372,7 @@ export class Worker {
|
|
|
360
372
|
return;
|
|
361
373
|
}
|
|
362
374
|
try {
|
|
363
|
-
const { boardingTxs, roundsToIgnore } = await this.wallet.getBoardingTxs();
|
|
375
|
+
const { boardingTxs, commitmentsToIgnore: roundsToIgnore } = await this.wallet.getBoardingTxs();
|
|
364
376
|
const { spendable, spent } = await this.vtxoRepository.getAllVtxos();
|
|
365
377
|
// convert VTXOs to offchain transactions
|
|
366
378
|
const offchainTxs = vtxosToTxs(spendable, spent, roundsToIgnore);
|
|
@@ -394,11 +406,11 @@ export class Worker {
|
|
|
394
406
|
}
|
|
395
407
|
event.source?.postMessage(Response.walletStatus(message.id, this.wallet !== undefined));
|
|
396
408
|
}
|
|
397
|
-
async
|
|
409
|
+
async handleSign(event) {
|
|
398
410
|
const message = event.data;
|
|
399
|
-
if (!Request.
|
|
400
|
-
console.error("Invalid
|
|
401
|
-
event.source?.postMessage(Response.error(message.id, "Invalid
|
|
411
|
+
if (!Request.isSign(message)) {
|
|
412
|
+
console.error("Invalid SIGN message format", message);
|
|
413
|
+
event.source?.postMessage(Response.error(message.id, "Invalid SIGN message format"));
|
|
402
414
|
return;
|
|
403
415
|
}
|
|
404
416
|
if (!this.wallet) {
|
|
@@ -407,11 +419,12 @@ export class Worker {
|
|
|
407
419
|
return;
|
|
408
420
|
}
|
|
409
421
|
try {
|
|
410
|
-
|
|
411
|
-
|
|
422
|
+
const tx = Transaction.fromPSBT(base64.decode(message.tx));
|
|
423
|
+
const signedTx = await this.wallet.identity.sign(tx, message.inputIndexes);
|
|
424
|
+
event.source?.postMessage(Response.signSuccess(message.id, base64.encode(signedTx.toPSBT())));
|
|
412
425
|
}
|
|
413
426
|
catch (error) {
|
|
414
|
-
console.error("Error
|
|
427
|
+
console.error("Error signing:", error);
|
|
415
428
|
const errorMessage = error instanceof Error
|
|
416
429
|
? error.message
|
|
417
430
|
: "Unknown error occurred";
|
|
@@ -443,18 +456,14 @@ export class Worker {
|
|
|
443
456
|
await this.handleGetAddress(event);
|
|
444
457
|
break;
|
|
445
458
|
}
|
|
446
|
-
case "
|
|
447
|
-
await this.
|
|
459
|
+
case "GET_BOARDING_ADDRESS": {
|
|
460
|
+
await this.handleGetBoardingAddress(event);
|
|
448
461
|
break;
|
|
449
462
|
}
|
|
450
463
|
case "GET_BALANCE": {
|
|
451
464
|
await this.handleGetBalance(event);
|
|
452
465
|
break;
|
|
453
466
|
}
|
|
454
|
-
case "GET_COINS": {
|
|
455
|
-
await this.handleGetCoins(event);
|
|
456
|
-
break;
|
|
457
|
-
}
|
|
458
467
|
case "GET_VTXOS": {
|
|
459
468
|
await this.handleGetVtxos(event);
|
|
460
469
|
break;
|
|
@@ -471,14 +480,14 @@ export class Worker {
|
|
|
471
480
|
await this.handleGetStatus(event);
|
|
472
481
|
break;
|
|
473
482
|
}
|
|
474
|
-
case "EXIT": {
|
|
475
|
-
await this.handleExit(event);
|
|
476
|
-
break;
|
|
477
|
-
}
|
|
478
483
|
case "CLEAR": {
|
|
479
484
|
await this.handleClear(event);
|
|
480
485
|
break;
|
|
481
486
|
}
|
|
487
|
+
case "SIGN": {
|
|
488
|
+
await this.handleSign(event);
|
|
489
|
+
break;
|
|
490
|
+
}
|
|
482
491
|
default:
|
|
483
492
|
event.source?.postMessage(Response.error(message.id, "Unknown message type"));
|
|
484
493
|
}
|