@arkade-os/sdk 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/README.md +312 -0
  2. package/dist/cjs/arknote/index.js +86 -0
  3. package/dist/cjs/forfeit.js +38 -0
  4. package/dist/cjs/identity/inMemoryKey.js +40 -0
  5. package/dist/cjs/identity/index.js +2 -0
  6. package/dist/cjs/index.js +48 -0
  7. package/dist/cjs/musig2/index.js +10 -0
  8. package/dist/cjs/musig2/keys.js +57 -0
  9. package/dist/cjs/musig2/nonces.js +44 -0
  10. package/dist/cjs/musig2/sign.js +102 -0
  11. package/dist/cjs/networks.js +26 -0
  12. package/dist/cjs/package.json +3 -0
  13. package/dist/cjs/providers/ark.js +530 -0
  14. package/dist/cjs/providers/onchain.js +61 -0
  15. package/dist/cjs/script/address.js +45 -0
  16. package/dist/cjs/script/base.js +51 -0
  17. package/dist/cjs/script/default.js +40 -0
  18. package/dist/cjs/script/tapscript.js +528 -0
  19. package/dist/cjs/script/vhtlc.js +84 -0
  20. package/dist/cjs/tree/signingSession.js +238 -0
  21. package/dist/cjs/tree/validation.js +184 -0
  22. package/dist/cjs/tree/vtxoTree.js +197 -0
  23. package/dist/cjs/utils/bip21.js +114 -0
  24. package/dist/cjs/utils/coinselect.js +73 -0
  25. package/dist/cjs/utils/psbt.js +124 -0
  26. package/dist/cjs/utils/transactionHistory.js +148 -0
  27. package/dist/cjs/utils/txSizeEstimator.js +95 -0
  28. package/dist/cjs/wallet/index.js +8 -0
  29. package/dist/cjs/wallet/serviceWorker/db/vtxo/idb.js +153 -0
  30. package/dist/cjs/wallet/serviceWorker/db/vtxo/index.js +2 -0
  31. package/dist/cjs/wallet/serviceWorker/request.js +75 -0
  32. package/dist/cjs/wallet/serviceWorker/response.js +187 -0
  33. package/dist/cjs/wallet/serviceWorker/wallet.js +332 -0
  34. package/dist/cjs/wallet/serviceWorker/worker.js +452 -0
  35. package/dist/cjs/wallet/wallet.js +720 -0
  36. package/dist/esm/arknote/index.js +81 -0
  37. package/dist/esm/forfeit.js +35 -0
  38. package/dist/esm/identity/inMemoryKey.js +36 -0
  39. package/dist/esm/identity/index.js +1 -0
  40. package/dist/esm/index.js +39 -0
  41. package/dist/esm/musig2/index.js +3 -0
  42. package/dist/esm/musig2/keys.js +21 -0
  43. package/dist/esm/musig2/nonces.js +8 -0
  44. package/dist/esm/musig2/sign.js +63 -0
  45. package/dist/esm/networks.js +22 -0
  46. package/dist/esm/package.json +3 -0
  47. package/dist/esm/providers/ark.js +526 -0
  48. package/dist/esm/providers/onchain.js +57 -0
  49. package/dist/esm/script/address.js +41 -0
  50. package/dist/esm/script/base.js +46 -0
  51. package/dist/esm/script/default.js +37 -0
  52. package/dist/esm/script/tapscript.js +491 -0
  53. package/dist/esm/script/vhtlc.js +81 -0
  54. package/dist/esm/tree/signingSession.js +200 -0
  55. package/dist/esm/tree/validation.js +179 -0
  56. package/dist/esm/tree/vtxoTree.js +157 -0
  57. package/dist/esm/utils/bip21.js +110 -0
  58. package/dist/esm/utils/coinselect.js +69 -0
  59. package/dist/esm/utils/psbt.js +118 -0
  60. package/dist/esm/utils/transactionHistory.js +145 -0
  61. package/dist/esm/utils/txSizeEstimator.js +91 -0
  62. package/dist/esm/wallet/index.js +5 -0
  63. package/dist/esm/wallet/serviceWorker/db/vtxo/idb.js +149 -0
  64. package/dist/esm/wallet/serviceWorker/db/vtxo/index.js +1 -0
  65. package/dist/esm/wallet/serviceWorker/request.js +72 -0
  66. package/dist/esm/wallet/serviceWorker/response.js +184 -0
  67. package/dist/esm/wallet/serviceWorker/wallet.js +328 -0
  68. package/dist/esm/wallet/serviceWorker/worker.js +448 -0
  69. package/dist/esm/wallet/wallet.js +716 -0
  70. package/dist/types/arknote/index.d.ts +17 -0
  71. package/dist/types/forfeit.d.ts +15 -0
  72. package/dist/types/identity/inMemoryKey.d.ts +12 -0
  73. package/dist/types/identity/index.d.ts +7 -0
  74. package/dist/types/index.d.ts +22 -0
  75. package/dist/types/musig2/index.d.ts +4 -0
  76. package/dist/types/musig2/keys.d.ts +9 -0
  77. package/dist/types/musig2/nonces.d.ts +13 -0
  78. package/dist/types/musig2/sign.d.ts +27 -0
  79. package/dist/types/networks.d.ts +16 -0
  80. package/dist/types/providers/ark.d.ts +126 -0
  81. package/dist/types/providers/onchain.d.ts +36 -0
  82. package/dist/types/script/address.d.ts +10 -0
  83. package/dist/types/script/base.d.ts +26 -0
  84. package/dist/types/script/default.d.ts +19 -0
  85. package/dist/types/script/tapscript.d.ts +94 -0
  86. package/dist/types/script/vhtlc.d.ts +31 -0
  87. package/dist/types/tree/signingSession.d.ts +32 -0
  88. package/dist/types/tree/validation.d.ts +22 -0
  89. package/dist/types/tree/vtxoTree.d.ts +32 -0
  90. package/dist/types/utils/bip21.d.ts +21 -0
  91. package/dist/types/utils/coinselect.d.ts +21 -0
  92. package/dist/types/utils/psbt.d.ts +11 -0
  93. package/dist/types/utils/transactionHistory.d.ts +2 -0
  94. package/dist/types/utils/txSizeEstimator.d.ts +27 -0
  95. package/dist/types/wallet/index.d.ts +122 -0
  96. package/dist/types/wallet/serviceWorker/db/vtxo/idb.d.ts +18 -0
  97. package/dist/types/wallet/serviceWorker/db/vtxo/index.d.ts +12 -0
  98. package/dist/types/wallet/serviceWorker/request.d.ts +68 -0
  99. package/dist/types/wallet/serviceWorker/response.d.ts +107 -0
  100. package/dist/types/wallet/serviceWorker/wallet.d.ts +23 -0
  101. package/dist/types/wallet/serviceWorker/worker.d.ts +26 -0
  102. package/dist/types/wallet/wallet.d.ts +42 -0
  103. package/package.json +88 -0
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.PartialSig = exports.PartialSignatureError = void 0;
37
+ exports.sign = sign;
38
+ const musig = __importStar(require("@scure/btc-signer/musig2"));
39
+ const utils_1 = require("@noble/curves/abstract/utils");
40
+ const secp256k1_1 = require("@noble/secp256k1");
41
+ const keys_1 = require("./keys");
42
+ const secp256k1_2 = require("@noble/curves/secp256k1");
43
+ // Add this error type for decode failures
44
+ class PartialSignatureError extends Error {
45
+ constructor(message) {
46
+ super(message);
47
+ this.name = "PartialSignatureError";
48
+ }
49
+ }
50
+ exports.PartialSignatureError = PartialSignatureError;
51
+ // Implement a concrete class for PartialSignature
52
+ class PartialSig {
53
+ constructor(s, R) {
54
+ this.s = s;
55
+ this.R = R;
56
+ if (s.length !== 32) {
57
+ throw new PartialSignatureError("Invalid s length");
58
+ }
59
+ if (R.length !== 33) {
60
+ throw new PartialSignatureError("Invalid R length");
61
+ }
62
+ }
63
+ /**
64
+ * Encodes the partial signature into bytes
65
+ * Returns a 32-byte array containing just the s value
66
+ */
67
+ encode() {
68
+ // Return copy of s bytes
69
+ return new Uint8Array(this.s);
70
+ }
71
+ /**
72
+ * Decodes a partial signature from bytes
73
+ * @param bytes - 32-byte array containing s value
74
+ */
75
+ static decode(bytes) {
76
+ if (bytes.length !== 32) {
77
+ throw new PartialSignatureError("Invalid partial signature length");
78
+ }
79
+ // Verify s is less than curve order
80
+ const s = (0, utils_1.bytesToNumberBE)(bytes);
81
+ if (s >= secp256k1_1.CURVE.n) {
82
+ throw new PartialSignatureError("s value overflows curve order");
83
+ }
84
+ // For decode we don't have R, so we'll need to compute it later
85
+ const R = new Uint8Array(33); // Zero R for now
86
+ return new PartialSig(bytes, R);
87
+ }
88
+ }
89
+ exports.PartialSig = PartialSig;
90
+ /**
91
+ * Generates a MuSig2 partial signature
92
+ */
93
+ function sign(secNonce, privateKey, combinedNonce, publicKeys, message, options) {
94
+ let tweakBytes;
95
+ if (options?.taprootTweak !== undefined) {
96
+ const { preTweakedKey } = (0, keys_1.aggregateKeys)(options?.sortKeys ? musig.sortKeys(publicKeys) : publicKeys, true);
97
+ tweakBytes = secp256k1_2.schnorr.utils.taggedHash("TapTweak", preTweakedKey.subarray(1), options.taprootTweak);
98
+ }
99
+ const session = new musig.Session(combinedNonce, options?.sortKeys ? musig.sortKeys(publicKeys) : publicKeys, message, tweakBytes ? [tweakBytes] : undefined, tweakBytes ? [true] : undefined);
100
+ const partialSig = session.sign(secNonce, privateKey);
101
+ return PartialSig.decode(partialSig);
102
+ }
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.networks = exports.getNetwork = void 0;
4
+ const btc_signer_1 = require("@scure/btc-signer");
5
+ const getNetwork = (network) => {
6
+ return exports.networks[network];
7
+ };
8
+ exports.getNetwork = getNetwork;
9
+ exports.networks = {
10
+ bitcoin: withArkPrefix(btc_signer_1.NETWORK, "ark"),
11
+ testnet: withArkPrefix(btc_signer_1.TEST_NETWORK, "tark"),
12
+ signet: withArkPrefix(btc_signer_1.TEST_NETWORK, "tark"),
13
+ mutinynet: withArkPrefix(btc_signer_1.TEST_NETWORK, "tark"),
14
+ regtest: withArkPrefix({
15
+ ...btc_signer_1.TEST_NETWORK,
16
+ bech32: "bcrt",
17
+ pubKeyHash: 0x6f,
18
+ scriptHash: 0xc4,
19
+ }, "tark"),
20
+ };
21
+ function withArkPrefix(network, prefix) {
22
+ return {
23
+ ...network,
24
+ hrp: prefix,
25
+ };
26
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
@@ -0,0 +1,530 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RestArkProvider = exports.SettlementEventType = void 0;
4
+ const vtxoTree_1 = require("../tree/vtxoTree");
5
+ const base_1 = require("@scure/base");
6
+ var SettlementEventType;
7
+ (function (SettlementEventType) {
8
+ SettlementEventType["Finalization"] = "finalization";
9
+ SettlementEventType["Finalized"] = "finalized";
10
+ SettlementEventType["Failed"] = "failed";
11
+ SettlementEventType["SigningStart"] = "signing_start";
12
+ SettlementEventType["SigningNoncesGenerated"] = "signing_nonces_generated";
13
+ })(SettlementEventType || (exports.SettlementEventType = SettlementEventType = {}));
14
+ class RestArkProvider {
15
+ constructor(serverUrl) {
16
+ this.serverUrl = serverUrl;
17
+ }
18
+ async getInfo() {
19
+ const url = `${this.serverUrl}/v1/info`;
20
+ const response = await fetch(url);
21
+ if (!response.ok) {
22
+ throw new Error(`Failed to get server info: ${response.statusText}`);
23
+ }
24
+ const fromServer = await response.json();
25
+ return {
26
+ ...fromServer,
27
+ unilateralExitDelay: BigInt(fromServer.unilateralExitDelay ?? 0),
28
+ batchExpiry: BigInt(fromServer.vtxoTreeExpiry ?? 0),
29
+ };
30
+ }
31
+ async getVirtualCoins(address) {
32
+ const url = `${this.serverUrl}/v1/vtxos/${address}`;
33
+ const response = await fetch(url);
34
+ if (!response.ok) {
35
+ throw new Error(`Failed to fetch VTXOs: ${response.statusText}`);
36
+ }
37
+ const data = await response.json();
38
+ return {
39
+ spendableVtxos: [...(data.spendableVtxos || [])].map(convertVtxo),
40
+ spentVtxos: [...(data.spentVtxos || [])].map(convertVtxo),
41
+ };
42
+ }
43
+ async submitVirtualTx(psbtBase64) {
44
+ const url = `${this.serverUrl}/v1/redeem-tx`;
45
+ const response = await fetch(url, {
46
+ method: "POST",
47
+ headers: {
48
+ "Content-Type": "application/json",
49
+ },
50
+ body: JSON.stringify({
51
+ redeem_tx: psbtBase64,
52
+ }),
53
+ });
54
+ if (!response.ok) {
55
+ const errorText = await response.text();
56
+ try {
57
+ const grpcError = JSON.parse(errorText);
58
+ // gRPC errors usually have a message and code field
59
+ throw new Error(`Failed to submit virtual transaction: ${grpcError.message || grpcError.error || errorText}`);
60
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
61
+ }
62
+ catch (_) {
63
+ // If JSON parse fails, use the raw error text
64
+ throw new Error(`Failed to submit virtual transaction: ${errorText}`);
65
+ }
66
+ }
67
+ const data = await response.json();
68
+ // Handle both current and future response formats
69
+ return data.txid || data.signedRedeemTx;
70
+ }
71
+ async subscribeToEvents(callback) {
72
+ const url = `${this.serverUrl}/v1/events`;
73
+ let abortController = new AbortController();
74
+ (async () => {
75
+ while (!abortController.signal.aborted) {
76
+ try {
77
+ const response = await fetch(url, {
78
+ headers: {
79
+ Accept: "application/json",
80
+ },
81
+ signal: abortController.signal,
82
+ });
83
+ if (!response.ok) {
84
+ throw new Error(`Unexpected status ${response.status} when fetching event stream`);
85
+ }
86
+ if (!response.body) {
87
+ throw new Error("Response body is null");
88
+ }
89
+ const reader = response.body.getReader();
90
+ const decoder = new TextDecoder();
91
+ let buffer = "";
92
+ while (!abortController.signal.aborted) {
93
+ const { done, value } = await reader.read();
94
+ if (done)
95
+ break;
96
+ // Append new data to buffer and split by newlines
97
+ buffer += decoder.decode(value, { stream: true });
98
+ const lines = buffer.split("\n");
99
+ // Process all complete lines
100
+ for (let i = 0; i < lines.length - 1; i++) {
101
+ const line = lines[i].trim();
102
+ if (!line)
103
+ continue;
104
+ try {
105
+ const data = JSON.parse(line);
106
+ callback(data);
107
+ }
108
+ catch (err) {
109
+ console.error("Failed to parse event:", err);
110
+ }
111
+ }
112
+ // Keep the last partial line in the buffer
113
+ buffer = lines[lines.length - 1];
114
+ }
115
+ }
116
+ catch (error) {
117
+ if (!abortController.signal.aborted) {
118
+ console.error("Event stream error:", error);
119
+ }
120
+ }
121
+ }
122
+ })();
123
+ // Return unsubscribe function
124
+ return () => {
125
+ abortController.abort();
126
+ // Create a new controller for potential future subscriptions
127
+ abortController = new AbortController();
128
+ };
129
+ }
130
+ async registerInputsForNextRound(inputs) {
131
+ const url = `${this.serverUrl}/v1/round/registerInputs`;
132
+ const vtxoInputs = [];
133
+ const noteInputs = [];
134
+ for (const input of inputs) {
135
+ if (typeof input === "string") {
136
+ noteInputs.push(input);
137
+ }
138
+ else {
139
+ vtxoInputs.push({
140
+ outpoint: {
141
+ txid: input.outpoint.txid,
142
+ vout: input.outpoint.vout,
143
+ },
144
+ tapscripts: {
145
+ scripts: input.tapscripts,
146
+ },
147
+ });
148
+ }
149
+ }
150
+ const response = await fetch(url, {
151
+ method: "POST",
152
+ headers: {
153
+ "Content-Type": "application/json",
154
+ },
155
+ body: JSON.stringify({
156
+ inputs: vtxoInputs,
157
+ notes: noteInputs,
158
+ }),
159
+ });
160
+ if (!response.ok) {
161
+ const errorText = await response.text();
162
+ throw new Error(`Failed to register inputs: ${errorText}`);
163
+ }
164
+ const data = await response.json();
165
+ return { requestId: data.requestId };
166
+ }
167
+ async registerOutputsForNextRound(requestId, outputs, cosignersPublicKeys, signingAll = false) {
168
+ const url = `${this.serverUrl}/v1/round/registerOutputs`;
169
+ const response = await fetch(url, {
170
+ method: "POST",
171
+ headers: {
172
+ "Content-Type": "application/json",
173
+ },
174
+ body: JSON.stringify({
175
+ requestId,
176
+ outputs: outputs.map((output) => ({
177
+ address: output.address,
178
+ amount: output.amount.toString(10),
179
+ })),
180
+ musig2: {
181
+ cosignersPublicKeys,
182
+ signingAll,
183
+ },
184
+ }),
185
+ });
186
+ if (!response.ok) {
187
+ const errorText = await response.text();
188
+ throw new Error(`Failed to register outputs: ${errorText}`);
189
+ }
190
+ }
191
+ async submitTreeNonces(settlementID, pubkey, nonces) {
192
+ const url = `${this.serverUrl}/v1/round/tree/submitNonces`;
193
+ const response = await fetch(url, {
194
+ method: "POST",
195
+ headers: {
196
+ "Content-Type": "application/json",
197
+ },
198
+ body: JSON.stringify({
199
+ roundId: settlementID,
200
+ pubkey,
201
+ treeNonces: encodeNoncesMatrix(nonces),
202
+ }),
203
+ });
204
+ if (!response.ok) {
205
+ const errorText = await response.text();
206
+ throw new Error(`Failed to submit tree nonces: ${errorText}`);
207
+ }
208
+ }
209
+ async submitTreeSignatures(settlementID, pubkey, signatures) {
210
+ const url = `${this.serverUrl}/v1/round/tree/submitSignatures`;
211
+ const response = await fetch(url, {
212
+ method: "POST",
213
+ headers: {
214
+ "Content-Type": "application/json",
215
+ },
216
+ body: JSON.stringify({
217
+ roundId: settlementID,
218
+ pubkey,
219
+ treeSignatures: encodeSignaturesMatrix(signatures),
220
+ }),
221
+ });
222
+ if (!response.ok) {
223
+ const errorText = await response.text();
224
+ throw new Error(`Failed to submit tree signatures: ${errorText}`);
225
+ }
226
+ }
227
+ async submitSignedForfeitTxs(signedForfeitTxs, signedRoundTx) {
228
+ const url = `${this.serverUrl}/v1/round/submitForfeitTxs`;
229
+ const response = await fetch(url, {
230
+ method: "POST",
231
+ headers: {
232
+ "Content-Type": "application/json",
233
+ },
234
+ body: JSON.stringify({
235
+ signedForfeitTxs: signedForfeitTxs,
236
+ signedRoundTx: signedRoundTx,
237
+ }),
238
+ });
239
+ if (!response.ok) {
240
+ throw new Error(`Failed to submit forfeit transactions: ${response.statusText}`);
241
+ }
242
+ }
243
+ async ping(requestId) {
244
+ const url = `${this.serverUrl}/v1/round/ping/${requestId}`;
245
+ const response = await fetch(url);
246
+ if (!response.ok) {
247
+ throw new Error(`Ping failed: ${response.statusText}`);
248
+ }
249
+ }
250
+ async *getEventStream(signal) {
251
+ const url = `${this.serverUrl}/v1/events`;
252
+ while (!signal?.aborted) {
253
+ try {
254
+ const response = await fetch(url, {
255
+ headers: {
256
+ Accept: "application/json",
257
+ },
258
+ signal,
259
+ });
260
+ if (!response.ok) {
261
+ throw new Error(`Unexpected status ${response.status} when fetching event stream`);
262
+ }
263
+ if (!response.body) {
264
+ throw new Error("Response body is null");
265
+ }
266
+ const reader = response.body.getReader();
267
+ const decoder = new TextDecoder();
268
+ let buffer = "";
269
+ while (!signal?.aborted) {
270
+ const { done, value } = await reader.read();
271
+ if (done) {
272
+ break;
273
+ }
274
+ // Append new data to buffer and split by newlines
275
+ buffer += decoder.decode(value, { stream: true });
276
+ const lines = buffer.split("\n");
277
+ // Process all complete lines
278
+ for (let i = 0; i < lines.length - 1; i++) {
279
+ const line = lines[i].trim();
280
+ if (!line)
281
+ continue;
282
+ try {
283
+ const data = JSON.parse(line);
284
+ const event = this.parseSettlementEvent(data.result);
285
+ if (event) {
286
+ yield event;
287
+ }
288
+ }
289
+ catch (err) {
290
+ console.error("Failed to parse event:", err);
291
+ throw err;
292
+ }
293
+ }
294
+ // Keep the last partial line in the buffer
295
+ buffer = lines[lines.length - 1];
296
+ }
297
+ }
298
+ catch (error) {
299
+ if (error instanceof Error && error.name === "AbortError") {
300
+ break;
301
+ }
302
+ console.error("Event stream error:", error);
303
+ throw error;
304
+ }
305
+ }
306
+ }
307
+ async *subscribeForAddress(address, abortSignal) {
308
+ const url = `${this.serverUrl}/v1/vtxos/${address}/subscribe`;
309
+ while (!abortSignal.aborted) {
310
+ try {
311
+ const response = await fetch(url, {
312
+ headers: {
313
+ Accept: "application/json",
314
+ },
315
+ });
316
+ if (!response.ok) {
317
+ throw new Error(`Unexpected status ${response.status} when subscribing to address updates`);
318
+ }
319
+ if (!response.body) {
320
+ throw new Error("Response body is null");
321
+ }
322
+ const reader = response.body.getReader();
323
+ const decoder = new TextDecoder();
324
+ let buffer = "";
325
+ while (!abortSignal.aborted) {
326
+ const { done, value } = await reader.read();
327
+ if (done) {
328
+ break;
329
+ }
330
+ buffer += decoder.decode(value, { stream: true });
331
+ const lines = buffer.split("\n");
332
+ for (let i = 0; i < lines.length - 1; i++) {
333
+ const line = lines[i].trim();
334
+ if (!line)
335
+ continue;
336
+ try {
337
+ const data = JSON.parse(line);
338
+ if ("result" in data) {
339
+ yield {
340
+ newVtxos: (data.result.newVtxos || []).map(convertVtxo),
341
+ spentVtxos: (data.result.spentVtxos || []).map(convertVtxo),
342
+ };
343
+ }
344
+ }
345
+ catch (err) {
346
+ console.error("Failed to parse address update:", err);
347
+ throw err;
348
+ }
349
+ }
350
+ buffer = lines[lines.length - 1];
351
+ }
352
+ }
353
+ catch (error) {
354
+ console.error("Address subscription error:", error);
355
+ throw error;
356
+ }
357
+ }
358
+ }
359
+ toConnectorsIndex(connectorsIndex) {
360
+ return new Map(Object.entries(connectorsIndex).map(([key, value]) => [
361
+ key,
362
+ { txid: value.txid, vout: value.vout },
363
+ ]));
364
+ }
365
+ toTxTree(t) {
366
+ // collect the parent txids to determine later if a node is a leaf
367
+ const parentTxids = new Set();
368
+ t.levels.forEach((level) => level.nodes.forEach((node) => {
369
+ if (node.parentTxid) {
370
+ parentTxids.add(node.parentTxid);
371
+ }
372
+ }));
373
+ return new vtxoTree_1.TxTree(t.levels.map((level) => level.nodes.map((node) => ({
374
+ txid: node.txid,
375
+ tx: node.tx,
376
+ parentTxid: node.parentTxid,
377
+ leaf: !parentTxids.has(node.txid),
378
+ }))));
379
+ }
380
+ parseSettlementEvent(data) {
381
+ // Check for Finalization event
382
+ if (data.roundFinalization) {
383
+ return {
384
+ type: SettlementEventType.Finalization,
385
+ id: data.roundFinalization.id,
386
+ roundTx: data.roundFinalization.roundTx,
387
+ vtxoTree: this.toTxTree(data.roundFinalization.vtxoTree),
388
+ connectors: this.toTxTree(data.roundFinalization.connectors),
389
+ connectorsIndex: this.toConnectorsIndex(data.roundFinalization.connectorsIndex),
390
+ // divide by 1000 to convert to sat/vbyte
391
+ minRelayFeeRate: BigInt(data.roundFinalization.minRelayFeeRate) /
392
+ BigInt(1000),
393
+ };
394
+ }
395
+ // Check for Finalized event
396
+ if (data.roundFinalized) {
397
+ return {
398
+ type: SettlementEventType.Finalized,
399
+ id: data.roundFinalized.id,
400
+ roundTxid: data.roundFinalized.roundTxid,
401
+ };
402
+ }
403
+ // Check for Failed event
404
+ if (data.roundFailed) {
405
+ return {
406
+ type: SettlementEventType.Failed,
407
+ id: data.roundFailed.id,
408
+ reason: data.roundFailed.reason,
409
+ };
410
+ }
411
+ // Check for Signing event
412
+ if (data.roundSigning) {
413
+ return {
414
+ type: SettlementEventType.SigningStart,
415
+ id: data.roundSigning.id,
416
+ cosignersPublicKeys: data.roundSigning.cosignersPubkeys,
417
+ unsignedVtxoTree: this.toTxTree(data.roundSigning.unsignedVtxoTree),
418
+ unsignedSettlementTx: data.roundSigning.unsignedRoundTx,
419
+ };
420
+ }
421
+ // Check for SigningNoncesGenerated event
422
+ if (data.roundSigningNoncesGenerated) {
423
+ return {
424
+ type: SettlementEventType.SigningNoncesGenerated,
425
+ id: data.roundSigningNoncesGenerated.id,
426
+ treeNonces: decodeNoncesMatrix(base_1.hex.decode(data.roundSigningNoncesGenerated.treeNonces)),
427
+ };
428
+ }
429
+ console.warn("Unknown event structure:", data);
430
+ return null;
431
+ }
432
+ }
433
+ exports.RestArkProvider = RestArkProvider;
434
+ function encodeMatrix(matrix) {
435
+ // Calculate total size needed:
436
+ // 4 bytes for number of rows
437
+ // For each row: 4 bytes for length + sum of encoded cell lengths + isNil byte * cell count
438
+ let totalSize = 4;
439
+ for (const row of matrix) {
440
+ totalSize += 4; // row length
441
+ for (const cell of row) {
442
+ totalSize += 1;
443
+ totalSize += cell.length;
444
+ }
445
+ }
446
+ // Create buffer and DataView
447
+ const buffer = new ArrayBuffer(totalSize);
448
+ const view = new DataView(buffer);
449
+ let offset = 0;
450
+ // Write number of rows
451
+ view.setUint32(offset, matrix.length, true); // true for little-endian
452
+ offset += 4;
453
+ // Write each row
454
+ for (const row of matrix) {
455
+ // Write row length
456
+ view.setUint32(offset, row.length, true);
457
+ offset += 4;
458
+ // Write each cell
459
+ for (const cell of row) {
460
+ const notNil = cell.length > 0;
461
+ view.setInt8(offset, notNil ? 1 : 0);
462
+ offset += 1;
463
+ if (!notNil) {
464
+ continue;
465
+ }
466
+ new Uint8Array(buffer).set(cell, offset);
467
+ offset += cell.length;
468
+ }
469
+ }
470
+ return new Uint8Array(buffer);
471
+ }
472
+ function decodeMatrix(matrix, cellLength) {
473
+ // Create DataView to read the buffer
474
+ const view = new DataView(matrix.buffer, matrix.byteOffset, matrix.byteLength);
475
+ let offset = 0;
476
+ // Read number of rows
477
+ const numRows = view.getUint32(offset, true); // true for little-endian
478
+ offset += 4;
479
+ // Initialize result matrix
480
+ const result = [];
481
+ // Read each row
482
+ for (let i = 0; i < numRows; i++) {
483
+ // Read row length
484
+ const rowLength = view.getUint32(offset, true);
485
+ offset += 4;
486
+ const row = [];
487
+ // Read each cell in the row
488
+ for (let j = 0; j < rowLength; j++) {
489
+ const notNil = view.getUint8(offset) === 1;
490
+ offset += 1;
491
+ if (notNil) {
492
+ const cell = new Uint8Array(matrix.buffer, matrix.byteOffset + offset, cellLength);
493
+ row.push(new Uint8Array(cell));
494
+ offset += cellLength;
495
+ }
496
+ else {
497
+ row.push(new Uint8Array());
498
+ }
499
+ }
500
+ result.push(row);
501
+ }
502
+ return result;
503
+ }
504
+ function decodeNoncesMatrix(matrix) {
505
+ const decoded = decodeMatrix(matrix, 66);
506
+ return decoded.map((row) => row.map((nonce) => ({ pubNonce: nonce })));
507
+ }
508
+ function encodeNoncesMatrix(nonces) {
509
+ return base_1.hex.encode(encodeMatrix(nonces.map((row) => row.map((nonce) => (nonce ? nonce.pubNonce : new Uint8Array())))));
510
+ }
511
+ function encodeSignaturesMatrix(signatures) {
512
+ return base_1.hex.encode(encodeMatrix(signatures.map((row) => row.map((s) => (s ? s.encode() : new Uint8Array())))));
513
+ }
514
+ function convertVtxo(vtxo) {
515
+ return {
516
+ txid: vtxo.outpoint.txid,
517
+ vout: vtxo.outpoint.vout,
518
+ value: Number(vtxo.amount),
519
+ status: {
520
+ confirmed: !!vtxo.roundTxid,
521
+ },
522
+ virtualStatus: {
523
+ state: vtxo.isPending ? "pending" : "settled",
524
+ batchTxID: vtxo.roundTxid,
525
+ batchExpiry: vtxo.expireAt ? Number(vtxo.expireAt) : undefined,
526
+ },
527
+ spentBy: vtxo.spentBy,
528
+ createdAt: new Date(vtxo.createdAt * 1000),
529
+ };
530
+ }