@arkade-os/sdk 0.3.1-alpha.1 → 0.3.1-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.js +5 -1
- package/dist/cjs/musig2/index.js +2 -1
- package/dist/cjs/musig2/nonces.js +4 -0
- package/dist/cjs/providers/ark.js +28 -36
- package/dist/cjs/providers/errors.js +59 -0
- package/dist/cjs/repositories/walletRepository.js +0 -26
- package/dist/cjs/tree/signingSession.js +38 -4
- package/dist/cjs/utils/unknownFields.js +2 -2
- package/dist/cjs/wallet/serviceWorker/response.js +32 -0
- package/dist/cjs/wallet/serviceWorker/wallet.js +3 -0
- package/dist/cjs/wallet/serviceWorker/worker.js +4 -7
- package/dist/cjs/wallet/wallet.js +16 -8
- package/dist/esm/index.js +4 -1
- package/dist/esm/musig2/index.js +1 -1
- package/dist/esm/musig2/nonces.js +3 -0
- package/dist/esm/providers/ark.js +28 -36
- package/dist/esm/providers/errors.js +54 -0
- package/dist/esm/repositories/walletRepository.js +0 -26
- package/dist/esm/tree/signingSession.js +38 -4
- package/dist/esm/utils/unknownFields.js +2 -2
- package/dist/esm/wallet/serviceWorker/response.js +32 -0
- package/dist/esm/wallet/serviceWorker/wallet.js +3 -0
- package/dist/esm/wallet/serviceWorker/worker.js +4 -7
- package/dist/esm/wallet/wallet.js +16 -8
- package/dist/types/index.d.ts +4 -3
- package/dist/types/musig2/index.d.ts +1 -1
- package/dist/types/musig2/nonces.d.ts +1 -0
- package/dist/types/providers/ark.d.ts +7 -5
- package/dist/types/providers/errors.d.ts +13 -0
- package/dist/types/repositories/walletRepository.d.ts +0 -4
- package/dist/types/tree/signingSession.d.ts +8 -3
- package/dist/types/utils/unknownFields.d.ts +2 -2
- package/dist/types/wallet/serviceWorker/response.d.ts +16 -2
- package/dist/types/wallet/wallet.d.ts +1 -1
- package/package.json +1 -1
package/dist/cjs/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Transaction = exports.Unroll = exports.P2A = exports.TxTree = exports.Intent = exports.ContractRepositoryImpl = exports.WalletRepositoryImpl = exports.networks = exports.ArkNote = exports.hasBoardingTxExpired = exports.waitForIncomingFunds = exports.verifyTapscriptSignatures = exports.buildOffchainTx = exports.ConditionWitness = exports.VtxoTaprootTree = exports.VtxoTreeExpiry = exports.CosignerPublicKey = exports.getArkPsbtFields = exports.setArkPsbtField = exports.ArkPsbtFieldKeyType = exports.ArkPsbtFieldKey = exports.CLTVMultisigTapscript = exports.ConditionMultisigTapscript = exports.ConditionCSVMultisigTapscript = exports.CSVMultisigTapscript = exports.MultisigTapscript = exports.decodeTapscript = exports.Response = exports.Request = exports.ServiceWorkerWallet = exports.Worker = exports.setupServiceWorker = exports.SettlementEventType = exports.ChainTxType = exports.IndexerTxType = exports.TxType = exports.VHTLC = exports.VtxoScript = exports.DefaultVtxo = exports.ArkAddress = exports.RestIndexerProvider = exports.RestArkProvider = exports.EsploraProvider = exports.ESPLORA_URL = exports.VtxoManager = exports.Ramps = exports.OnchainWallet = exports.SingleKey = exports.Wallet = void 0;
|
|
3
|
+
exports.ArkError = exports.Transaction = exports.Unroll = exports.P2A = exports.TxTree = exports.Intent = exports.ContractRepositoryImpl = exports.WalletRepositoryImpl = exports.networks = exports.ArkNote = exports.hasBoardingTxExpired = exports.waitForIncomingFunds = exports.verifyTapscriptSignatures = exports.buildOffchainTx = exports.ConditionWitness = exports.VtxoTaprootTree = exports.VtxoTreeExpiry = exports.CosignerPublicKey = exports.getArkPsbtFields = exports.setArkPsbtField = exports.ArkPsbtFieldKeyType = exports.ArkPsbtFieldKey = exports.CLTVMultisigTapscript = exports.ConditionMultisigTapscript = exports.ConditionCSVMultisigTapscript = exports.CSVMultisigTapscript = exports.MultisigTapscript = exports.decodeTapscript = exports.Response = exports.Request = exports.ServiceWorkerWallet = exports.Worker = exports.setupServiceWorker = exports.SettlementEventType = exports.ChainTxType = exports.IndexerTxType = exports.TxType = exports.VHTLC = exports.VtxoScript = exports.DefaultVtxo = exports.ArkAddress = exports.RestIndexerProvider = exports.RestArkProvider = exports.EsploraProvider = exports.ESPLORA_URL = exports.VtxoManager = exports.Ramps = exports.OnchainWallet = exports.SingleKey = exports.Wallet = void 0;
|
|
4
|
+
exports.maybeArkError = void 0;
|
|
4
5
|
const transaction_js_1 = require("@scure/btc-signer/transaction.js");
|
|
5
6
|
Object.defineProperty(exports, "Transaction", { enumerable: true, get: function () { return transaction_js_1.Transaction; } });
|
|
6
7
|
const singleKey_1 = require("./identity/singleKey");
|
|
@@ -80,3 +81,6 @@ const walletRepository_1 = require("./repositories/walletRepository");
|
|
|
80
81
|
Object.defineProperty(exports, "WalletRepositoryImpl", { enumerable: true, get: function () { return walletRepository_1.WalletRepositoryImpl; } });
|
|
81
82
|
const contractRepository_1 = require("./repositories/contractRepository");
|
|
82
83
|
Object.defineProperty(exports, "ContractRepositoryImpl", { enumerable: true, get: function () { return contractRepository_1.ContractRepositoryImpl; } });
|
|
84
|
+
const errors_1 = require("./providers/errors");
|
|
85
|
+
Object.defineProperty(exports, "ArkError", { enumerable: true, get: function () { return errors_1.ArkError; } });
|
|
86
|
+
Object.defineProperty(exports, "maybeArkError", { enumerable: true, get: function () { return errors_1.maybeArkError; } });
|
package/dist/cjs/musig2/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.aggregateKeys = exports.sign = exports.PartialSig = exports.generateNonces = void 0;
|
|
3
|
+
exports.aggregateKeys = exports.sign = exports.PartialSig = exports.aggregateNonces = exports.generateNonces = void 0;
|
|
4
4
|
var nonces_1 = require("./nonces");
|
|
5
5
|
Object.defineProperty(exports, "generateNonces", { enumerable: true, get: function () { return nonces_1.generateNonces; } });
|
|
6
|
+
Object.defineProperty(exports, "aggregateNonces", { enumerable: true, get: function () { return nonces_1.aggregateNonces; } });
|
|
6
7
|
var sign_1 = require("./sign");
|
|
7
8
|
Object.defineProperty(exports, "PartialSig", { enumerable: true, get: function () { return sign_1.PartialSig; } });
|
|
8
9
|
Object.defineProperty(exports, "sign", { enumerable: true, get: function () { return sign_1.sign; } });
|
|
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.generateNonces = generateNonces;
|
|
37
|
+
exports.aggregateNonces = aggregateNonces;
|
|
37
38
|
const musig = __importStar(require("@scure/btc-signer/musig2.js"));
|
|
38
39
|
/**
|
|
39
40
|
* Generates a pair of public and secret nonces for MuSig2 signing
|
|
@@ -42,3 +43,6 @@ function generateNonces(publicKey) {
|
|
|
42
43
|
const nonces = musig.nonceGen(publicKey);
|
|
43
44
|
return { secNonce: nonces.secret, pubNonce: nonces.public };
|
|
44
45
|
}
|
|
46
|
+
function aggregateNonces(pubNonces) {
|
|
47
|
+
return musig.nonceAggregate(pubNonces);
|
|
48
|
+
}
|
|
@@ -4,6 +4,7 @@ exports.RestArkProvider = exports.SettlementEventType = void 0;
|
|
|
4
4
|
exports.isFetchTimeoutError = isFetchTimeoutError;
|
|
5
5
|
const base_1 = require("@scure/base");
|
|
6
6
|
const utils_1 = require("./utils");
|
|
7
|
+
const errors_1 = require("./errors");
|
|
7
8
|
var SettlementEventType;
|
|
8
9
|
(function (SettlementEventType) {
|
|
9
10
|
SettlementEventType["BatchStarted"] = "batch_started";
|
|
@@ -11,7 +12,7 @@ var SettlementEventType;
|
|
|
11
12
|
SettlementEventType["BatchFinalized"] = "batch_finalized";
|
|
12
13
|
SettlementEventType["BatchFailed"] = "batch_failed";
|
|
13
14
|
SettlementEventType["TreeSigningStarted"] = "tree_signing_started";
|
|
14
|
-
SettlementEventType["
|
|
15
|
+
SettlementEventType["TreeNonces"] = "tree_nonces";
|
|
15
16
|
SettlementEventType["TreeTx"] = "tree_tx";
|
|
16
17
|
SettlementEventType["TreeSignature"] = "tree_signature";
|
|
17
18
|
})(SettlementEventType || (exports.SettlementEventType = SettlementEventType = {}));
|
|
@@ -32,7 +33,8 @@ class RestArkProvider {
|
|
|
32
33
|
const url = `${this.serverUrl}/v1/info`;
|
|
33
34
|
const response = await fetch(url);
|
|
34
35
|
if (!response.ok) {
|
|
35
|
-
|
|
36
|
+
const errorText = await response.text();
|
|
37
|
+
handleError(errorText, `Failed to get server info: ${response.statusText}`);
|
|
36
38
|
}
|
|
37
39
|
const fromServer = await response.json();
|
|
38
40
|
return {
|
|
@@ -82,16 +84,7 @@ class RestArkProvider {
|
|
|
82
84
|
});
|
|
83
85
|
if (!response.ok) {
|
|
84
86
|
const errorText = await response.text();
|
|
85
|
-
|
|
86
|
-
const grpcError = JSON.parse(errorText);
|
|
87
|
-
// gRPC errors usually have a message and code field
|
|
88
|
-
throw new Error(`Failed to submit virtual transaction: ${grpcError.message || grpcError.error || errorText}`);
|
|
89
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
90
|
-
}
|
|
91
|
-
catch (_) {
|
|
92
|
-
// If JSON parse fails, use the raw error text
|
|
93
|
-
throw new Error(`Failed to submit virtual transaction: ${errorText}`);
|
|
94
|
-
}
|
|
87
|
+
handleError(errorText, `Failed to submit virtual transaction: ${errorText}`);
|
|
95
88
|
}
|
|
96
89
|
const data = await response.json();
|
|
97
90
|
return {
|
|
@@ -114,7 +107,7 @@ class RestArkProvider {
|
|
|
114
107
|
});
|
|
115
108
|
if (!response.ok) {
|
|
116
109
|
const errorText = await response.text();
|
|
117
|
-
|
|
110
|
+
handleError(errorText, `Failed to finalize offchain transaction: ${errorText}`);
|
|
118
111
|
}
|
|
119
112
|
}
|
|
120
113
|
async registerIntent(intent) {
|
|
@@ -133,7 +126,7 @@ class RestArkProvider {
|
|
|
133
126
|
});
|
|
134
127
|
if (!response.ok) {
|
|
135
128
|
const errorText = await response.text();
|
|
136
|
-
|
|
129
|
+
handleError(errorText, `Failed to register intent: ${errorText}`);
|
|
137
130
|
}
|
|
138
131
|
const data = await response.json();
|
|
139
132
|
return data.intentId;
|
|
@@ -154,7 +147,7 @@ class RestArkProvider {
|
|
|
154
147
|
});
|
|
155
148
|
if (!response.ok) {
|
|
156
149
|
const errorText = await response.text();
|
|
157
|
-
|
|
150
|
+
handleError(errorText, `Failed to delete intent: ${errorText}`);
|
|
158
151
|
}
|
|
159
152
|
}
|
|
160
153
|
async confirmRegistration(intentId) {
|
|
@@ -170,7 +163,7 @@ class RestArkProvider {
|
|
|
170
163
|
});
|
|
171
164
|
if (!response.ok) {
|
|
172
165
|
const errorText = await response.text();
|
|
173
|
-
|
|
166
|
+
handleError(errorText, `Failed to confirm registration: ${errorText}`);
|
|
174
167
|
}
|
|
175
168
|
}
|
|
176
169
|
async submitTreeNonces(batchId, pubkey, nonces) {
|
|
@@ -188,7 +181,7 @@ class RestArkProvider {
|
|
|
188
181
|
});
|
|
189
182
|
if (!response.ok) {
|
|
190
183
|
const errorText = await response.text();
|
|
191
|
-
|
|
184
|
+
handleError(errorText, `Failed to submit tree nonces: ${errorText}`);
|
|
192
185
|
}
|
|
193
186
|
}
|
|
194
187
|
async submitTreeSignatures(batchId, pubkey, signatures) {
|
|
@@ -206,7 +199,7 @@ class RestArkProvider {
|
|
|
206
199
|
});
|
|
207
200
|
if (!response.ok) {
|
|
208
201
|
const errorText = await response.text();
|
|
209
|
-
|
|
202
|
+
handleError(errorText, `Failed to submit tree signatures: ${errorText}`);
|
|
210
203
|
}
|
|
211
204
|
}
|
|
212
205
|
async submitSignedForfeitTxs(signedForfeitTxs, signedCommitmentTx) {
|
|
@@ -222,7 +215,8 @@ class RestArkProvider {
|
|
|
222
215
|
}),
|
|
223
216
|
});
|
|
224
217
|
if (!response.ok) {
|
|
225
|
-
|
|
218
|
+
const errorText = await response.text();
|
|
219
|
+
handleError(errorText, `Failed to submit forfeit transactions: ${response.statusText}`);
|
|
226
220
|
}
|
|
227
221
|
}
|
|
228
222
|
async *getEventStream(signal, topics) {
|
|
@@ -331,16 +325,7 @@ class RestArkProvider {
|
|
|
331
325
|
});
|
|
332
326
|
if (!response.ok) {
|
|
333
327
|
const errorText = await response.text();
|
|
334
|
-
|
|
335
|
-
const grpcError = JSON.parse(errorText);
|
|
336
|
-
// gRPC errors usually have a message and code field
|
|
337
|
-
throw new Error(`Failed to get pending transactions: ${grpcError.message || grpcError.error || errorText}`);
|
|
338
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
339
|
-
}
|
|
340
|
-
catch (_) {
|
|
341
|
-
// If JSON parse fails, use the raw error text
|
|
342
|
-
throw new Error(`Failed to get pending transactions: ${errorText}`);
|
|
343
|
-
}
|
|
328
|
+
handleError(errorText, `Failed to get pending transactions: ${errorText}`);
|
|
344
329
|
}
|
|
345
330
|
const data = await response.json();
|
|
346
331
|
return data.pendingTxs;
|
|
@@ -390,10 +375,16 @@ class RestArkProvider {
|
|
|
390
375
|
}
|
|
391
376
|
// Check for TreeNoncesAggregated event
|
|
392
377
|
if (data.treeNoncesAggregated) {
|
|
378
|
+
// skip treeNoncesAggregated event, deprecated
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
381
|
+
if (data.treeNonces) {
|
|
393
382
|
return {
|
|
394
|
-
type: SettlementEventType.
|
|
395
|
-
id: data.
|
|
396
|
-
|
|
383
|
+
type: SettlementEventType.TreeNonces,
|
|
384
|
+
id: data.treeNonces.id,
|
|
385
|
+
topic: data.treeNonces.topic,
|
|
386
|
+
txid: data.treeNonces.txid,
|
|
387
|
+
nonces: decodeMusig2Nonces(data.treeNonces.nonces), // pubkey -> public nonce
|
|
397
388
|
};
|
|
398
389
|
}
|
|
399
390
|
// Check for TreeTx event
|
|
@@ -423,10 +414,6 @@ class RestArkProvider {
|
|
|
423
414
|
signature: data.treeSignature.signature,
|
|
424
415
|
};
|
|
425
416
|
}
|
|
426
|
-
// TODO: Handle TreeNoncesEvent when implemented server-side
|
|
427
|
-
if (data.treeNonces) {
|
|
428
|
-
return null;
|
|
429
|
-
}
|
|
430
417
|
// Skip heartbeat events
|
|
431
418
|
if (data.heartbeat) {
|
|
432
419
|
return null;
|
|
@@ -522,3 +509,8 @@ function mapVtxo(vtxo) {
|
|
|
522
509
|
arkTxid: vtxo.arkTxid,
|
|
523
510
|
};
|
|
524
511
|
}
|
|
512
|
+
function handleError(errorText, defaultMessage) {
|
|
513
|
+
const error = new Error(errorText);
|
|
514
|
+
const arkError = (0, errors_1.maybeArkError)(error);
|
|
515
|
+
throw arkError ?? new Error(defaultMessage);
|
|
516
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ArkError = void 0;
|
|
4
|
+
exports.maybeArkError = maybeArkError;
|
|
5
|
+
class ArkError extends Error {
|
|
6
|
+
constructor(code, message, name, metadata) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.message = message;
|
|
10
|
+
this.name = name;
|
|
11
|
+
this.metadata = metadata;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
exports.ArkError = ArkError;
|
|
15
|
+
/**
|
|
16
|
+
* Try to convert an error to an ArkError class, returning undefined if the error is not an ArkError
|
|
17
|
+
* @param error - The error to parse
|
|
18
|
+
* @returns The parsed ArkError, or undefined if the error is not an ArkError
|
|
19
|
+
*/
|
|
20
|
+
function maybeArkError(error) {
|
|
21
|
+
try {
|
|
22
|
+
if (!(error instanceof Error))
|
|
23
|
+
return undefined;
|
|
24
|
+
const decoded = JSON.parse(error.message);
|
|
25
|
+
if (!("details" in decoded))
|
|
26
|
+
return undefined;
|
|
27
|
+
if (!Array.isArray(decoded.details))
|
|
28
|
+
return undefined;
|
|
29
|
+
// search for a valid details object with the correct type
|
|
30
|
+
for (const details of decoded.details) {
|
|
31
|
+
if (!("@type" in details))
|
|
32
|
+
continue;
|
|
33
|
+
const type = details["@type"];
|
|
34
|
+
if (type !== "type.googleapis.com/ark.v1.ErrorDetails")
|
|
35
|
+
continue;
|
|
36
|
+
if (!("code" in details))
|
|
37
|
+
continue;
|
|
38
|
+
const code = details.code;
|
|
39
|
+
if (!("message" in details))
|
|
40
|
+
continue;
|
|
41
|
+
const message = details.message;
|
|
42
|
+
if (!("name" in details))
|
|
43
|
+
continue;
|
|
44
|
+
const name = details.name;
|
|
45
|
+
let metadata;
|
|
46
|
+
if ("metadata" in details && isMetadata(details.metadata)) {
|
|
47
|
+
metadata = details.metadata;
|
|
48
|
+
}
|
|
49
|
+
return new ArkError(code, message, name, metadata);
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
catch (e) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function isMetadata(value) {
|
|
58
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
59
|
+
}
|
|
@@ -61,18 +61,6 @@ class WalletRepositoryImpl {
|
|
|
61
61
|
return [];
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
|
-
async saveVtxo(address, vtxo) {
|
|
65
|
-
const vtxos = await this.getVtxos(address);
|
|
66
|
-
const existing = vtxos.findIndex((v) => v.txid === vtxo.txid && v.vout === vtxo.vout);
|
|
67
|
-
if (existing !== -1) {
|
|
68
|
-
vtxos[existing] = vtxo;
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
vtxos.push(vtxo);
|
|
72
|
-
}
|
|
73
|
-
this.cache.vtxos.set(address, vtxos.slice());
|
|
74
|
-
await this.storage.setItem(`vtxos:${address}`, JSON.stringify(vtxos.map(serializeVtxo)));
|
|
75
|
-
}
|
|
76
64
|
async saveVtxos(address, vtxos) {
|
|
77
65
|
const storedVtxos = await this.getVtxos(address);
|
|
78
66
|
for (const vtxo of vtxos) {
|
|
@@ -119,20 +107,6 @@ class WalletRepositoryImpl {
|
|
|
119
107
|
return [];
|
|
120
108
|
}
|
|
121
109
|
}
|
|
122
|
-
async saveTransaction(address, tx) {
|
|
123
|
-
const transactions = await this.getTransactionHistory(address);
|
|
124
|
-
const existing = transactions.findIndex((t) => t.key === tx.key);
|
|
125
|
-
if (existing !== -1) {
|
|
126
|
-
transactions[existing] = tx;
|
|
127
|
-
}
|
|
128
|
-
else {
|
|
129
|
-
transactions.push(tx);
|
|
130
|
-
}
|
|
131
|
-
// Sort by createdAt descending
|
|
132
|
-
transactions.sort((a, b) => b.createdAt - a.createdAt);
|
|
133
|
-
this.cache.transactions.set(address, transactions);
|
|
134
|
-
await this.storage.setItem(`tx:${address}`, JSON.stringify(transactions));
|
|
135
|
-
}
|
|
136
110
|
async saveTransactions(address, txs) {
|
|
137
111
|
const storedTransactions = await this.getTransactionHistory(address);
|
|
138
112
|
for (const tx of txs) {
|
|
@@ -77,10 +77,44 @@ class TreeSignerSession {
|
|
|
77
77
|
}
|
|
78
78
|
return publicNonces;
|
|
79
79
|
}
|
|
80
|
-
async
|
|
81
|
-
if (this.
|
|
82
|
-
throw
|
|
83
|
-
this.aggregateNonces
|
|
80
|
+
async aggregatedNonces(txid, noncesByPubkey) {
|
|
81
|
+
if (!this.graph)
|
|
82
|
+
throw exports.ErrMissingVtxoGraph;
|
|
83
|
+
if (!this.aggregateNonces) {
|
|
84
|
+
this.aggregateNonces = new Map();
|
|
85
|
+
}
|
|
86
|
+
if (!this.myNonces) {
|
|
87
|
+
await this.getNonces(); // generate nonces if not generated yet
|
|
88
|
+
}
|
|
89
|
+
if (this.aggregateNonces.has(txid)) {
|
|
90
|
+
return {
|
|
91
|
+
hasAllNonces: this.aggregateNonces.size === this.myNonces?.size,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
const myNonce = this.myNonces.get(txid);
|
|
95
|
+
if (!myNonce)
|
|
96
|
+
throw new Error(`missing nonce for txid ${txid}`);
|
|
97
|
+
const myPublicKey = await this.getPublicKey();
|
|
98
|
+
// set my nonce to not rely on server
|
|
99
|
+
noncesByPubkey.set(base_1.hex.encode(myPublicKey.subarray(1)), myNonce);
|
|
100
|
+
const tx = this.graph.find(txid);
|
|
101
|
+
if (!tx)
|
|
102
|
+
throw new Error(`missing tx for txid ${txid}`);
|
|
103
|
+
const cosigners = (0, unknownFields_1.getArkPsbtFields)(tx.root, 0, unknownFields_1.CosignerPublicKey).map((c) => base_1.hex.encode(c.key.subarray(1)) // xonly pubkey
|
|
104
|
+
);
|
|
105
|
+
const pubNonces = [];
|
|
106
|
+
for (const cosigner of cosigners) {
|
|
107
|
+
const nonce = noncesByPubkey.get(cosigner);
|
|
108
|
+
if (!nonce) {
|
|
109
|
+
throw new Error(`missing nonce for cosigner ${cosigner}`);
|
|
110
|
+
}
|
|
111
|
+
pubNonces.push(nonce.pubNonce);
|
|
112
|
+
}
|
|
113
|
+
const aggregateNonce = musig2.aggregateNonces(pubNonces);
|
|
114
|
+
this.aggregateNonces.set(txid, { pubNonce: aggregateNonce });
|
|
115
|
+
return {
|
|
116
|
+
hasAllNonces: this.aggregateNonces.size === this.myNonces?.size,
|
|
117
|
+
};
|
|
84
118
|
}
|
|
85
119
|
async sign() {
|
|
86
120
|
if (!this.graph)
|
|
@@ -51,9 +51,9 @@ var ArkPsbtFieldKey;
|
|
|
51
51
|
})(ArkPsbtFieldKey || (exports.ArkPsbtFieldKey = ArkPsbtFieldKey = {}));
|
|
52
52
|
/**
|
|
53
53
|
* ArkPsbtFieldKeyType is the type of the ark psbt field key.
|
|
54
|
-
* Every ark psbt field has key type
|
|
54
|
+
* Every ark psbt field has key type 222.
|
|
55
55
|
*/
|
|
56
|
-
exports.ArkPsbtFieldKeyType =
|
|
56
|
+
exports.ArkPsbtFieldKeyType = 222;
|
|
57
57
|
/**
|
|
58
58
|
* setArkPsbtField appends a new unknown field to the input at inputIndex
|
|
59
59
|
*
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Response = void 0;
|
|
4
|
+
const base_1 = require("@scure/base");
|
|
5
|
+
function getRandomId() {
|
|
6
|
+
const randomValue = crypto.getRandomValues(new Uint8Array(16));
|
|
7
|
+
return base_1.hex.encode(randomValue);
|
|
8
|
+
}
|
|
4
9
|
/**
|
|
5
10
|
* Response is the namespace that contains the response types for the service worker.
|
|
6
11
|
*/
|
|
@@ -187,4 +192,31 @@ var Response;
|
|
|
187
192
|
};
|
|
188
193
|
}
|
|
189
194
|
Response.walletReloaded = walletReloaded;
|
|
195
|
+
function isVtxoUpdate(response) {
|
|
196
|
+
return response.type === "VTXO_UPDATE";
|
|
197
|
+
}
|
|
198
|
+
Response.isVtxoUpdate = isVtxoUpdate;
|
|
199
|
+
function vtxoUpdate(newVtxos, spentVtxos) {
|
|
200
|
+
return {
|
|
201
|
+
type: "VTXO_UPDATE",
|
|
202
|
+
id: getRandomId(), // spontaneous update, not tied to a request
|
|
203
|
+
success: true,
|
|
204
|
+
spentVtxos,
|
|
205
|
+
newVtxos,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
Response.vtxoUpdate = vtxoUpdate;
|
|
209
|
+
function isUtxoUpdate(response) {
|
|
210
|
+
return response.type === "UTXO_UPDATE";
|
|
211
|
+
}
|
|
212
|
+
Response.isUtxoUpdate = isUtxoUpdate;
|
|
213
|
+
function utxoUpdate(coins) {
|
|
214
|
+
return {
|
|
215
|
+
type: "UTXO_UPDATE",
|
|
216
|
+
id: getRandomId(), // spontaneous update, not tied to a request
|
|
217
|
+
success: true,
|
|
218
|
+
coins,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
Response.utxoUpdate = utxoUpdate;
|
|
190
222
|
})(Response || (exports.Response = Response = {}));
|
|
@@ -256,6 +256,9 @@ class ServiceWorkerWallet {
|
|
|
256
256
|
return new Promise((resolve, reject) => {
|
|
257
257
|
const messageHandler = (event) => {
|
|
258
258
|
const response = event.data;
|
|
259
|
+
if (response.id !== message.id) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
259
262
|
if (!response.success) {
|
|
260
263
|
navigator.serviceWorker.removeEventListener("message", messageHandler);
|
|
261
264
|
reject(new Error(response.message));
|
|
@@ -130,11 +130,11 @@ class Worker {
|
|
|
130
130
|
...spentVtxos,
|
|
131
131
|
]);
|
|
132
132
|
// notify all clients about the vtxo update
|
|
133
|
-
this.sendMessageToAllClients(
|
|
133
|
+
this.sendMessageToAllClients(response_1.Response.vtxoUpdate(newVtxos, spentVtxos));
|
|
134
134
|
}
|
|
135
135
|
if (funds.type === "utxo") {
|
|
136
136
|
// notify all clients about the utxo update
|
|
137
|
-
this.sendMessageToAllClients(
|
|
137
|
+
this.sendMessageToAllClients(response_1.Response.utxoUpdate(funds.coins));
|
|
138
138
|
}
|
|
139
139
|
});
|
|
140
140
|
}
|
|
@@ -518,15 +518,12 @@ class Worker {
|
|
|
518
518
|
event.source?.postMessage(response_1.Response.error(message.id, "Unknown message type"));
|
|
519
519
|
}
|
|
520
520
|
}
|
|
521
|
-
async sendMessageToAllClients(
|
|
521
|
+
async sendMessageToAllClients(message) {
|
|
522
522
|
self.clients
|
|
523
523
|
.matchAll({ includeUncontrolled: true, type: "window" })
|
|
524
524
|
.then((clients) => {
|
|
525
525
|
clients.forEach((client) => {
|
|
526
|
-
client.postMessage(
|
|
527
|
-
type,
|
|
528
|
-
message,
|
|
529
|
-
});
|
|
526
|
+
client.postMessage(message);
|
|
530
527
|
});
|
|
531
528
|
});
|
|
532
529
|
}
|
|
@@ -546,13 +546,13 @@ class Wallet {
|
|
|
546
546
|
if (!hasOffchainOutputs) {
|
|
547
547
|
// if there are no offchain outputs, we don't have to handle musig2 tree signatures
|
|
548
548
|
// we can directly advance to the finalization step
|
|
549
|
-
step = ark_1.SettlementEventType.
|
|
549
|
+
step = ark_1.SettlementEventType.TreeNonces;
|
|
550
550
|
}
|
|
551
551
|
}
|
|
552
552
|
break;
|
|
553
553
|
case ark_1.SettlementEventType.TreeTx:
|
|
554
554
|
if (step !== ark_1.SettlementEventType.BatchStarted &&
|
|
555
|
-
step !== ark_1.SettlementEventType.
|
|
555
|
+
step !== ark_1.SettlementEventType.TreeNonces) {
|
|
556
556
|
continue;
|
|
557
557
|
}
|
|
558
558
|
// index 0 = vtxo tree
|
|
@@ -568,7 +568,7 @@ class Wallet {
|
|
|
568
568
|
}
|
|
569
569
|
break;
|
|
570
570
|
case ark_1.SettlementEventType.TreeSignature:
|
|
571
|
-
if (step !== ark_1.SettlementEventType.
|
|
571
|
+
if (step !== ark_1.SettlementEventType.TreeNonces) {
|
|
572
572
|
continue;
|
|
573
573
|
}
|
|
574
574
|
if (!hasOffchainOutputs) {
|
|
@@ -610,7 +610,7 @@ class Wallet {
|
|
|
610
610
|
break;
|
|
611
611
|
// the musig2 nonces of the vtxo tree transactions are generated
|
|
612
612
|
// the server expects now the partial musig2 signatures
|
|
613
|
-
case ark_1.SettlementEventType.
|
|
613
|
+
case ark_1.SettlementEventType.TreeNonces:
|
|
614
614
|
if (step !== ark_1.SettlementEventType.TreeSigningStarted) {
|
|
615
615
|
continue;
|
|
616
616
|
}
|
|
@@ -618,14 +618,18 @@ class Wallet {
|
|
|
618
618
|
if (!session) {
|
|
619
619
|
throw new Error("Signing session not set");
|
|
620
620
|
}
|
|
621
|
-
await this.
|
|
621
|
+
const signed = await this.handleSettlementTreeNoncesEvent(event, session);
|
|
622
|
+
if (signed) {
|
|
623
|
+
step = event.type;
|
|
624
|
+
}
|
|
625
|
+
break;
|
|
622
626
|
}
|
|
623
627
|
step = event.type;
|
|
624
628
|
break;
|
|
625
629
|
// the vtxo tree is signed, craft, sign and submit forfeit transactions
|
|
626
630
|
// if any boarding utxos are involved, the settlement tx is also signed
|
|
627
631
|
case ark_1.SettlementEventType.BatchFinalization:
|
|
628
|
-
if (step !== ark_1.SettlementEventType.
|
|
632
|
+
if (step !== ark_1.SettlementEventType.TreeNonces) {
|
|
629
633
|
continue;
|
|
630
634
|
}
|
|
631
635
|
if (!this.forfeitOutputScript) {
|
|
@@ -771,11 +775,15 @@ class Wallet {
|
|
|
771
775
|
const nonces = await session.getNonces();
|
|
772
776
|
await this.arkProvider.submitTreeNonces(event.id, pubkey, nonces);
|
|
773
777
|
}
|
|
774
|
-
async
|
|
775
|
-
session.
|
|
778
|
+
async handleSettlementTreeNoncesEvent(event, session) {
|
|
779
|
+
const { hasAllNonces } = await session.aggregatedNonces(event.txid, event.nonces);
|
|
780
|
+
// wait to receive and aggregate all nonces before sending signatures
|
|
781
|
+
if (!hasAllNonces)
|
|
782
|
+
return false;
|
|
776
783
|
const signatures = await session.sign();
|
|
777
784
|
const pubkey = base_1.hex.encode(await session.getPublicKey());
|
|
778
785
|
await this.arkProvider.submitTreeSignatures(event.id, pubkey, signatures);
|
|
786
|
+
return true;
|
|
779
787
|
}
|
|
780
788
|
async handleSettlementFinalizationEvent(event, inputs, forfeitOutputScript, connectorsGraph) {
|
|
781
789
|
// the signed forfeits transactions to submit
|
package/dist/esm/index.js
CHANGED
|
@@ -28,6 +28,7 @@ import { P2A } from './utils/anchor.js';
|
|
|
28
28
|
import { Unroll } from './wallet/unroll.js';
|
|
29
29
|
import { WalletRepositoryImpl } from './repositories/walletRepository.js';
|
|
30
30
|
import { ContractRepositoryImpl } from './repositories/contractRepository.js';
|
|
31
|
+
import { ArkError, maybeArkError } from './providers/errors.js';
|
|
31
32
|
export {
|
|
32
33
|
// Wallets
|
|
33
34
|
Wallet, SingleKey, OnchainWallet, Ramps, VtxoManager,
|
|
@@ -56,4 +57,6 @@ Intent,
|
|
|
56
57
|
// TxTree
|
|
57
58
|
TxTree,
|
|
58
59
|
// Anchor
|
|
59
|
-
P2A, Unroll, Transaction,
|
|
60
|
+
P2A, Unroll, Transaction,
|
|
61
|
+
// Errors
|
|
62
|
+
ArkError, maybeArkError, };
|
package/dist/esm/musig2/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { hex } from "@scure/base";
|
|
2
2
|
import { eventSourceIterator } from './utils.js';
|
|
3
|
+
import { maybeArkError } from './errors.js';
|
|
3
4
|
export var SettlementEventType;
|
|
4
5
|
(function (SettlementEventType) {
|
|
5
6
|
SettlementEventType["BatchStarted"] = "batch_started";
|
|
@@ -7,7 +8,7 @@ export var SettlementEventType;
|
|
|
7
8
|
SettlementEventType["BatchFinalized"] = "batch_finalized";
|
|
8
9
|
SettlementEventType["BatchFailed"] = "batch_failed";
|
|
9
10
|
SettlementEventType["TreeSigningStarted"] = "tree_signing_started";
|
|
10
|
-
SettlementEventType["
|
|
11
|
+
SettlementEventType["TreeNonces"] = "tree_nonces";
|
|
11
12
|
SettlementEventType["TreeTx"] = "tree_tx";
|
|
12
13
|
SettlementEventType["TreeSignature"] = "tree_signature";
|
|
13
14
|
})(SettlementEventType || (SettlementEventType = {}));
|
|
@@ -28,7 +29,8 @@ export class RestArkProvider {
|
|
|
28
29
|
const url = `${this.serverUrl}/v1/info`;
|
|
29
30
|
const response = await fetch(url);
|
|
30
31
|
if (!response.ok) {
|
|
31
|
-
|
|
32
|
+
const errorText = await response.text();
|
|
33
|
+
handleError(errorText, `Failed to get server info: ${response.statusText}`);
|
|
32
34
|
}
|
|
33
35
|
const fromServer = await response.json();
|
|
34
36
|
return {
|
|
@@ -78,16 +80,7 @@ export class RestArkProvider {
|
|
|
78
80
|
});
|
|
79
81
|
if (!response.ok) {
|
|
80
82
|
const errorText = await response.text();
|
|
81
|
-
|
|
82
|
-
const grpcError = JSON.parse(errorText);
|
|
83
|
-
// gRPC errors usually have a message and code field
|
|
84
|
-
throw new Error(`Failed to submit virtual transaction: ${grpcError.message || grpcError.error || errorText}`);
|
|
85
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
86
|
-
}
|
|
87
|
-
catch (_) {
|
|
88
|
-
// If JSON parse fails, use the raw error text
|
|
89
|
-
throw new Error(`Failed to submit virtual transaction: ${errorText}`);
|
|
90
|
-
}
|
|
83
|
+
handleError(errorText, `Failed to submit virtual transaction: ${errorText}`);
|
|
91
84
|
}
|
|
92
85
|
const data = await response.json();
|
|
93
86
|
return {
|
|
@@ -110,7 +103,7 @@ export class RestArkProvider {
|
|
|
110
103
|
});
|
|
111
104
|
if (!response.ok) {
|
|
112
105
|
const errorText = await response.text();
|
|
113
|
-
|
|
106
|
+
handleError(errorText, `Failed to finalize offchain transaction: ${errorText}`);
|
|
114
107
|
}
|
|
115
108
|
}
|
|
116
109
|
async registerIntent(intent) {
|
|
@@ -129,7 +122,7 @@ export class RestArkProvider {
|
|
|
129
122
|
});
|
|
130
123
|
if (!response.ok) {
|
|
131
124
|
const errorText = await response.text();
|
|
132
|
-
|
|
125
|
+
handleError(errorText, `Failed to register intent: ${errorText}`);
|
|
133
126
|
}
|
|
134
127
|
const data = await response.json();
|
|
135
128
|
return data.intentId;
|
|
@@ -150,7 +143,7 @@ export class RestArkProvider {
|
|
|
150
143
|
});
|
|
151
144
|
if (!response.ok) {
|
|
152
145
|
const errorText = await response.text();
|
|
153
|
-
|
|
146
|
+
handleError(errorText, `Failed to delete intent: ${errorText}`);
|
|
154
147
|
}
|
|
155
148
|
}
|
|
156
149
|
async confirmRegistration(intentId) {
|
|
@@ -166,7 +159,7 @@ export class RestArkProvider {
|
|
|
166
159
|
});
|
|
167
160
|
if (!response.ok) {
|
|
168
161
|
const errorText = await response.text();
|
|
169
|
-
|
|
162
|
+
handleError(errorText, `Failed to confirm registration: ${errorText}`);
|
|
170
163
|
}
|
|
171
164
|
}
|
|
172
165
|
async submitTreeNonces(batchId, pubkey, nonces) {
|
|
@@ -184,7 +177,7 @@ export class RestArkProvider {
|
|
|
184
177
|
});
|
|
185
178
|
if (!response.ok) {
|
|
186
179
|
const errorText = await response.text();
|
|
187
|
-
|
|
180
|
+
handleError(errorText, `Failed to submit tree nonces: ${errorText}`);
|
|
188
181
|
}
|
|
189
182
|
}
|
|
190
183
|
async submitTreeSignatures(batchId, pubkey, signatures) {
|
|
@@ -202,7 +195,7 @@ export class RestArkProvider {
|
|
|
202
195
|
});
|
|
203
196
|
if (!response.ok) {
|
|
204
197
|
const errorText = await response.text();
|
|
205
|
-
|
|
198
|
+
handleError(errorText, `Failed to submit tree signatures: ${errorText}`);
|
|
206
199
|
}
|
|
207
200
|
}
|
|
208
201
|
async submitSignedForfeitTxs(signedForfeitTxs, signedCommitmentTx) {
|
|
@@ -218,7 +211,8 @@ export class RestArkProvider {
|
|
|
218
211
|
}),
|
|
219
212
|
});
|
|
220
213
|
if (!response.ok) {
|
|
221
|
-
|
|
214
|
+
const errorText = await response.text();
|
|
215
|
+
handleError(errorText, `Failed to submit forfeit transactions: ${response.statusText}`);
|
|
222
216
|
}
|
|
223
217
|
}
|
|
224
218
|
async *getEventStream(signal, topics) {
|
|
@@ -327,16 +321,7 @@ export class RestArkProvider {
|
|
|
327
321
|
});
|
|
328
322
|
if (!response.ok) {
|
|
329
323
|
const errorText = await response.text();
|
|
330
|
-
|
|
331
|
-
const grpcError = JSON.parse(errorText);
|
|
332
|
-
// gRPC errors usually have a message and code field
|
|
333
|
-
throw new Error(`Failed to get pending transactions: ${grpcError.message || grpcError.error || errorText}`);
|
|
334
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
335
|
-
}
|
|
336
|
-
catch (_) {
|
|
337
|
-
// If JSON parse fails, use the raw error text
|
|
338
|
-
throw new Error(`Failed to get pending transactions: ${errorText}`);
|
|
339
|
-
}
|
|
324
|
+
handleError(errorText, `Failed to get pending transactions: ${errorText}`);
|
|
340
325
|
}
|
|
341
326
|
const data = await response.json();
|
|
342
327
|
return data.pendingTxs;
|
|
@@ -386,10 +371,16 @@ export class RestArkProvider {
|
|
|
386
371
|
}
|
|
387
372
|
// Check for TreeNoncesAggregated event
|
|
388
373
|
if (data.treeNoncesAggregated) {
|
|
374
|
+
// skip treeNoncesAggregated event, deprecated
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
if (data.treeNonces) {
|
|
389
378
|
return {
|
|
390
|
-
type: SettlementEventType.
|
|
391
|
-
id: data.
|
|
392
|
-
|
|
379
|
+
type: SettlementEventType.TreeNonces,
|
|
380
|
+
id: data.treeNonces.id,
|
|
381
|
+
topic: data.treeNonces.topic,
|
|
382
|
+
txid: data.treeNonces.txid,
|
|
383
|
+
nonces: decodeMusig2Nonces(data.treeNonces.nonces), // pubkey -> public nonce
|
|
393
384
|
};
|
|
394
385
|
}
|
|
395
386
|
// Check for TreeTx event
|
|
@@ -419,10 +410,6 @@ export class RestArkProvider {
|
|
|
419
410
|
signature: data.treeSignature.signature,
|
|
420
411
|
};
|
|
421
412
|
}
|
|
422
|
-
// TODO: Handle TreeNoncesEvent when implemented server-side
|
|
423
|
-
if (data.treeNonces) {
|
|
424
|
-
return null;
|
|
425
|
-
}
|
|
426
413
|
// Skip heartbeat events
|
|
427
414
|
if (data.heartbeat) {
|
|
428
415
|
return null;
|
|
@@ -517,3 +504,8 @@ function mapVtxo(vtxo) {
|
|
|
517
504
|
arkTxid: vtxo.arkTxid,
|
|
518
505
|
};
|
|
519
506
|
}
|
|
507
|
+
function handleError(errorText, defaultMessage) {
|
|
508
|
+
const error = new Error(errorText);
|
|
509
|
+
const arkError = maybeArkError(error);
|
|
510
|
+
throw arkError ?? new Error(defaultMessage);
|
|
511
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export class ArkError extends Error {
|
|
2
|
+
constructor(code, message, name, metadata) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.code = code;
|
|
5
|
+
this.message = message;
|
|
6
|
+
this.name = name;
|
|
7
|
+
this.metadata = metadata;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Try to convert an error to an ArkError class, returning undefined if the error is not an ArkError
|
|
12
|
+
* @param error - The error to parse
|
|
13
|
+
* @returns The parsed ArkError, or undefined if the error is not an ArkError
|
|
14
|
+
*/
|
|
15
|
+
export function maybeArkError(error) {
|
|
16
|
+
try {
|
|
17
|
+
if (!(error instanceof Error))
|
|
18
|
+
return undefined;
|
|
19
|
+
const decoded = JSON.parse(error.message);
|
|
20
|
+
if (!("details" in decoded))
|
|
21
|
+
return undefined;
|
|
22
|
+
if (!Array.isArray(decoded.details))
|
|
23
|
+
return undefined;
|
|
24
|
+
// search for a valid details object with the correct type
|
|
25
|
+
for (const details of decoded.details) {
|
|
26
|
+
if (!("@type" in details))
|
|
27
|
+
continue;
|
|
28
|
+
const type = details["@type"];
|
|
29
|
+
if (type !== "type.googleapis.com/ark.v1.ErrorDetails")
|
|
30
|
+
continue;
|
|
31
|
+
if (!("code" in details))
|
|
32
|
+
continue;
|
|
33
|
+
const code = details.code;
|
|
34
|
+
if (!("message" in details))
|
|
35
|
+
continue;
|
|
36
|
+
const message = details.message;
|
|
37
|
+
if (!("name" in details))
|
|
38
|
+
continue;
|
|
39
|
+
const name = details.name;
|
|
40
|
+
let metadata;
|
|
41
|
+
if ("metadata" in details && isMetadata(details.metadata)) {
|
|
42
|
+
metadata = details.metadata;
|
|
43
|
+
}
|
|
44
|
+
return new ArkError(code, message, name, metadata);
|
|
45
|
+
}
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
catch (e) {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function isMetadata(value) {
|
|
53
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
54
|
+
}
|
|
@@ -58,18 +58,6 @@ export class WalletRepositoryImpl {
|
|
|
58
58
|
return [];
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
-
async saveVtxo(address, vtxo) {
|
|
62
|
-
const vtxos = await this.getVtxos(address);
|
|
63
|
-
const existing = vtxos.findIndex((v) => v.txid === vtxo.txid && v.vout === vtxo.vout);
|
|
64
|
-
if (existing !== -1) {
|
|
65
|
-
vtxos[existing] = vtxo;
|
|
66
|
-
}
|
|
67
|
-
else {
|
|
68
|
-
vtxos.push(vtxo);
|
|
69
|
-
}
|
|
70
|
-
this.cache.vtxos.set(address, vtxos.slice());
|
|
71
|
-
await this.storage.setItem(`vtxos:${address}`, JSON.stringify(vtxos.map(serializeVtxo)));
|
|
72
|
-
}
|
|
73
61
|
async saveVtxos(address, vtxos) {
|
|
74
62
|
const storedVtxos = await this.getVtxos(address);
|
|
75
63
|
for (const vtxo of vtxos) {
|
|
@@ -116,20 +104,6 @@ export class WalletRepositoryImpl {
|
|
|
116
104
|
return [];
|
|
117
105
|
}
|
|
118
106
|
}
|
|
119
|
-
async saveTransaction(address, tx) {
|
|
120
|
-
const transactions = await this.getTransactionHistory(address);
|
|
121
|
-
const existing = transactions.findIndex((t) => t.key === tx.key);
|
|
122
|
-
if (existing !== -1) {
|
|
123
|
-
transactions[existing] = tx;
|
|
124
|
-
}
|
|
125
|
-
else {
|
|
126
|
-
transactions.push(tx);
|
|
127
|
-
}
|
|
128
|
-
// Sort by createdAt descending
|
|
129
|
-
transactions.sort((a, b) => b.createdAt - a.createdAt);
|
|
130
|
-
this.cache.transactions.set(address, transactions);
|
|
131
|
-
await this.storage.setItem(`tx:${address}`, JSON.stringify(transactions));
|
|
132
|
-
}
|
|
133
107
|
async saveTransactions(address, txs) {
|
|
134
108
|
const storedTransactions = await this.getTransactionHistory(address);
|
|
135
109
|
for (const tx of txs) {
|
|
@@ -40,10 +40,44 @@ export class TreeSignerSession {
|
|
|
40
40
|
}
|
|
41
41
|
return publicNonces;
|
|
42
42
|
}
|
|
43
|
-
async
|
|
44
|
-
if (this.
|
|
45
|
-
throw
|
|
46
|
-
this.aggregateNonces
|
|
43
|
+
async aggregatedNonces(txid, noncesByPubkey) {
|
|
44
|
+
if (!this.graph)
|
|
45
|
+
throw ErrMissingVtxoGraph;
|
|
46
|
+
if (!this.aggregateNonces) {
|
|
47
|
+
this.aggregateNonces = new Map();
|
|
48
|
+
}
|
|
49
|
+
if (!this.myNonces) {
|
|
50
|
+
await this.getNonces(); // generate nonces if not generated yet
|
|
51
|
+
}
|
|
52
|
+
if (this.aggregateNonces.has(txid)) {
|
|
53
|
+
return {
|
|
54
|
+
hasAllNonces: this.aggregateNonces.size === this.myNonces?.size,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
const myNonce = this.myNonces.get(txid);
|
|
58
|
+
if (!myNonce)
|
|
59
|
+
throw new Error(`missing nonce for txid ${txid}`);
|
|
60
|
+
const myPublicKey = await this.getPublicKey();
|
|
61
|
+
// set my nonce to not rely on server
|
|
62
|
+
noncesByPubkey.set(hex.encode(myPublicKey.subarray(1)), myNonce);
|
|
63
|
+
const tx = this.graph.find(txid);
|
|
64
|
+
if (!tx)
|
|
65
|
+
throw new Error(`missing tx for txid ${txid}`);
|
|
66
|
+
const cosigners = getArkPsbtFields(tx.root, 0, CosignerPublicKey).map((c) => hex.encode(c.key.subarray(1)) // xonly pubkey
|
|
67
|
+
);
|
|
68
|
+
const pubNonces = [];
|
|
69
|
+
for (const cosigner of cosigners) {
|
|
70
|
+
const nonce = noncesByPubkey.get(cosigner);
|
|
71
|
+
if (!nonce) {
|
|
72
|
+
throw new Error(`missing nonce for cosigner ${cosigner}`);
|
|
73
|
+
}
|
|
74
|
+
pubNonces.push(nonce.pubNonce);
|
|
75
|
+
}
|
|
76
|
+
const aggregateNonce = musig2.aggregateNonces(pubNonces);
|
|
77
|
+
this.aggregateNonces.set(txid, { pubNonce: aggregateNonce });
|
|
78
|
+
return {
|
|
79
|
+
hasAllNonces: this.aggregateNonces.size === this.myNonces?.size,
|
|
80
|
+
};
|
|
47
81
|
}
|
|
48
82
|
async sign() {
|
|
49
83
|
if (!this.graph)
|
|
@@ -13,9 +13,9 @@ export var ArkPsbtFieldKey;
|
|
|
13
13
|
})(ArkPsbtFieldKey || (ArkPsbtFieldKey = {}));
|
|
14
14
|
/**
|
|
15
15
|
* ArkPsbtFieldKeyType is the type of the ark psbt field key.
|
|
16
|
-
* Every ark psbt field has key type
|
|
16
|
+
* Every ark psbt field has key type 222.
|
|
17
17
|
*/
|
|
18
|
-
export const ArkPsbtFieldKeyType =
|
|
18
|
+
export const ArkPsbtFieldKeyType = 222;
|
|
19
19
|
/**
|
|
20
20
|
* setArkPsbtField appends a new unknown field to the input at inputIndex
|
|
21
21
|
*
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import { hex } from "@scure/base";
|
|
2
|
+
function getRandomId() {
|
|
3
|
+
const randomValue = crypto.getRandomValues(new Uint8Array(16));
|
|
4
|
+
return hex.encode(randomValue);
|
|
5
|
+
}
|
|
1
6
|
/**
|
|
2
7
|
* Response is the namespace that contains the response types for the service worker.
|
|
3
8
|
*/
|
|
@@ -184,4 +189,31 @@ export var Response;
|
|
|
184
189
|
};
|
|
185
190
|
}
|
|
186
191
|
Response.walletReloaded = walletReloaded;
|
|
192
|
+
function isVtxoUpdate(response) {
|
|
193
|
+
return response.type === "VTXO_UPDATE";
|
|
194
|
+
}
|
|
195
|
+
Response.isVtxoUpdate = isVtxoUpdate;
|
|
196
|
+
function vtxoUpdate(newVtxos, spentVtxos) {
|
|
197
|
+
return {
|
|
198
|
+
type: "VTXO_UPDATE",
|
|
199
|
+
id: getRandomId(), // spontaneous update, not tied to a request
|
|
200
|
+
success: true,
|
|
201
|
+
spentVtxos,
|
|
202
|
+
newVtxos,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
Response.vtxoUpdate = vtxoUpdate;
|
|
206
|
+
function isUtxoUpdate(response) {
|
|
207
|
+
return response.type === "UTXO_UPDATE";
|
|
208
|
+
}
|
|
209
|
+
Response.isUtxoUpdate = isUtxoUpdate;
|
|
210
|
+
function utxoUpdate(coins) {
|
|
211
|
+
return {
|
|
212
|
+
type: "UTXO_UPDATE",
|
|
213
|
+
id: getRandomId(), // spontaneous update, not tied to a request
|
|
214
|
+
success: true,
|
|
215
|
+
coins,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
Response.utxoUpdate = utxoUpdate;
|
|
187
219
|
})(Response || (Response = {}));
|
|
@@ -253,6 +253,9 @@ export class ServiceWorkerWallet {
|
|
|
253
253
|
return new Promise((resolve, reject) => {
|
|
254
254
|
const messageHandler = (event) => {
|
|
255
255
|
const response = event.data;
|
|
256
|
+
if (response.id !== message.id) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
256
259
|
if (!response.success) {
|
|
257
260
|
navigator.serviceWorker.removeEventListener("message", messageHandler);
|
|
258
261
|
reject(new Error(response.message));
|
|
@@ -127,11 +127,11 @@ export class Worker {
|
|
|
127
127
|
...spentVtxos,
|
|
128
128
|
]);
|
|
129
129
|
// notify all clients about the vtxo update
|
|
130
|
-
this.sendMessageToAllClients(
|
|
130
|
+
this.sendMessageToAllClients(Response.vtxoUpdate(newVtxos, spentVtxos));
|
|
131
131
|
}
|
|
132
132
|
if (funds.type === "utxo") {
|
|
133
133
|
// notify all clients about the utxo update
|
|
134
|
-
this.sendMessageToAllClients(
|
|
134
|
+
this.sendMessageToAllClients(Response.utxoUpdate(funds.coins));
|
|
135
135
|
}
|
|
136
136
|
});
|
|
137
137
|
}
|
|
@@ -515,15 +515,12 @@ export class Worker {
|
|
|
515
515
|
event.source?.postMessage(Response.error(message.id, "Unknown message type"));
|
|
516
516
|
}
|
|
517
517
|
}
|
|
518
|
-
async sendMessageToAllClients(
|
|
518
|
+
async sendMessageToAllClients(message) {
|
|
519
519
|
self.clients
|
|
520
520
|
.matchAll({ includeUncontrolled: true, type: "window" })
|
|
521
521
|
.then((clients) => {
|
|
522
522
|
clients.forEach((client) => {
|
|
523
|
-
client.postMessage(
|
|
524
|
-
type,
|
|
525
|
-
message,
|
|
526
|
-
});
|
|
523
|
+
client.postMessage(message);
|
|
527
524
|
});
|
|
528
525
|
});
|
|
529
526
|
}
|
|
@@ -509,13 +509,13 @@ export class Wallet {
|
|
|
509
509
|
if (!hasOffchainOutputs) {
|
|
510
510
|
// if there are no offchain outputs, we don't have to handle musig2 tree signatures
|
|
511
511
|
// we can directly advance to the finalization step
|
|
512
|
-
step = SettlementEventType.
|
|
512
|
+
step = SettlementEventType.TreeNonces;
|
|
513
513
|
}
|
|
514
514
|
}
|
|
515
515
|
break;
|
|
516
516
|
case SettlementEventType.TreeTx:
|
|
517
517
|
if (step !== SettlementEventType.BatchStarted &&
|
|
518
|
-
step !== SettlementEventType.
|
|
518
|
+
step !== SettlementEventType.TreeNonces) {
|
|
519
519
|
continue;
|
|
520
520
|
}
|
|
521
521
|
// index 0 = vtxo tree
|
|
@@ -531,7 +531,7 @@ export class Wallet {
|
|
|
531
531
|
}
|
|
532
532
|
break;
|
|
533
533
|
case SettlementEventType.TreeSignature:
|
|
534
|
-
if (step !== SettlementEventType.
|
|
534
|
+
if (step !== SettlementEventType.TreeNonces) {
|
|
535
535
|
continue;
|
|
536
536
|
}
|
|
537
537
|
if (!hasOffchainOutputs) {
|
|
@@ -573,7 +573,7 @@ export class Wallet {
|
|
|
573
573
|
break;
|
|
574
574
|
// the musig2 nonces of the vtxo tree transactions are generated
|
|
575
575
|
// the server expects now the partial musig2 signatures
|
|
576
|
-
case SettlementEventType.
|
|
576
|
+
case SettlementEventType.TreeNonces:
|
|
577
577
|
if (step !== SettlementEventType.TreeSigningStarted) {
|
|
578
578
|
continue;
|
|
579
579
|
}
|
|
@@ -581,14 +581,18 @@ export class Wallet {
|
|
|
581
581
|
if (!session) {
|
|
582
582
|
throw new Error("Signing session not set");
|
|
583
583
|
}
|
|
584
|
-
await this.
|
|
584
|
+
const signed = await this.handleSettlementTreeNoncesEvent(event, session);
|
|
585
|
+
if (signed) {
|
|
586
|
+
step = event.type;
|
|
587
|
+
}
|
|
588
|
+
break;
|
|
585
589
|
}
|
|
586
590
|
step = event.type;
|
|
587
591
|
break;
|
|
588
592
|
// the vtxo tree is signed, craft, sign and submit forfeit transactions
|
|
589
593
|
// if any boarding utxos are involved, the settlement tx is also signed
|
|
590
594
|
case SettlementEventType.BatchFinalization:
|
|
591
|
-
if (step !== SettlementEventType.
|
|
595
|
+
if (step !== SettlementEventType.TreeNonces) {
|
|
592
596
|
continue;
|
|
593
597
|
}
|
|
594
598
|
if (!this.forfeitOutputScript) {
|
|
@@ -734,11 +738,15 @@ export class Wallet {
|
|
|
734
738
|
const nonces = await session.getNonces();
|
|
735
739
|
await this.arkProvider.submitTreeNonces(event.id, pubkey, nonces);
|
|
736
740
|
}
|
|
737
|
-
async
|
|
738
|
-
session.
|
|
741
|
+
async handleSettlementTreeNoncesEvent(event, session) {
|
|
742
|
+
const { hasAllNonces } = await session.aggregatedNonces(event.txid, event.nonces);
|
|
743
|
+
// wait to receive and aggregate all nonces before sending signatures
|
|
744
|
+
if (!hasAllNonces)
|
|
745
|
+
return false;
|
|
739
746
|
const signatures = await session.sign();
|
|
740
747
|
const pubkey = hex.encode(await session.getPublicKey());
|
|
741
748
|
await this.arkProvider.submitTreeSignatures(event.id, pubkey, signatures);
|
|
749
|
+
return true;
|
|
742
750
|
}
|
|
743
751
|
async handleSettlementFinalizationEvent(event, inputs, forfeitOutputScript, connectorsGraph) {
|
|
744
752
|
// the signed forfeits transactions to submit
|
package/dist/types/index.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ import { Worker } from "./wallet/serviceWorker/worker";
|
|
|
18
18
|
import { Request } from "./wallet/serviceWorker/request";
|
|
19
19
|
import { Response } from "./wallet/serviceWorker/response";
|
|
20
20
|
import { ESPLORA_URL, EsploraProvider, OnchainProvider, ExplorerTransaction } from "./providers/onchain";
|
|
21
|
-
import { RestArkProvider, ArkProvider, SettlementEvent, SettlementEventType, ArkInfo, SignedIntent, Output, TxNotification, BatchFinalizationEvent, BatchFinalizedEvent, BatchFailedEvent, TreeSigningStartedEvent,
|
|
21
|
+
import { RestArkProvider, ArkProvider, SettlementEvent, SettlementEventType, ArkInfo, SignedIntent, Output, TxNotification, BatchFinalizationEvent, BatchFinalizedEvent, BatchFailedEvent, TreeSigningStartedEvent, TreeNoncesEvent, BatchStartedEvent, TreeTxEvent, TreeSignatureEvent, ScheduledSession } from "./providers/ark";
|
|
22
22
|
import { CLTVMultisigTapscript, ConditionCSVMultisigTapscript, ConditionMultisigTapscript, CSVMultisigTapscript, decodeTapscript, MultisigTapscript, TapscriptType, ArkTapscript, RelativeTimelock } from "./script/tapscript";
|
|
23
23
|
import { hasBoardingTxExpired, buildOffchainTx, verifyTapscriptSignatures, ArkTxInput, OffchainTx } from "./utils/arkTransaction";
|
|
24
24
|
import { VtxoTaprootTree, ConditionWitness, getArkPsbtFields, setArkPsbtField, ArkPsbtFieldCoder, ArkPsbtFieldKey, ArkPsbtFieldKeyType, CosignerPublicKey, VtxoTreeExpiry } from "./utils/unknownFields";
|
|
@@ -32,5 +32,6 @@ import { AnchorBumper, P2A } from "./utils/anchor";
|
|
|
32
32
|
import { Unroll } from "./wallet/unroll";
|
|
33
33
|
import { WalletRepositoryImpl } from "./repositories/walletRepository";
|
|
34
34
|
import { ContractRepositoryImpl } from "./repositories/contractRepository";
|
|
35
|
-
|
|
36
|
-
export
|
|
35
|
+
import { ArkError, maybeArkError } from "./providers/errors";
|
|
36
|
+
export { Wallet, SingleKey, OnchainWallet, Ramps, VtxoManager, ESPLORA_URL, EsploraProvider, RestArkProvider, RestIndexerProvider, ArkAddress, DefaultVtxo, VtxoScript, VHTLC, TxType, IndexerTxType, ChainTxType, SettlementEventType, setupServiceWorker, Worker, ServiceWorkerWallet, Request, Response, decodeTapscript, MultisigTapscript, CSVMultisigTapscript, ConditionCSVMultisigTapscript, ConditionMultisigTapscript, CLTVMultisigTapscript, ArkPsbtFieldKey, ArkPsbtFieldKeyType, setArkPsbtField, getArkPsbtFields, CosignerPublicKey, VtxoTreeExpiry, VtxoTaprootTree, ConditionWitness, buildOffchainTx, verifyTapscriptSignatures, waitForIncomingFunds, hasBoardingTxExpired, ArkNote, networks, WalletRepositoryImpl, ContractRepositoryImpl, Intent, TxTree, P2A, Unroll, Transaction, ArkError, maybeArkError, };
|
|
37
|
+
export type { Identity, IWallet, WalletConfig, ProviderClass, ArkTransaction, Coin, ExtendedCoin, ExtendedVirtualCoin, WalletBalance, SendBitcoinParams, Recipient, SettleParams, Status, VirtualStatus, Outpoint, VirtualCoin, TxKey, TapscriptType, ArkTxInput, OffchainTx, TapLeaves, IncomingFunds, IndexerProvider, PageResponse, Batch, ChainTx, CommitmentTx, TxHistoryRecord, Vtxo, VtxoChain, Tx, OnchainProvider, ArkProvider, SettlementEvent, ArkInfo, SignedIntent, Output, TxNotification, ExplorerTransaction, BatchFinalizationEvent, BatchFinalizedEvent, BatchFailedEvent, TreeSigningStartedEvent, TreeNoncesEvent, BatchStartedEvent, TreeTxEvent, TreeSignatureEvent, ScheduledSession, PaginationOptions, SubscriptionResponse, SubscriptionHeartbeat, SubscriptionEvent, Network, NetworkName, ArkTapscript, RelativeTimelock, EncodedVtxoScript, TapLeafScript, SignerSession, TreeNonces, TreePartialSigs, GetVtxosFilter, Nonces, PartialSig, ArkPsbtFieldCoder, TxTreeNode, AnchorBumper, };
|
|
@@ -11,7 +11,7 @@ export declare enum SettlementEventType {
|
|
|
11
11
|
BatchFinalized = "batch_finalized",
|
|
12
12
|
BatchFailed = "batch_failed",
|
|
13
13
|
TreeSigningStarted = "tree_signing_started",
|
|
14
|
-
|
|
14
|
+
TreeNonces = "tree_nonces",
|
|
15
15
|
TreeTx = "tree_tx",
|
|
16
16
|
TreeSignature = "tree_signature"
|
|
17
17
|
}
|
|
@@ -36,10 +36,12 @@ export type TreeSigningStartedEvent = {
|
|
|
36
36
|
cosignersPublicKeys: string[];
|
|
37
37
|
unsignedCommitmentTx: string;
|
|
38
38
|
};
|
|
39
|
-
export type
|
|
40
|
-
type: SettlementEventType.
|
|
39
|
+
export type TreeNoncesEvent = {
|
|
40
|
+
type: SettlementEventType.TreeNonces;
|
|
41
41
|
id: string;
|
|
42
|
-
|
|
42
|
+
topic: string[];
|
|
43
|
+
txid: string;
|
|
44
|
+
nonces: TreeNonces;
|
|
43
45
|
};
|
|
44
46
|
export type BatchStartedEvent = {
|
|
45
47
|
type: SettlementEventType.BatchStarted;
|
|
@@ -62,7 +64,7 @@ export type TreeSignatureEvent = {
|
|
|
62
64
|
txid: string;
|
|
63
65
|
signature: string;
|
|
64
66
|
};
|
|
65
|
-
export type SettlementEvent = BatchFinalizationEvent | BatchFinalizedEvent | BatchFailedEvent | TreeSigningStartedEvent |
|
|
67
|
+
export type SettlementEvent = BatchFinalizationEvent | BatchFinalizedEvent | BatchFailedEvent | TreeSigningStartedEvent | TreeNoncesEvent | BatchStartedEvent | TreeTxEvent | TreeSignatureEvent;
|
|
66
68
|
export interface ScheduledSession {
|
|
67
69
|
duration: bigint;
|
|
68
70
|
fees: FeeInfo;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare class ArkError extends Error {
|
|
2
|
+
readonly code: number;
|
|
3
|
+
readonly message: string;
|
|
4
|
+
readonly name: string;
|
|
5
|
+
readonly metadata?: Record<string, string> | undefined;
|
|
6
|
+
constructor(code: number, message: string, name: string, metadata?: Record<string, string> | undefined);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Try to convert an error to an ArkError class, returning undefined if the error is not an ArkError
|
|
10
|
+
* @param error - The error to parse
|
|
11
|
+
* @returns The parsed ArkError, or undefined if the error is not an ArkError
|
|
12
|
+
*/
|
|
13
|
+
export declare function maybeArkError(error: any): ArkError | undefined;
|
|
@@ -6,12 +6,10 @@ export interface WalletState {
|
|
|
6
6
|
}
|
|
7
7
|
export interface WalletRepository {
|
|
8
8
|
getVtxos(address: string): Promise<ExtendedVirtualCoin[]>;
|
|
9
|
-
saveVtxo(address: string, vtxo: ExtendedVirtualCoin): Promise<void>;
|
|
10
9
|
saveVtxos(address: string, vtxos: ExtendedVirtualCoin[]): Promise<void>;
|
|
11
10
|
removeVtxo(address: string, vtxoId: string): Promise<void>;
|
|
12
11
|
clearVtxos(address: string): Promise<void>;
|
|
13
12
|
getTransactionHistory(address: string): Promise<ArkTransaction[]>;
|
|
14
|
-
saveTransaction(address: string, tx: ArkTransaction): Promise<void>;
|
|
15
13
|
saveTransactions(address: string, txs: ArkTransaction[]): Promise<void>;
|
|
16
14
|
clearTransactions(address: string): Promise<void>;
|
|
17
15
|
getWalletState(): Promise<WalletState | null>;
|
|
@@ -22,12 +20,10 @@ export declare class WalletRepositoryImpl implements WalletRepository {
|
|
|
22
20
|
private cache;
|
|
23
21
|
constructor(storage: StorageAdapter);
|
|
24
22
|
getVtxos(address: string): Promise<ExtendedVirtualCoin[]>;
|
|
25
|
-
saveVtxo(address: string, vtxo: ExtendedVirtualCoin): Promise<void>;
|
|
26
23
|
saveVtxos(address: string, vtxos: ExtendedVirtualCoin[]): Promise<void>;
|
|
27
24
|
removeVtxo(address: string, vtxoId: string): Promise<void>;
|
|
28
25
|
clearVtxos(address: string): Promise<void>;
|
|
29
26
|
getTransactionHistory(address: string): Promise<ArkTransaction[]>;
|
|
30
|
-
saveTransaction(address: string, tx: ArkTransaction): Promise<void>;
|
|
31
27
|
saveTransactions(address: string, txs: ArkTransaction[]): Promise<void>;
|
|
32
28
|
clearTransactions(address: string): Promise<void>;
|
|
33
29
|
getWalletState(): Promise<WalletState | null>;
|
|
@@ -2,13 +2,16 @@ import * as musig2 from "../musig2";
|
|
|
2
2
|
import { TxTree } from "./txTree";
|
|
3
3
|
export declare const ErrMissingVtxoGraph: Error;
|
|
4
4
|
export declare const ErrMissingAggregateKey: Error;
|
|
5
|
-
export type
|
|
5
|
+
export type Musig2PublicNonce = Pick<musig2.Nonces, "pubNonce">;
|
|
6
|
+
export type TreeNonces = Map<string, Musig2PublicNonce>;
|
|
6
7
|
export type TreePartialSigs = Map<string, musig2.PartialSig>;
|
|
7
8
|
export interface SignerSession {
|
|
8
9
|
getPublicKey(): Promise<Uint8Array>;
|
|
9
10
|
init(tree: TxTree, scriptRoot: Uint8Array, rootInputAmount: bigint): Promise<void>;
|
|
10
11
|
getNonces(): Promise<TreeNonces>;
|
|
11
|
-
|
|
12
|
+
aggregatedNonces(txid: string, noncesByPubkey: TreeNonces): Promise<{
|
|
13
|
+
hasAllNonces: boolean;
|
|
14
|
+
}>;
|
|
12
15
|
sign(): Promise<TreePartialSigs>;
|
|
13
16
|
}
|
|
14
17
|
export declare class TreeSignerSession implements SignerSession {
|
|
@@ -24,7 +27,9 @@ export declare class TreeSignerSession implements SignerSession {
|
|
|
24
27
|
init(tree: TxTree, scriptRoot: Uint8Array, rootInputAmount: bigint): Promise<void>;
|
|
25
28
|
getPublicKey(): Promise<Uint8Array>;
|
|
26
29
|
getNonces(): Promise<TreeNonces>;
|
|
27
|
-
|
|
30
|
+
aggregatedNonces(txid: string, noncesByPubkey: TreeNonces): Promise<{
|
|
31
|
+
hasAllNonces: boolean;
|
|
32
|
+
}>;
|
|
28
33
|
sign(): Promise<TreePartialSigs>;
|
|
29
34
|
private generateNonces;
|
|
30
35
|
private signPartial;
|
|
@@ -11,9 +11,9 @@ export declare enum ArkPsbtFieldKey {
|
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
13
|
* ArkPsbtFieldKeyType is the type of the ark psbt field key.
|
|
14
|
-
* Every ark psbt field has key type
|
|
14
|
+
* Every ark psbt field has key type 222.
|
|
15
15
|
*/
|
|
16
|
-
export declare const ArkPsbtFieldKeyType =
|
|
16
|
+
export declare const ArkPsbtFieldKeyType = 222;
|
|
17
17
|
/**
|
|
18
18
|
* ArkPsbtFieldCoder is the coder for the ark psbt fields.
|
|
19
19
|
* each type has its own coder.
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { WalletBalance, VirtualCoin, ArkTransaction, IWallet } from "..";
|
|
1
|
+
import { WalletBalance, VirtualCoin, ArkTransaction, IWallet, Coin } from "..";
|
|
2
|
+
import { ExtendedVirtualCoin } from "../..";
|
|
2
3
|
import { SettlementEvent } from "../../providers/ark";
|
|
3
4
|
/**
|
|
4
5
|
* Response is the namespace that contains the response types for the service worker.
|
|
5
6
|
*/
|
|
6
7
|
export declare namespace Response {
|
|
7
|
-
type Type = "WALLET_INITIALIZED" | "WALLET_RELOADED" | "SETTLE_EVENT" | "SETTLE_SUCCESS" | "ADDRESS" | "BOARDING_ADDRESS" | "BALANCE" | "VTXOS" | "VIRTUAL_COINS" | "BOARDING_UTXOS" | "SEND_BITCOIN_SUCCESS" | "TRANSACTION_HISTORY" | "WALLET_STATUS" | "ERROR" | "CLEAR_RESPONSE";
|
|
8
|
+
type Type = "WALLET_INITIALIZED" | "WALLET_RELOADED" | "SETTLE_EVENT" | "SETTLE_SUCCESS" | "ADDRESS" | "BOARDING_ADDRESS" | "BALANCE" | "VTXOS" | "VIRTUAL_COINS" | "BOARDING_UTXOS" | "SEND_BITCOIN_SUCCESS" | "TRANSACTION_HISTORY" | "WALLET_STATUS" | "ERROR" | "CLEAR_RESPONSE" | "VTXO_UPDATE" | "UTXO_UPDATE";
|
|
8
9
|
interface Base {
|
|
9
10
|
type: Type;
|
|
10
11
|
success: boolean;
|
|
@@ -106,4 +107,17 @@ export declare namespace Response {
|
|
|
106
107
|
}
|
|
107
108
|
function isWalletReloaded(response: Base): response is WalletReloaded;
|
|
108
109
|
function walletReloaded(id: string, success: boolean): WalletReloaded;
|
|
110
|
+
interface VtxoUpdate extends Base {
|
|
111
|
+
type: "VTXO_UPDATE";
|
|
112
|
+
spentVtxos: ExtendedVirtualCoin[];
|
|
113
|
+
newVtxos: ExtendedVirtualCoin[];
|
|
114
|
+
}
|
|
115
|
+
function isVtxoUpdate(response: Base): response is VtxoUpdate;
|
|
116
|
+
function vtxoUpdate(newVtxos: ExtendedVirtualCoin[], spentVtxos: ExtendedVirtualCoin[]): VtxoUpdate;
|
|
117
|
+
interface UtxoUpdate extends Base {
|
|
118
|
+
type: "UTXO_UPDATE";
|
|
119
|
+
coins: Coin[];
|
|
120
|
+
}
|
|
121
|
+
function isUtxoUpdate(response: Base): response is UtxoUpdate;
|
|
122
|
+
function utxoUpdate(coins: Coin[]): UtxoUpdate;
|
|
109
123
|
}
|
|
@@ -91,7 +91,7 @@ export declare class Wallet implements IWallet {
|
|
|
91
91
|
notifyIncomingFunds(eventCallback: (coins: IncomingFunds) => void): Promise<() => void>;
|
|
92
92
|
private handleBatchStartedEvent;
|
|
93
93
|
private handleSettlementSigningEvent;
|
|
94
|
-
private
|
|
94
|
+
private handleSettlementTreeNoncesEvent;
|
|
95
95
|
private handleSettlementFinalizationEvent;
|
|
96
96
|
private makeRegisterIntentSignature;
|
|
97
97
|
private makeDeleteIntentSignature;
|