@arkade-os/sdk 0.1.3 → 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 -459
- 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 -466
- 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 -26
- 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
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
import { isFetchTimeoutError } from './ark.js';
|
|
2
|
+
export var IndexerTxType;
|
|
3
|
+
(function (IndexerTxType) {
|
|
4
|
+
IndexerTxType[IndexerTxType["INDEXER_TX_TYPE_UNSPECIFIED"] = 0] = "INDEXER_TX_TYPE_UNSPECIFIED";
|
|
5
|
+
IndexerTxType[IndexerTxType["INDEXER_TX_TYPE_RECEIVED"] = 1] = "INDEXER_TX_TYPE_RECEIVED";
|
|
6
|
+
IndexerTxType[IndexerTxType["INDEXER_TX_TYPE_SENT"] = 2] = "INDEXER_TX_TYPE_SENT";
|
|
7
|
+
})(IndexerTxType || (IndexerTxType = {}));
|
|
8
|
+
export var ChainTxType;
|
|
9
|
+
(function (ChainTxType) {
|
|
10
|
+
ChainTxType["UNSPECIFIED"] = "INDEXER_CHAINED_TX_TYPE_UNSPECIFIED";
|
|
11
|
+
ChainTxType["COMMITMENT"] = "INDEXER_CHAINED_TX_TYPE_COMMITMENT";
|
|
12
|
+
ChainTxType["ARK"] = "INDEXER_CHAINED_TX_TYPE_ARK";
|
|
13
|
+
ChainTxType["TREE"] = "INDEXER_CHAINED_TX_TYPE_TREE";
|
|
14
|
+
ChainTxType["CHECKPOINT"] = "INDEXER_CHAINED_TX_TYPE_CHECKPOINT";
|
|
15
|
+
})(ChainTxType || (ChainTxType = {}));
|
|
16
|
+
/**
|
|
17
|
+
* REST-based Indexer provider implementation.
|
|
18
|
+
* @see https://buf.build/arkade-os/arkd/docs/main:ark.v1#ark.v1.IndexerService
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* const provider = new RestIndexerProvider('https://ark.indexer.example.com');
|
|
22
|
+
* const commitmentTx = await provider.getCommitmentTx("6686af8f3be3517880821f62e6c3d749b9d6713736a1d8e229a55daa659446b2");
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export class RestIndexerProvider {
|
|
26
|
+
constructor(serverUrl) {
|
|
27
|
+
this.serverUrl = serverUrl;
|
|
28
|
+
}
|
|
29
|
+
async getVtxoTree(batchOutpoint, opts) {
|
|
30
|
+
let url = `${this.serverUrl}/v1/batch/${batchOutpoint.txid}/${batchOutpoint.vout}/tree`;
|
|
31
|
+
const params = new URLSearchParams();
|
|
32
|
+
if (opts) {
|
|
33
|
+
if (opts.pageIndex !== undefined)
|
|
34
|
+
params.append("page.index", opts.pageIndex.toString());
|
|
35
|
+
if (opts.pageSize !== undefined)
|
|
36
|
+
params.append("page.size", opts.pageSize.toString());
|
|
37
|
+
}
|
|
38
|
+
if (params.toString()) {
|
|
39
|
+
url += "?" + params.toString();
|
|
40
|
+
}
|
|
41
|
+
const res = await fetch(url);
|
|
42
|
+
if (!res.ok) {
|
|
43
|
+
throw new Error(`Failed to fetch vtxo tree: ${res.statusText}`);
|
|
44
|
+
}
|
|
45
|
+
const data = await res.json();
|
|
46
|
+
if (!Response.isVtxoTreeResponse(data)) {
|
|
47
|
+
throw new Error("Invalid vtxo tree data received");
|
|
48
|
+
}
|
|
49
|
+
data.vtxoTree.forEach((tx) => {
|
|
50
|
+
tx.children = Object.fromEntries(Object.entries(tx.children).map(([key, value]) => [
|
|
51
|
+
Number(key),
|
|
52
|
+
value,
|
|
53
|
+
]));
|
|
54
|
+
});
|
|
55
|
+
return data;
|
|
56
|
+
}
|
|
57
|
+
async getVtxoTreeLeaves(batchOutpoint, opts) {
|
|
58
|
+
let url = `${this.serverUrl}/v1/batch/${batchOutpoint.txid}/${batchOutpoint.vout}/tree/leaves`;
|
|
59
|
+
const params = new URLSearchParams();
|
|
60
|
+
if (opts) {
|
|
61
|
+
if (opts.pageIndex !== undefined)
|
|
62
|
+
params.append("page.index", opts.pageIndex.toString());
|
|
63
|
+
if (opts.pageSize !== undefined)
|
|
64
|
+
params.append("page.size", opts.pageSize.toString());
|
|
65
|
+
}
|
|
66
|
+
if (params.toString()) {
|
|
67
|
+
url += "?" + params.toString();
|
|
68
|
+
}
|
|
69
|
+
const res = await fetch(url);
|
|
70
|
+
if (!res.ok) {
|
|
71
|
+
throw new Error(`Failed to fetch vtxo tree leaves: ${res.statusText}`);
|
|
72
|
+
}
|
|
73
|
+
const data = await res.json();
|
|
74
|
+
if (!Response.isVtxoTreeLeavesResponse(data)) {
|
|
75
|
+
throw new Error("Invalid vtxos tree leaves data received");
|
|
76
|
+
}
|
|
77
|
+
return data;
|
|
78
|
+
}
|
|
79
|
+
async getBatchSweepTransactions(batchOutpoint) {
|
|
80
|
+
const url = `${this.serverUrl}/v1/batch/${batchOutpoint.txid}/${batchOutpoint.vout}/sweepTxs`;
|
|
81
|
+
const res = await fetch(url);
|
|
82
|
+
if (!res.ok) {
|
|
83
|
+
throw new Error(`Failed to fetch batch sweep transactions: ${res.statusText}`);
|
|
84
|
+
}
|
|
85
|
+
const data = await res.json();
|
|
86
|
+
if (!Response.isBatchSweepTransactionsResponse(data)) {
|
|
87
|
+
throw new Error("Invalid batch sweep transactions data received");
|
|
88
|
+
}
|
|
89
|
+
return data;
|
|
90
|
+
}
|
|
91
|
+
async getCommitmentTx(txid) {
|
|
92
|
+
const url = `${this.serverUrl}/v1/commitmentTx/${txid}`;
|
|
93
|
+
const res = await fetch(url);
|
|
94
|
+
if (!res.ok) {
|
|
95
|
+
throw new Error(`Failed to fetch commitment tx: ${res.statusText}`);
|
|
96
|
+
}
|
|
97
|
+
const data = await res.json();
|
|
98
|
+
if (!Response.isCommitmentTx(data)) {
|
|
99
|
+
throw new Error("Invalid commitment tx data received");
|
|
100
|
+
}
|
|
101
|
+
return data;
|
|
102
|
+
}
|
|
103
|
+
async getCommitmentTxConnectors(txid, opts) {
|
|
104
|
+
let url = `${this.serverUrl}/v1/commitmentTx/${txid}/connectors`;
|
|
105
|
+
const params = new URLSearchParams();
|
|
106
|
+
if (opts) {
|
|
107
|
+
if (opts.pageIndex !== undefined)
|
|
108
|
+
params.append("page.index", opts.pageIndex.toString());
|
|
109
|
+
if (opts.pageSize !== undefined)
|
|
110
|
+
params.append("page.size", opts.pageSize.toString());
|
|
111
|
+
}
|
|
112
|
+
if (params.toString()) {
|
|
113
|
+
url += "?" + params.toString();
|
|
114
|
+
}
|
|
115
|
+
const res = await fetch(url);
|
|
116
|
+
if (!res.ok) {
|
|
117
|
+
throw new Error(`Failed to fetch commitment tx connectors: ${res.statusText}`);
|
|
118
|
+
}
|
|
119
|
+
const data = await res.json();
|
|
120
|
+
if (!Response.isConnectorsResponse(data)) {
|
|
121
|
+
throw new Error("Invalid commitment tx connectors data received");
|
|
122
|
+
}
|
|
123
|
+
data.connectors.forEach((tx) => {
|
|
124
|
+
tx.children = Object.fromEntries(Object.entries(tx.children).map(([key, value]) => [
|
|
125
|
+
Number(key),
|
|
126
|
+
value,
|
|
127
|
+
]));
|
|
128
|
+
});
|
|
129
|
+
return data;
|
|
130
|
+
}
|
|
131
|
+
async getCommitmentTxForfeitTxs(txid, opts) {
|
|
132
|
+
let url = `${this.serverUrl}/v1/commitmentTx/${txid}/forfeitTxs`;
|
|
133
|
+
const params = new URLSearchParams();
|
|
134
|
+
if (opts) {
|
|
135
|
+
if (opts.pageIndex !== undefined)
|
|
136
|
+
params.append("page.index", opts.pageIndex.toString());
|
|
137
|
+
if (opts.pageSize !== undefined)
|
|
138
|
+
params.append("page.size", opts.pageSize.toString());
|
|
139
|
+
}
|
|
140
|
+
if (params.toString()) {
|
|
141
|
+
url += "?" + params.toString();
|
|
142
|
+
}
|
|
143
|
+
const res = await fetch(url);
|
|
144
|
+
if (!res.ok) {
|
|
145
|
+
throw new Error(`Failed to fetch commitment tx forfeitTxs: ${res.statusText}`);
|
|
146
|
+
}
|
|
147
|
+
const data = await res.json();
|
|
148
|
+
if (!Response.isForfeitTxsResponse(data)) {
|
|
149
|
+
throw new Error("Invalid commitment tx forfeitTxs data received");
|
|
150
|
+
}
|
|
151
|
+
return data;
|
|
152
|
+
}
|
|
153
|
+
async *getSubscription(subscriptionId, abortSignal) {
|
|
154
|
+
const url = `${this.serverUrl}/v1/script/subscription/${subscriptionId}`;
|
|
155
|
+
while (!abortSignal.aborted) {
|
|
156
|
+
try {
|
|
157
|
+
const res = await fetch(url, {
|
|
158
|
+
headers: {
|
|
159
|
+
Accept: "application/json",
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
if (!res.ok) {
|
|
163
|
+
throw new Error(`Unexpected status ${res.status} when subscribing to address updates`);
|
|
164
|
+
}
|
|
165
|
+
if (!res.body) {
|
|
166
|
+
throw new Error("Response body is null");
|
|
167
|
+
}
|
|
168
|
+
const reader = res.body.getReader();
|
|
169
|
+
const decoder = new TextDecoder();
|
|
170
|
+
let buffer = "";
|
|
171
|
+
while (!abortSignal.aborted) {
|
|
172
|
+
const { done, value } = await reader.read();
|
|
173
|
+
if (done) {
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
buffer += decoder.decode(value, { stream: true });
|
|
177
|
+
const lines = buffer.split("\n");
|
|
178
|
+
for (let i = 0; i < lines.length - 1; i++) {
|
|
179
|
+
const line = lines[i].trim();
|
|
180
|
+
if (!line)
|
|
181
|
+
continue;
|
|
182
|
+
const data = JSON.parse(line);
|
|
183
|
+
if ("result" in data) {
|
|
184
|
+
yield {
|
|
185
|
+
txid: data.result.txid,
|
|
186
|
+
scripts: data.result.scripts || [],
|
|
187
|
+
newVtxos: (data.result.newVtxos || []).map(convertVtxo),
|
|
188
|
+
spentVtxos: (data.result.spentVtxos || []).map(convertVtxo),
|
|
189
|
+
tx: data.result.tx,
|
|
190
|
+
checkpointTxs: data.result.checkpointTxs,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
buffer = lines[lines.length - 1];
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
// ignore timeout errors, they're expected when the server is not sending anything for 5 min
|
|
202
|
+
// these timeouts are set by builtin fetch function
|
|
203
|
+
if (isFetchTimeoutError(error)) {
|
|
204
|
+
console.debug("Timeout error ignored");
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
console.error("Subscription error:", error);
|
|
208
|
+
throw error;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
async getVirtualTxs(txids, opts) {
|
|
213
|
+
let url = `${this.serverUrl}/v1/virtualTx/${txids.join(",")}`;
|
|
214
|
+
const params = new URLSearchParams();
|
|
215
|
+
if (opts) {
|
|
216
|
+
if (opts.pageIndex !== undefined)
|
|
217
|
+
params.append("page.index", opts.pageIndex.toString());
|
|
218
|
+
if (opts.pageSize !== undefined)
|
|
219
|
+
params.append("page.size", opts.pageSize.toString());
|
|
220
|
+
}
|
|
221
|
+
if (params.toString()) {
|
|
222
|
+
url += "?" + params.toString();
|
|
223
|
+
}
|
|
224
|
+
const res = await fetch(url);
|
|
225
|
+
if (!res.ok) {
|
|
226
|
+
throw new Error(`Failed to fetch virtual txs: ${res.statusText}`);
|
|
227
|
+
}
|
|
228
|
+
const data = await res.json();
|
|
229
|
+
if (!Response.isVirtualTxsResponse(data)) {
|
|
230
|
+
throw new Error("Invalid virtual txs data received");
|
|
231
|
+
}
|
|
232
|
+
return data;
|
|
233
|
+
}
|
|
234
|
+
async getVtxoChain(vtxoOutpoint, opts) {
|
|
235
|
+
let url = `${this.serverUrl}/v1/vtxo/${vtxoOutpoint.txid}/${vtxoOutpoint.vout}/chain`;
|
|
236
|
+
const params = new URLSearchParams();
|
|
237
|
+
if (opts) {
|
|
238
|
+
if (opts.pageIndex !== undefined)
|
|
239
|
+
params.append("page.index", opts.pageIndex.toString());
|
|
240
|
+
if (opts.pageSize !== undefined)
|
|
241
|
+
params.append("page.size", opts.pageSize.toString());
|
|
242
|
+
}
|
|
243
|
+
if (params.toString()) {
|
|
244
|
+
url += "?" + params.toString();
|
|
245
|
+
}
|
|
246
|
+
const res = await fetch(url);
|
|
247
|
+
if (!res.ok) {
|
|
248
|
+
throw new Error(`Failed to fetch vtxo chain: ${res.statusText}`);
|
|
249
|
+
}
|
|
250
|
+
const data = await res.json();
|
|
251
|
+
if (!Response.isVtxoChainResponse(data)) {
|
|
252
|
+
throw new Error("Invalid vtxo chain data received");
|
|
253
|
+
}
|
|
254
|
+
return data;
|
|
255
|
+
}
|
|
256
|
+
async getVtxos(opts) {
|
|
257
|
+
// scripts and outpoints are mutually exclusive
|
|
258
|
+
if (opts?.scripts && opts?.outpoints) {
|
|
259
|
+
throw new Error("scripts and outpoints are mutually exclusive options");
|
|
260
|
+
}
|
|
261
|
+
if (!opts?.scripts && !opts?.outpoints) {
|
|
262
|
+
throw new Error("Either scripts or outpoints must be provided");
|
|
263
|
+
}
|
|
264
|
+
let url = `${this.serverUrl}/v1/vtxos`;
|
|
265
|
+
const params = new URLSearchParams();
|
|
266
|
+
// Handle scripts with multi collection format
|
|
267
|
+
if (opts?.scripts && opts.scripts.length > 0) {
|
|
268
|
+
opts.scripts.forEach((script) => {
|
|
269
|
+
params.append("scripts", script);
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
// Handle outpoints with multi collection format
|
|
273
|
+
if (opts?.outpoints && opts.outpoints.length > 0) {
|
|
274
|
+
opts.outpoints.forEach((outpoint) => {
|
|
275
|
+
params.append("outpoints", `${outpoint.txid}:${outpoint.vout}`);
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
if (opts) {
|
|
279
|
+
if (opts.spendableOnly !== undefined)
|
|
280
|
+
params.append("spendableOnly", opts.spendableOnly.toString());
|
|
281
|
+
if (opts.spentOnly !== undefined)
|
|
282
|
+
params.append("spentOnly", opts.spentOnly.toString());
|
|
283
|
+
if (opts.recoverableOnly !== undefined)
|
|
284
|
+
params.append("recoverableOnly", opts.recoverableOnly.toString());
|
|
285
|
+
if (opts.pageIndex !== undefined)
|
|
286
|
+
params.append("page.index", opts.pageIndex.toString());
|
|
287
|
+
if (opts.pageSize !== undefined)
|
|
288
|
+
params.append("page.size", opts.pageSize.toString());
|
|
289
|
+
}
|
|
290
|
+
if (params.toString()) {
|
|
291
|
+
url += "?" + params.toString();
|
|
292
|
+
}
|
|
293
|
+
const res = await fetch(url);
|
|
294
|
+
if (!res.ok) {
|
|
295
|
+
throw new Error(`Failed to fetch vtxos: ${res.statusText}`);
|
|
296
|
+
}
|
|
297
|
+
const data = await res.json();
|
|
298
|
+
if (!Response.isVtxosResponse(data)) {
|
|
299
|
+
throw new Error("Invalid vtxos data received");
|
|
300
|
+
}
|
|
301
|
+
return {
|
|
302
|
+
vtxos: data.vtxos.map(convertVtxo),
|
|
303
|
+
page: data.page,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
async subscribeForScripts(scripts, subscriptionId) {
|
|
307
|
+
const url = `${this.serverUrl}/v1/script/subscribe`;
|
|
308
|
+
const res = await fetch(url, {
|
|
309
|
+
headers: {
|
|
310
|
+
"Content-Type": "application/json",
|
|
311
|
+
},
|
|
312
|
+
method: "POST",
|
|
313
|
+
body: JSON.stringify({ scripts, subscriptionId }),
|
|
314
|
+
});
|
|
315
|
+
if (!res.ok) {
|
|
316
|
+
const errorText = await res.text();
|
|
317
|
+
throw new Error(`Failed to subscribe to scripts: ${errorText}`);
|
|
318
|
+
}
|
|
319
|
+
const data = await res.json();
|
|
320
|
+
if (!data.subscriptionId)
|
|
321
|
+
throw new Error(`Subscription ID not found`);
|
|
322
|
+
return data.subscriptionId;
|
|
323
|
+
}
|
|
324
|
+
async unsubscribeForScripts(subscriptionId, scripts) {
|
|
325
|
+
const url = `${this.serverUrl}/v1/script/unsubscribe`;
|
|
326
|
+
const res = await fetch(url, {
|
|
327
|
+
headers: {
|
|
328
|
+
"Content-Type": "application/json",
|
|
329
|
+
},
|
|
330
|
+
method: "POST",
|
|
331
|
+
body: JSON.stringify({ subscriptionId, scripts }),
|
|
332
|
+
});
|
|
333
|
+
if (!res.ok) {
|
|
334
|
+
const errorText = await res.text();
|
|
335
|
+
throw new Error(`Failed to unsubscribe to scripts: ${errorText}`);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
function convertVtxo(vtxo) {
|
|
340
|
+
return {
|
|
341
|
+
txid: vtxo.outpoint.txid,
|
|
342
|
+
vout: vtxo.outpoint.vout,
|
|
343
|
+
value: Number(vtxo.amount),
|
|
344
|
+
status: {
|
|
345
|
+
confirmed: !vtxo.isSwept && !vtxo.isPreconfirmed,
|
|
346
|
+
},
|
|
347
|
+
virtualStatus: {
|
|
348
|
+
state: vtxo.isSwept
|
|
349
|
+
? "swept"
|
|
350
|
+
: vtxo.isPreconfirmed
|
|
351
|
+
? "preconfirmed"
|
|
352
|
+
: "settled",
|
|
353
|
+
commitmentTxIds: vtxo.commitmentTxids,
|
|
354
|
+
batchExpiry: vtxo.expiresAt
|
|
355
|
+
? Number(vtxo.expiresAt) * 1000
|
|
356
|
+
: undefined,
|
|
357
|
+
},
|
|
358
|
+
spentBy: vtxo.spentBy ?? "",
|
|
359
|
+
settledBy: vtxo.settledBy,
|
|
360
|
+
arkTxId: vtxo.arkTxid,
|
|
361
|
+
createdAt: new Date(Number(vtxo.createdAt) * 1000),
|
|
362
|
+
isUnrolled: vtxo.isUnrolled,
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
// Unexported namespace for type guards only
|
|
366
|
+
var Response;
|
|
367
|
+
(function (Response) {
|
|
368
|
+
function isBatch(data) {
|
|
369
|
+
return (typeof data === "object" &&
|
|
370
|
+
typeof data.totalOutputAmount === "string" &&
|
|
371
|
+
typeof data.totalOutputVtxos === "number" &&
|
|
372
|
+
typeof data.expiresAt === "string" &&
|
|
373
|
+
typeof data.swept === "boolean");
|
|
374
|
+
}
|
|
375
|
+
function isChain(data) {
|
|
376
|
+
return (typeof data === "object" &&
|
|
377
|
+
typeof data.txid === "string" &&
|
|
378
|
+
typeof data.expiresAt === "string" &&
|
|
379
|
+
Object.values(ChainTxType).includes(data.type) &&
|
|
380
|
+
Array.isArray(data.spends) &&
|
|
381
|
+
data.spends.every((spend) => typeof spend === "string"));
|
|
382
|
+
}
|
|
383
|
+
function isCommitmentTx(data) {
|
|
384
|
+
return (typeof data === "object" &&
|
|
385
|
+
typeof data.startedAt === "string" &&
|
|
386
|
+
typeof data.endedAt === "string" &&
|
|
387
|
+
typeof data.totalInputAmount === "string" &&
|
|
388
|
+
typeof data.totalInputVtxos === "number" &&
|
|
389
|
+
typeof data.totalOutputAmount === "string" &&
|
|
390
|
+
typeof data.totalOutputVtxos === "number" &&
|
|
391
|
+
typeof data.batches === "object" &&
|
|
392
|
+
Object.values(data.batches).every(isBatch));
|
|
393
|
+
}
|
|
394
|
+
Response.isCommitmentTx = isCommitmentTx;
|
|
395
|
+
function isOutpoint(data) {
|
|
396
|
+
return (typeof data === "object" &&
|
|
397
|
+
typeof data.txid === "string" &&
|
|
398
|
+
typeof data.vout === "number");
|
|
399
|
+
}
|
|
400
|
+
Response.isOutpoint = isOutpoint;
|
|
401
|
+
function isOutpointArray(data) {
|
|
402
|
+
return Array.isArray(data) && data.every(isOutpoint);
|
|
403
|
+
}
|
|
404
|
+
Response.isOutpointArray = isOutpointArray;
|
|
405
|
+
function isTx(data) {
|
|
406
|
+
return (typeof data === "object" &&
|
|
407
|
+
typeof data.txid === "string" &&
|
|
408
|
+
typeof data.children === "object" &&
|
|
409
|
+
Object.values(data.children).every(isTxid) &&
|
|
410
|
+
Object.keys(data.children).every((k) => Number.isInteger(Number(k))));
|
|
411
|
+
}
|
|
412
|
+
function isTxsArray(data) {
|
|
413
|
+
return Array.isArray(data) && data.every(isTx);
|
|
414
|
+
}
|
|
415
|
+
Response.isTxsArray = isTxsArray;
|
|
416
|
+
function isTxHistoryRecord(data) {
|
|
417
|
+
return (typeof data === "object" &&
|
|
418
|
+
typeof data.amount === "string" &&
|
|
419
|
+
typeof data.createdAt === "string" &&
|
|
420
|
+
typeof data.isSettled === "boolean" &&
|
|
421
|
+
typeof data.settledBy === "string" &&
|
|
422
|
+
Object.values(IndexerTxType).includes(data.type) &&
|
|
423
|
+
((!data.commitmentTxid && typeof data.virtualTxid === "string") ||
|
|
424
|
+
(typeof data.commitmentTxid === "string" && !data.virtualTxid)));
|
|
425
|
+
}
|
|
426
|
+
function isTxHistoryRecordArray(data) {
|
|
427
|
+
return Array.isArray(data) && data.every(isTxHistoryRecord);
|
|
428
|
+
}
|
|
429
|
+
Response.isTxHistoryRecordArray = isTxHistoryRecordArray;
|
|
430
|
+
function isTxid(data) {
|
|
431
|
+
return typeof data === "string" && data.length === 64;
|
|
432
|
+
}
|
|
433
|
+
function isTxidArray(data) {
|
|
434
|
+
return Array.isArray(data) && data.every(isTxid);
|
|
435
|
+
}
|
|
436
|
+
Response.isTxidArray = isTxidArray;
|
|
437
|
+
function isVtxo(data) {
|
|
438
|
+
return (typeof data === "object" &&
|
|
439
|
+
isOutpoint(data.outpoint) &&
|
|
440
|
+
typeof data.createdAt === "string" &&
|
|
441
|
+
typeof data.expiresAt === "string" &&
|
|
442
|
+
typeof data.amount === "string" &&
|
|
443
|
+
typeof data.script === "string" &&
|
|
444
|
+
typeof data.isPreconfirmed === "boolean" &&
|
|
445
|
+
typeof data.isSwept === "boolean" &&
|
|
446
|
+
typeof data.isUnrolled === "boolean" &&
|
|
447
|
+
typeof data.isSpent === "boolean" &&
|
|
448
|
+
(!data.spentBy || typeof data.spentBy === "string") &&
|
|
449
|
+
(!data.settledBy || typeof data.settledBy === "string") &&
|
|
450
|
+
(!data.arkTxid || typeof data.arkTxid === "string") &&
|
|
451
|
+
Array.isArray(data.commitmentTxids) &&
|
|
452
|
+
data.commitmentTxids.every(isTxid));
|
|
453
|
+
}
|
|
454
|
+
function isPageResponse(data) {
|
|
455
|
+
return (typeof data === "object" &&
|
|
456
|
+
typeof data.current === "number" &&
|
|
457
|
+
typeof data.next === "number" &&
|
|
458
|
+
typeof data.total === "number");
|
|
459
|
+
}
|
|
460
|
+
function isVtxoTreeResponse(data) {
|
|
461
|
+
return (typeof data === "object" &&
|
|
462
|
+
Array.isArray(data.vtxoTree) &&
|
|
463
|
+
data.vtxoTree.every(isTx) &&
|
|
464
|
+
(!data.page || isPageResponse(data.page)));
|
|
465
|
+
}
|
|
466
|
+
Response.isVtxoTreeResponse = isVtxoTreeResponse;
|
|
467
|
+
function isVtxoTreeLeavesResponse(data) {
|
|
468
|
+
return (typeof data === "object" &&
|
|
469
|
+
Array.isArray(data.leaves) &&
|
|
470
|
+
data.leaves.every(isOutpoint) &&
|
|
471
|
+
(!data.page || isPageResponse(data.page)));
|
|
472
|
+
}
|
|
473
|
+
Response.isVtxoTreeLeavesResponse = isVtxoTreeLeavesResponse;
|
|
474
|
+
function isConnectorsResponse(data) {
|
|
475
|
+
return (typeof data === "object" &&
|
|
476
|
+
Array.isArray(data.connectors) &&
|
|
477
|
+
data.connectors.every(isTx) &&
|
|
478
|
+
(!data.page || isPageResponse(data.page)));
|
|
479
|
+
}
|
|
480
|
+
Response.isConnectorsResponse = isConnectorsResponse;
|
|
481
|
+
function isForfeitTxsResponse(data) {
|
|
482
|
+
return (typeof data === "object" &&
|
|
483
|
+
Array.isArray(data.txids) &&
|
|
484
|
+
data.txids.every(isTxid) &&
|
|
485
|
+
(!data.page || isPageResponse(data.page)));
|
|
486
|
+
}
|
|
487
|
+
Response.isForfeitTxsResponse = isForfeitTxsResponse;
|
|
488
|
+
function isSweptCommitmentTxResponse(data) {
|
|
489
|
+
return (typeof data === "object" &&
|
|
490
|
+
Array.isArray(data.sweptBy) &&
|
|
491
|
+
data.sweptBy.every(isTxid));
|
|
492
|
+
}
|
|
493
|
+
Response.isSweptCommitmentTxResponse = isSweptCommitmentTxResponse;
|
|
494
|
+
function isBatchSweepTransactionsResponse(data) {
|
|
495
|
+
return (typeof data === "object" &&
|
|
496
|
+
Array.isArray(data.sweptBy) &&
|
|
497
|
+
data.sweptBy.every(isTxid));
|
|
498
|
+
}
|
|
499
|
+
Response.isBatchSweepTransactionsResponse = isBatchSweepTransactionsResponse;
|
|
500
|
+
function isVirtualTxsResponse(data) {
|
|
501
|
+
return (typeof data === "object" &&
|
|
502
|
+
Array.isArray(data.txs) &&
|
|
503
|
+
data.txs.every((tx) => typeof tx === "string") &&
|
|
504
|
+
(!data.page || isPageResponse(data.page)));
|
|
505
|
+
}
|
|
506
|
+
Response.isVirtualTxsResponse = isVirtualTxsResponse;
|
|
507
|
+
function isVtxoChainResponse(data) {
|
|
508
|
+
return (typeof data === "object" &&
|
|
509
|
+
Array.isArray(data.chain) &&
|
|
510
|
+
data.chain.every(isChain) &&
|
|
511
|
+
(!data.page || isPageResponse(data.page)));
|
|
512
|
+
}
|
|
513
|
+
Response.isVtxoChainResponse = isVtxoChainResponse;
|
|
514
|
+
function isVtxosResponse(data) {
|
|
515
|
+
return (typeof data === "object" &&
|
|
516
|
+
Array.isArray(data.vtxos) &&
|
|
517
|
+
data.vtxos.every(isVtxo) &&
|
|
518
|
+
(!data.page || isPageResponse(data.page)));
|
|
519
|
+
}
|
|
520
|
+
Response.isVtxosResponse = isVtxosResponse;
|
|
521
|
+
})(Response || (Response = {}));
|