@pioneer-platform/blockbook 8.3.16 → 8.4.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/lib/index.js CHANGED
@@ -1,23 +1,8 @@
1
1
  "use strict";
2
- /**
3
- * Blockbook Client Integration Module
4
- *
5
- * Provides a unified interface for interacting with Blockbook blockchain explorers
6
- * across multiple cryptocurrency networks. Handles pagination, retries, and fallbacks.
7
- *
8
- * @module blockbook-client
2
+ /*
3
+
4
+
9
5
  */
10
- var __assign = (this && this.__assign) || function () {
11
- __assign = Object.assign || function(t) {
12
- for (var s, i = 1, n = arguments.length; i < n; i++) {
13
- s = arguments[i];
14
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
15
- t[p] = s[p];
16
- }
17
- return t;
18
- };
19
- return __assign.apply(this, arguments);
20
- };
21
6
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
22
7
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
23
8
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -54,184 +39,163 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
54
39
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
55
40
  }
56
41
  };
57
- var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
58
- if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
59
- if (ar || !(i in from)) {
60
- if (!ar) ar = Array.prototype.slice.call(from, 0, i);
61
- ar[i] = from[i];
62
- }
63
- }
64
- return to.concat(ar || Array.prototype.slice.call(from));
65
- };
42
+ var TAG = " | blockbook-client | ";
66
43
  var Blockbook = require('blockbook-client').Blockbook;
67
44
  var log = require('@pioneer-platform/loggerdog')();
68
45
  var fakeUa = require('fake-useragent');
69
46
  var Axios = require('axios');
70
47
  var https = require('https');
71
- var nodes = require('@pioneer-platform/nodes');
72
- var axiosRetry = require('axios-retry');
73
- var TAG = " | blockbook-client | ";
74
- var NOW_NODES_API = process.env['NOW_NODES_API'];
75
- // Configure axios with retry logic and custom settings
48
+ var nodes = require("@pioneer-platform/nodes");
76
49
  var axios = Axios.create({
77
50
  httpsAgent: new https.Agent({
78
51
  rejectUnauthorized: false
79
52
  }),
80
- timeout: 30000 // 30 seconds timeout
81
- });
82
- // Configure automatic retries for transient failures
83
- axiosRetry(axios, {
84
- retries: 3,
85
- retryDelay: function (retryCount) {
86
- log.error(TAG, "Retry attempt: ".concat(retryCount));
87
- return retryCount * 2000; // Exponential backoff
88
- },
89
- retryCondition: function (error) {
90
- var _a;
91
- // Retry on network errors or 5xx status codes
92
- return axiosRetry.isNetworkOrIdempotentRequestError(error) ||
93
- (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) ? error.response.status >= 500 : false);
94
- },
53
+ timeout: 30000 // 10 seconds
95
54
  });
96
- // Global storage for Blockbook URLs and WebSocket connections
55
+ // const axiosRetry = require('axios-retry');
56
+ var NOW_NODES_API = process.env['NOW_NODES_API'];
57
+ // axiosRetry(axios, {
58
+ // retries: 3, // number of retries
59
+ // retryDelay: (retryCount: number) => {
60
+ // log.error(TAG,`retry attempt: ${retryCount}`);
61
+ // return retryCount * 2000; // time interval between retries
62
+ // },
63
+ // retryCondition: (error: { response: { status: number; }; }) => {
64
+ // log.error(TAG,error)
65
+ // //@TODO mark node offline, and punish
66
+ // // if retry condition is not specified, by default idempotent requests are retried
67
+ // return error?.response?.status === 503;
68
+ // },
69
+ // });
97
70
  var BLOCKBOOK_URLS = {};
98
71
  var BLOCKBOOK_SOCKETS = {};
99
- // Cache for frequently accessed data
100
- var cache = new Map();
101
- var CACHE_TTL = 60000; // 1 minute cache TTL
102
- /**
103
- * Get cached data if available and not expired
104
- */
105
- function getCached(key) {
106
- var cached = cache.get(key);
107
- if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
108
- return cached.data;
109
- }
110
- cache.delete(key);
111
- return null;
112
- }
113
- /**
114
- * Store data in cache
115
- */
116
- function setCache(key, data) {
117
- cache.set(key, { data: data, timestamp: Date.now() });
118
- }
119
- // Main module exports
120
72
  module.exports = {
121
- init: init_network,
122
- getInfo: get_node_info,
123
- getBlockbooks: function () { return BLOCKBOOK_URLS; },
124
- getBlockbookSockets: function () { return BLOCKBOOK_SOCKETS; },
125
- getFees: get_fees,
126
- getTransaction: get_transaction,
127
- getAddressInfo: get_info_by_address,
128
- getPubkeyInfo: get_info_by_pubkey,
129
- getNextIndexes: get_next_indexes_by_pubkey,
130
- computeNextIndexes: computeNextIndexes,
131
- txidsByAddress: get_txids_by_address,
132
- txsByXpub: get_txs_by_xpub,
133
- utxosByXpub: get_utxos_by_xpub,
134
- getBalanceByXpub: get_balance_by_xpub,
135
- broadcast: broadcast_transaction,
73
+ init: function (servers) {
74
+ return init_network(servers);
75
+ },
76
+ addNode: function (coin, url) {
77
+ return add_custom_node(coin, url);
78
+ },
79
+ getInfo: function () {
80
+ return get_node_info();
81
+ },
82
+ getBlockbooks: function () {
83
+ return BLOCKBOOK_URLS;
84
+ },
85
+ getBlockbookSockets: function () {
86
+ return BLOCKBOOK_SOCKETS;
87
+ },
88
+ getFees: function (coin) {
89
+ return get_fees(coin);
90
+ },
91
+ getTransaction: function (coin, txid) {
92
+ return get_transaction(coin, txid);
93
+ },
94
+ getAddressInfo: function (coin, address, filter) {
95
+ return get_info_by_address(coin, address, filter);
96
+ },
97
+ getPubkeyInfo: function (coin, pubkey, filter) {
98
+ return get_info_by_pubkey(coin, pubkey, filter);
99
+ },
100
+ txidsByAddress: function (coin, address, page) {
101
+ return get_txids_by_address(coin, address, page);
102
+ },
103
+ txsByXpub: function (coin, addresses) {
104
+ return get_txs_by_xpub(coin, addresses);
105
+ },
106
+ utxosByXpub: function (coin, xpub) {
107
+ return get_utxos_by_xpub(coin, xpub);
108
+ },
109
+ getBalanceByXpub: function (coin, xpub) {
110
+ return get_balance_by_xpub(coin, xpub);
111
+ },
112
+ broadcast: function (coin, hex) {
113
+ return broadcast_transaction(coin, hex);
114
+ },
136
115
  };
137
- /**
138
- * Initialize the Blockbook network with seed nodes and custom servers
139
- * @param servers Optional array of custom Blockbook server configurations
140
- * @returns Promise<boolean> indicating successful initialization
141
- */
142
- function init_network(servers) {
116
+ // Add a custom node at runtime
117
+ var add_custom_node = function (coin, url) {
118
+ var symbol = coin.toUpperCase();
119
+ var cleanUrl = url.replace(/\/$/, ''); // Remove trailing slash
120
+ // Store URLs as arrays if not already
121
+ if (typeof BLOCKBOOK_URLS[symbol] === 'string') {
122
+ BLOCKBOOK_URLS[symbol] = [BLOCKBOOK_URLS[symbol]];
123
+ }
124
+ if (!BLOCKBOOK_URLS[symbol]) {
125
+ BLOCKBOOK_URLS[symbol] = [];
126
+ }
127
+ // Check for duplicates
128
+ if (Array.isArray(BLOCKBOOK_URLS[symbol]) && BLOCKBOOK_URLS[symbol].includes(cleanUrl)) {
129
+ log.warn("Node ".concat(cleanUrl, " already exists for ").concat(symbol));
130
+ return false;
131
+ }
132
+ if (Array.isArray(BLOCKBOOK_URLS[symbol])) {
133
+ BLOCKBOOK_URLS[symbol].push(cleanUrl);
134
+ }
135
+ else {
136
+ BLOCKBOOK_URLS[symbol] = [BLOCKBOOK_URLS[symbol], cleanUrl];
137
+ }
138
+ log.info("Added custom node for ".concat(symbol, ": ").concat(cleanUrl));
139
+ log.info("".concat(symbol, " now has ").concat(Array.isArray(BLOCKBOOK_URLS[symbol]) ? BLOCKBOOK_URLS[symbol].length : 1, " node(s)"));
140
+ return true;
141
+ };
142
+ var init_network = function (servers) {
143
143
  return __awaiter(this, void 0, void 0, function () {
144
- var tag, SEED_NODES, allNodes, blockbooks, _i, blockbooks_1, blockbook, symbol, httpUrl, e_1;
144
+ var tag, SEED_NODES, blockbooks, i, blockbook, url, e_1;
145
145
  return __generator(this, function (_a) {
146
146
  switch (_a.label) {
147
147
  case 0:
148
- tag = TAG + " | init_network | ";
148
+ tag = ' | get_txs_by_address | ';
149
149
  _a.label = 1;
150
150
  case 1:
151
- _a.trys.push([1, 7, , 8]);
152
- log.debug(tag, "Initializing Blockbook network...");
153
- SEED_NODES = [];
154
- if (!(typeof nodes.getBlockbooks === 'function')) return [3 /*break*/, 3];
151
+ _a.trys.push([1, 3, , 4]);
152
+ log.debug(tag, "checkpoint: ");
155
153
  return [4 /*yield*/, nodes.getBlockbooks()];
156
154
  case 2:
157
155
  SEED_NODES = _a.sent();
158
- return [3 /*break*/, 6];
159
- case 3:
160
- if (!(typeof nodes.getNodes === 'function')) return [3 /*break*/, 5];
161
- return [4 /*yield*/, nodes.getNodes()];
162
- case 4:
163
- allNodes = _a.sent();
164
- SEED_NODES = allNodes.filter(function (n) { return n.type === 'blockbook' || n.service; });
165
- return [3 /*break*/, 6];
166
- case 5:
167
- if (nodes.blockbooks) {
168
- SEED_NODES = nodes.blockbooks;
169
- }
170
- else {
171
- log.warn(tag, "Unable to load seed nodes from @pioneer-platform/nodes");
172
- }
173
- _a.label = 6;
174
- case 6:
175
- log.info(tag, "Loaded ".concat(SEED_NODES.length, " seed nodes"));
156
+ log.info(tag, "SEED_NODES: ", SEED_NODES);
176
157
  blockbooks = [];
177
- if (servers && Array.isArray(servers)) {
178
- blockbooks = servers.concat(SEED_NODES);
179
- log.info(tag, "Added ".concat(servers.length, " custom servers"));
158
+ if (servers && Array.isArray(servers)) { // Type checking for array
159
+ blockbooks = servers.concat(SEED_NODES); // Combine arrays
180
160
  }
181
161
  else {
182
- if (servers) {
183
- log.warn(tag, "Invalid 'servers' parameter. Expected an array.");
184
- }
162
+ console.error("Invalid 'servers' parameter. Expected an array.");
185
163
  blockbooks = SEED_NODES;
186
164
  }
187
- log.debug(tag, "Total blockbook servers: ".concat(blockbooks.length));
188
- // Initialize each Blockbook server
189
- for (_i = 0, blockbooks_1 = blockbooks; _i < blockbooks_1.length; _i++) {
190
- blockbook = blockbooks_1[_i];
191
- try {
192
- if (blockbook === null || blockbook === void 0 ? void 0 : blockbook.service) {
193
- symbol = blockbook.symbol.toUpperCase();
194
- BLOCKBOOK_URLS[symbol] = blockbook.service;
195
- if (blockbook.websocket) {
196
- httpUrl = blockbook.websocket
197
- .replace("/websocket", "")
198
- .replace("wss://", "https://")
199
- .replace("ws://", "http://");
200
- BLOCKBOOK_SOCKETS[symbol] = new Blockbook({
201
- nodes: [httpUrl],
202
- disableTypeValidation: true,
203
- });
204
- log.debug(tag, "Initialized ".concat(symbol, " with URL: ").concat(blockbook.service));
205
- }
206
- }
207
- else {
208
- log.warn(tag, "Invalid blockbook configuration:", blockbook);
209
- }
165
+ log.debug(tag, "blockbooks: ", blockbooks.length);
166
+ for (i = 0; i < blockbooks.length; i++) {
167
+ blockbook = blockbooks[i];
168
+ //get swagger
169
+ if (blockbook && blockbook.service)
170
+ BLOCKBOOK_URLS[blockbook.symbol.toUpperCase()] = blockbook.service;
171
+ if (blockbook && blockbook.websocket) {
172
+ url = blockbook.websocket.replace("/websocket", "");
173
+ url = blockbook.websocket.replace("wss://", "https://");
174
+ BLOCKBOOK_SOCKETS[blockbook.symbol.toUpperCase()] = new Blockbook({
175
+ nodes: [url],
176
+ disableTypeValidation: true,
177
+ });
210
178
  }
211
- catch (error) {
212
- log.error(tag, "Failed to initialize blockbook ".concat(blockbook === null || blockbook === void 0 ? void 0 : blockbook.symbol, ":"), error);
179
+ else {
180
+ log.error(tag, "invalid unchained service: ", blockbook);
181
+ // throw Error("invalid unchained service!")
213
182
  }
214
183
  }
215
- log.info(tag, "Initialized ".concat(Object.keys(BLOCKBOOK_URLS).length, " Blockbook URLs"));
216
- log.info(tag, "Initialized ".concat(Object.keys(BLOCKBOOK_SOCKETS).length, " WebSocket connections"));
184
+ log.debug(tag, "BLOCKBOOK_URLS: ", BLOCKBOOK_URLS);
185
+ log.debug(tag, "BLOCKBOOK_SOCKETS: ", BLOCKBOOK_SOCKETS);
217
186
  return [2 /*return*/, true];
218
- case 7:
187
+ case 3:
219
188
  e_1 = _a.sent();
220
- log.error(tag, "Failed to initialize network:", e_1);
189
+ // console.error(tag, 'Error: ', e)
221
190
  throw e_1;
222
- case 8: return [2 /*return*/];
191
+ case 4: return [2 /*return*/];
223
192
  }
224
193
  });
225
194
  });
226
- }
227
- /**
228
- * Get fee estimates for a specific coin
229
- * @param coin Coin symbol (e.g., 'BTC', 'ETH')
230
- * @returns Promise<FeeEstimate> containing fee recommendations
231
- */
232
- function get_fees(coin) {
195
+ };
196
+ var get_fees = function (coin) {
233
197
  return __awaiter(this, void 0, void 0, function () {
234
- var tag, cacheKey, cached, baseUrl, url, resp, feeData, e_2;
198
+ var tag, url, body, resp, e_2;
235
199
  return __generator(this, function (_a) {
236
200
  switch (_a.label) {
237
201
  case 0:
@@ -239,254 +203,74 @@ function get_fees(coin) {
239
203
  _a.label = 1;
240
204
  case 1:
241
205
  _a.trys.push([1, 3, , 4]);
242
- cacheKey = "fees:".concat(coin.toUpperCase());
243
- cached = getCached(cacheKey);
244
- if (cached) {
245
- log.debug(tag, "Returning cached fees for ".concat(coin));
246
- return [2 /*return*/, cached];
247
- }
248
- baseUrl = BLOCKBOOK_URLS[coin.toUpperCase()];
249
- if (!baseUrl) {
250
- throw new Error("Unknown coin '".concat(coin, "' or missing BLOCKBOOK_URLS entry"));
251
- }
252
- url = "".concat(baseUrl, "/api/v2/fees");
253
- log.debug(tag, "Fetching fees from:", url);
254
- return [4 /*yield*/, axios({
255
- method: 'GET',
256
- url: url,
257
- headers: {
258
- 'content-type': 'application/json',
259
- 'User-Agent': typeof fakeUa === 'function' ? fakeUa() : 'blockbook-client/1.0'
260
- },
261
- })];
206
+ url = BLOCKBOOK_URLS[coin.toUpperCase()] + "/api/v2/fees";
207
+ log.debug(tag, "url: ", url);
208
+ body = {
209
+ method: 'GET',
210
+ url: url,
211
+ headers: {
212
+ 'content-type': 'application/json',
213
+ 'User-Agent': fakeUa()
214
+ },
215
+ };
216
+ return [4 /*yield*/, axios(body)
217
+ //log.debug(tag,"resp: ",resp)
218
+ //TODO paginate?
219
+ ];
262
220
  case 2:
263
221
  resp = _a.sent();
264
- feeData = resp.data;
265
- setCache(cacheKey, feeData);
266
- return [2 /*return*/, feeData];
222
+ //log.debug(tag,"resp: ",resp)
223
+ //TODO paginate?
224
+ return [2 /*return*/, resp.data];
267
225
  case 3:
268
226
  e_2 = _a.sent();
269
- log.error(tag, "Failed to get fees for ".concat(coin, ":"), e_2);
227
+ console.error(tag, e_2);
270
228
  throw e_2;
271
229
  case 4: return [2 /*return*/];
272
230
  }
273
231
  });
274
232
  });
275
- }
276
- /**
277
- * Fetch xpub info from Blockbook with tokens, handling pagination and fallbacks.
278
- * @param coin Uppercase/anycase coin key resolvable in BLOCKBOOK_URLS (e.g., 'BTC')
279
- * @param pubkey xpub/ypub/zpub/tpub/vpub
280
- * @param page Starting page number (default 1)
281
- * @param pageSize Items per page (default 1000)
282
- * @returns Promise<XpubResponse> with complete token information including changeIndex and receiveIndex
283
- */
284
- function get_info_by_pubkey(coin_1, pubkey_1) {
285
- return __awaiter(this, arguments, void 0, function (coin, pubkey, page, pageSize) {
286
- var tag, baseUrl, url_1, fetchPage, params, data, totalPages, allTokens, startPage, pagePromises, p, pageResults, _i, pageResults_1, pageData, txidsParams, txidsData, err_1, nextIndexes, enhancedData, e_3;
287
- var _this = this;
288
- var _a, _b, _c, _d;
289
- if (page === void 0) { page = 1; }
290
- if (pageSize === void 0) { pageSize = 1000; }
291
- return __generator(this, function (_e) {
292
- switch (_e.label) {
233
+ };
234
+ var get_info_by_pubkey = function (coin, pubkey, page) {
235
+ return __awaiter(this, void 0, void 0, function () {
236
+ var tag, url, body, resp, e_3;
237
+ return __generator(this, function (_a) {
238
+ switch (_a.label) {
293
239
  case 0:
294
240
  tag = TAG + " | get_info_by_pubkey | ";
295
- _e.label = 1;
241
+ _a.label = 1;
296
242
  case 1:
297
- _e.trys.push([1, 11, , 12]);
298
- baseUrl = BLOCKBOOK_URLS[coin.toUpperCase()];
299
- if (!baseUrl) {
300
- throw new Error("Unknown coin '".concat(coin, "' or missing BLOCKBOOK_URLS entry"));
301
- }
302
- url_1 = "".concat(baseUrl, "/api/v2/xpub/").concat(encodeURIComponent(pubkey));
303
- fetchPage = function (params) { return __awaiter(_this, void 0, void 0, function () {
304
- var resp;
305
- return __generator(this, function (_a) {
306
- switch (_a.label) {
307
- case 0:
308
- log.debug(tag, "Fetching page with params:", params);
309
- return [4 /*yield*/, axios({
310
- method: "GET",
311
- url: url_1,
312
- headers: {
313
- "content-type": "application/json",
314
- "User-Agent": typeof fakeUa === "function" ? fakeUa() : "blockbook-client/1.0",
315
- },
316
- params: params,
317
- })];
318
- case 1:
319
- resp = _a.sent();
320
- return [2 /*return*/, resp.data];
321
- }
322
- });
323
- }); };
324
- params = {
325
- page: page,
326
- pageSize: pageSize,
327
- details: "tokenBalances",
328
- tokens: "derived",
243
+ _a.trys.push([1, 3, , 4]);
244
+ if (!page)
245
+ page = "1";
246
+ url = BLOCKBOOK_URLS[coin.toUpperCase()] + "/api/v2/xpub/" + pubkey;
247
+ log.debug(tag, "url: ", url);
248
+ body = {
249
+ method: 'GET',
250
+ url: url,
251
+ headers: {
252
+ 'content-type': 'application/json',
253
+ 'User-Agent': fakeUa()
254
+ },
329
255
  };
330
- return [4 /*yield*/, fetchPage(params)];
256
+ return [4 /*yield*/, axios(body)];
331
257
  case 2:
332
- data = _e.sent();
333
- log.debug(tag, "Initial fetch returned ".concat(((_a = data.tokens) === null || _a === void 0 ? void 0 : _a.length) || 0, " tokens"));
334
- if (!(!data.tokens || data.tokens.length === 0)) return [3 /*break*/, 4];
335
- log.debug(tag, "No derived tokens found, trying 'used' fallback");
336
- params = {
337
- page: page,
338
- pageSize: pageSize,
339
- details: "tokens",
340
- tokens: "used",
341
- };
342
- return [4 /*yield*/, fetchPage(params)];
258
+ resp = _a.sent();
259
+ log.debug(tag, "resp: ", resp);
260
+ //TODO paginate?
261
+ return [2 /*return*/, resp.data];
343
262
  case 3:
344
- data = _e.sent();
345
- _e.label = 4;
346
- case 4:
347
- // Ensure tokens array exists
348
- if (!data.tokens) {
349
- data.tokens = [];
350
- }
351
- totalPages = Number((_b = data.totalPages) !== null && _b !== void 0 ? _b : 1);
352
- if (!(totalPages > 1)) return [3 /*break*/, 6];
353
- log.info(tag, "Fetching ".concat(totalPages, " pages of token data"));
354
- allTokens = __spreadArray([], data.tokens, true);
355
- startPage = Number((_c = data.page) !== null && _c !== void 0 ? _c : page);
356
- pagePromises = [];
357
- for (p = startPage + 1; p <= totalPages; p++) {
358
- pagePromises.push(fetchPage(__assign(__assign({}, params), { page: p })));
359
- }
360
- return [4 /*yield*/, Promise.all(pagePromises)];
361
- case 5:
362
- pageResults = _e.sent();
363
- for (_i = 0, pageResults_1 = pageResults; _i < pageResults_1.length; _i++) {
364
- pageData = pageResults_1[_i];
365
- if ((_d = pageData === null || pageData === void 0 ? void 0 : pageData.tokens) === null || _d === void 0 ? void 0 : _d.length) {
366
- allTokens.push.apply(allTokens, pageData.tokens);
367
- }
368
- }
369
- // Update metadata to reflect merged data
370
- data.tokens = allTokens;
371
- data.page = 1;
372
- data.totalPages = 1;
373
- data.itemsOnPage = allTokens.length;
374
- log.info(tag, "Merged ".concat(allTokens.length, " total tokens from ").concat(totalPages, " pages"));
375
- _e.label = 6;
376
- case 6:
377
- if (!(data.txs > 0 && (!data.txids || data.txids.length === 0))) return [3 /*break*/, 10];
378
- log.debug(tag, "Fetching txids for ".concat(data.txs, " transactions"));
379
- txidsParams = {
380
- page: 1,
381
- pageSize: Math.min(1000, data.txs * 2), // Get more to ensure we get all
382
- details: "txids",
383
- };
384
- _e.label = 7;
385
- case 7:
386
- _e.trys.push([7, 9, , 10]);
387
- return [4 /*yield*/, fetchPage(txidsParams)];
388
- case 8:
389
- txidsData = _e.sent();
390
- if (txidsData.txids && txidsData.txids.length > 0) {
391
- data.txids = txidsData.txids;
392
- log.info(tag, "Fetched ".concat(txidsData.txids.length, " txids"));
393
- }
394
- return [3 /*break*/, 10];
395
- case 9:
396
- err_1 = _e.sent();
397
- log.warn(tag, "Failed to fetch txids separately:", err_1);
398
- return [3 /*break*/, 10];
399
- case 10:
400
- nextIndexes = computeNextIndexes(data.tokens || []);
401
- enhancedData = __assign(__assign({}, data), { changeIndex: nextIndexes.nextChangeAddressIndex, receiveIndex: nextIndexes.nextReceiveAddressIndex });
402
- return [2 /*return*/, enhancedData];
403
- case 11:
404
- e_3 = _e.sent();
405
- log.error(tag, "Failed to get pubkey info for ".concat(coin, ":"), e_3);
263
+ e_3 = _a.sent();
264
+ console.error(tag, e_3);
406
265
  throw e_3;
407
- case 12: return [2 /*return*/];
408
- }
409
- });
410
- });
411
- }
412
- /**
413
- * Compute next indexes from Blockbook tokens array.
414
- * Returns the next external (receive) and internal (change) indexes.
415
- *
416
- * Logic:
417
- * - Consider an address "used" if transfers > 0 OR balance !== '0'
418
- * - Next index = (max used index on that branch) + 1
419
- *
420
- * @param tokens Array of BlockbookToken objects with path information
421
- * @returns Object with nextReceiveAddressIndex and nextChangeAddressIndex
422
- */
423
- function computeNextIndexes(tokens) {
424
- var _a, _b, _c, _d;
425
- var next = []; // next[0] = next receive, next[1] = next change
426
- for (var _i = 0, _e = tokens !== null && tokens !== void 0 ? tokens : []; _i < _e.length; _i++) {
427
- var token = _e[_i];
428
- if (!token.path)
429
- continue;
430
- // Parse BIP32 path: m/84'/0'/0'/1/5
431
- var parts = token.path.split("/");
432
- if (parts.length < 6)
433
- continue;
434
- var change = Number(parts[4]);
435
- var index = Number(parts[5]);
436
- if (!Number.isInteger(change) || !Number.isInteger(index))
437
- continue;
438
- if (change !== 0 && change !== 1)
439
- continue; // Only handle standard change values
440
- // Check if address is used
441
- var used = ((_a = token.transfers) !== null && _a !== void 0 ? _a : 0) > 0 || ((_b = token.balance) !== null && _b !== void 0 ? _b : "0") !== "0";
442
- if (!used)
443
- continue;
444
- // Update next index if this is higher than current
445
- var candidate = index + 1;
446
- if (next[change] == null || candidate > next[change]) {
447
- next[change] = candidate;
448
- }
449
- }
450
- return {
451
- nextReceiveAddressIndex: (_c = next[0]) !== null && _c !== void 0 ? _c : 0,
452
- nextChangeAddressIndex: (_d = next[1]) !== null && _d !== void 0 ? _d : 0,
453
- };
454
- }
455
- /**
456
- * Convenience function: fetch tokens and return the next indexes directly.
457
- * @param coin Coin symbol
458
- * @param pubkey Extended public key
459
- * @param page Starting page
460
- * @param pageSize Items per page
461
- * @returns Promise<NextIndexes> with next receive and change indexes
462
- */
463
- function get_next_indexes_by_pubkey(coin_1, pubkey_1) {
464
- return __awaiter(this, arguments, void 0, function (coin, pubkey, page, pageSize) {
465
- var info;
466
- var _a;
467
- if (page === void 0) { page = 1; }
468
- if (pageSize === void 0) { pageSize = 1000; }
469
- return __generator(this, function (_b) {
470
- switch (_b.label) {
471
- case 0: return [4 /*yield*/, get_info_by_pubkey(coin, pubkey, page, pageSize)];
472
- case 1:
473
- info = _b.sent();
474
- return [2 /*return*/, computeNextIndexes((_a = info.tokens) !== null && _a !== void 0 ? _a : [])];
266
+ case 4: return [2 /*return*/];
475
267
  }
476
268
  });
477
269
  });
478
- }
479
- /**
480
- * Get transaction IDs for a specific address with pagination support
481
- * @param coin Coin symbol
482
- * @param address Blockchain address
483
- * @param page Page number (default 1)
484
- * @returns Promise with address info including transaction IDs
485
- */
486
- function get_txids_by_address(coin_1, address_1) {
487
- return __awaiter(this, arguments, void 0, function (coin, address, page) {
488
- var tag, baseUrl, url, resp, data, e_4;
489
- if (page === void 0) { page = 1; }
270
+ };
271
+ var get_txids_by_address = function (coin, address, page) {
272
+ return __awaiter(this, void 0, void 0, function () {
273
+ var tag, url, body, resp, e_4;
490
274
  return __generator(this, function (_a) {
491
275
  switch (_a.label) {
492
276
  case 0:
@@ -494,53 +278,37 @@ function get_txids_by_address(coin_1, address_1) {
494
278
  _a.label = 1;
495
279
  case 1:
496
280
  _a.trys.push([1, 3, , 4]);
497
- baseUrl = BLOCKBOOK_URLS[coin.toUpperCase()];
498
- if (!baseUrl) {
499
- throw new Error("Unknown coin '".concat(coin, "' or missing BLOCKBOOK_URLS entry"));
500
- }
501
- url = "".concat(baseUrl, "/api/v2/address/").concat(address);
502
- log.debug(tag, "Fetching txids from:", url);
503
- return [4 /*yield*/, axios({
504
- method: 'GET',
505
- url: url,
506
- headers: {
507
- 'content-type': 'application/json',
508
- 'User-Agent': typeof fakeUa === 'function' ? fakeUa() : 'blockbook-client/1.0'
509
- },
510
- params: {
511
- page: page,
512
- details: 'txids',
513
- pageSize: 1000
514
- }
515
- })];
281
+ if (!page)
282
+ page = 1;
283
+ url = BLOCKBOOK_URLS[coin.toUpperCase()] + "/api/v2/address/" + address + "?page=" + page + "&details=all";
284
+ log.debug(tag, "url: ", url);
285
+ body = {
286
+ method: 'GET',
287
+ url: url,
288
+ headers: {
289
+ 'content-type': 'application/json',
290
+ 'User-Agent': fakeUa()
291
+ },
292
+ };
293
+ return [4 /*yield*/, axios(body)
294
+ //TODO paginate?
295
+ ];
516
296
  case 2:
517
297
  resp = _a.sent();
518
- data = resp.data;
519
- if (data.totalPages > 1 && page === 1) {
520
- log.info(tag, "Address has ".concat(data.totalPages, " pages of transactions"));
521
- // Consider implementing full pagination here if needed
522
- }
523
- return [2 /*return*/, data];
298
+ //TODO paginate?
299
+ return [2 /*return*/, resp.data];
524
300
  case 3:
525
301
  e_4 = _a.sent();
526
- log.error(tag, "Failed to get txids for address ".concat(address, ":"), e_4);
302
+ console.error(tag, e_4);
527
303
  throw e_4;
528
304
  case 4: return [2 /*return*/];
529
305
  }
530
306
  });
531
307
  });
532
- }
533
- /**
534
- * Get detailed information for a specific address
535
- * @param coin Coin symbol
536
- * @param address Blockchain address
537
- * @param filter Detail level filter (default 'all')
538
- * @returns Promise with complete address information
539
- */
540
- function get_info_by_address(coin_1, address_1) {
541
- return __awaiter(this, arguments, void 0, function (coin, address, filter) {
542
- var tag, baseUrl, url, resp, e_5;
543
- if (filter === void 0) { filter = 'all'; }
308
+ };
309
+ var get_info_by_address = function (coin, address, filter) {
310
+ return __awaiter(this, void 0, void 0, function () {
311
+ var tag, url, body, resp, e_5;
544
312
  return __generator(this, function (_a) {
545
313
  switch (_a.label) {
546
314
  case 0:
@@ -548,141 +316,118 @@ function get_info_by_address(coin_1, address_1) {
548
316
  _a.label = 1;
549
317
  case 1:
550
318
  _a.trys.push([1, 3, , 4]);
551
- baseUrl = BLOCKBOOK_URLS[coin.toUpperCase()];
552
- if (!baseUrl) {
553
- throw new Error("Unknown coin '".concat(coin, "' or missing BLOCKBOOK_URLS entry"));
554
- }
555
- url = "".concat(baseUrl, "/api/v2/address/").concat(address);
556
- log.debug(tag, "Fetching address info from:", url);
557
- return [4 /*yield*/, axios({
558
- method: 'GET',
559
- url: url,
560
- headers: {
561
- 'content-type': 'application/json',
562
- 'User-Agent': typeof fakeUa === 'function' ? fakeUa() : 'blockbook-client/1.0'
563
- },
564
- params: {
565
- details: filter,
566
- pageSize: 1000
567
- }
568
- })];
319
+ if (!filter)
320
+ filter = "all";
321
+ //let url = ETH_BLOCKBOOK_URL+"/api/v2/address/"+address+"?="+filter
322
+ if (!BLOCKBOOK_URLS[coin.toUpperCase()])
323
+ throw Error("invalid coin: " + coin);
324
+ url = BLOCKBOOK_URLS[coin.toUpperCase()] + "/api/v2/address/" + address + "?details=all";
325
+ body = {
326
+ method: 'GET',
327
+ url: url,
328
+ headers: {
329
+ 'content-type': 'application/json',
330
+ 'User-Agent': fakeUa()
331
+ },
332
+ };
333
+ return [4 /*yield*/, axios(body)
334
+ //TODO paginate?
335
+ ];
569
336
  case 2:
570
337
  resp = _a.sent();
338
+ //TODO paginate?
571
339
  return [2 /*return*/, resp.data];
572
340
  case 3:
573
341
  e_5 = _a.sent();
574
- log.error(tag, "Failed to get info for address ".concat(address, ":"), e_5);
342
+ console.error(tag, e_5);
575
343
  throw e_5;
576
344
  case 4: return [2 /*return*/];
577
345
  }
578
346
  });
579
347
  });
580
- }
581
- /**
582
- * Get all transactions for an extended public key
583
- * @param coin Coin symbol
584
- * @param xpub Extended public key
585
- * @returns Promise with xpub info including all transactions
586
- */
587
- function get_txs_by_xpub(coin, xpub) {
348
+ };
349
+ var get_txs_by_xpub = function (coin, xpub) {
588
350
  return __awaiter(this, void 0, void 0, function () {
589
- var tag, baseUrl, url, resp, e_6;
351
+ var tag, url, body, resp, e_6;
590
352
  return __generator(this, function (_a) {
591
353
  switch (_a.label) {
592
354
  case 0:
593
- tag = TAG + " | get_txs_by_xpub | ";
355
+ tag = TAG + " | FA get_txs_by_xpub | ";
594
356
  _a.label = 1;
595
357
  case 1:
596
358
  _a.trys.push([1, 3, , 4]);
597
- baseUrl = BLOCKBOOK_URLS[coin.toUpperCase()];
598
- if (!baseUrl) {
599
- throw new Error("Unknown coin '".concat(coin, "' or missing BLOCKBOOK_URLS entry"));
600
- }
601
- url = "".concat(baseUrl, "/api/v2/xpub/").concat(xpub);
602
- log.debug(tag, "Fetching xpub transactions from:", url);
603
- return [4 /*yield*/, axios({
604
- method: 'GET',
605
- url: url,
606
- headers: {
607
- 'content-type': 'application/json',
608
- 'User-Agent': typeof fakeUa === 'function' ? fakeUa() : 'blockbook-client/1.0'
609
- },
610
- params: {
611
- details: 'txs',
612
- tokens: 'derived',
613
- pageSize: 1000
614
- }
615
- })];
359
+ url = BLOCKBOOK_URLS[coin.toUpperCase()] + "/api/v2/xpub/" + xpub + "?details=all";
360
+ body = {
361
+ method: 'GET',
362
+ url: url,
363
+ headers: {
364
+ 'content-type': 'application/json',
365
+ 'User-Agent': fakeUa()
366
+ },
367
+ };
368
+ return [4 /*yield*/, axios(body)];
616
369
  case 2:
617
370
  resp = _a.sent();
618
371
  return [2 /*return*/, resp.data];
619
372
  case 3:
620
373
  e_6 = _a.sent();
621
- log.error(tag, "Failed to get transactions for xpub:", e_6);
374
+ console.error(tag, e_6);
622
375
  throw e_6;
623
376
  case 4: return [2 /*return*/];
624
377
  }
625
378
  });
626
379
  });
627
- }
628
- /**
629
- * Broadcast a raw transaction to the network
630
- * @param coin Coin symbol
631
- * @param hex Raw transaction hex
632
- * @returns Promise with broadcast result including success status and txid or error
633
- */
634
- function broadcast_transaction(coin, hex) {
380
+ };
381
+ var broadcast_transaction = function (coin, hex) {
635
382
  return __awaiter(this, void 0, void 0, function () {
636
- var tag, baseUrl, url, output, resp, e_7, errorMessage, statusCode, e_8;
637
- var _a, _b;
638
- return __generator(this, function (_c) {
639
- switch (_c.label) {
383
+ var tag, url, data, body, output, resp, e_7, errorMessage, statusCode, e_8;
384
+ var _a;
385
+ return __generator(this, function (_b) {
386
+ switch (_b.label) {
640
387
  case 0:
641
388
  tag = TAG + " | broadcast_transaction | ";
642
- _c.label = 1;
389
+ _b.label = 1;
643
390
  case 1:
644
- _c.trys.push([1, 6, , 7]);
645
- baseUrl = BLOCKBOOK_URLS[coin.toUpperCase()];
646
- if (!baseUrl) {
647
- throw new Error("Unknown coin '".concat(coin, "' or missing BLOCKBOOK_URLS entry"));
648
- }
649
- url = "".concat(baseUrl, "/api/v2/sendtx/");
650
- log.debug(tag, "Broadcasting to:", url);
391
+ _b.trys.push([1, 6, , 7]);
392
+ url = BLOCKBOOK_URLS[coin.toUpperCase()] + "/api/v2/sendtx/";
393
+ data = hex;
394
+ body = {
395
+ url: url,
396
+ headers: {
397
+ 'content-type': 'application/json',
398
+ 'User-Agent': fakeUa()
399
+ },
400
+ method: 'POST',
401
+ json: false,
402
+ data: data,
403
+ };
651
404
  output = {
652
405
  success: false
653
406
  };
654
- _c.label = 2;
407
+ resp = void 0;
408
+ _b.label = 2;
655
409
  case 2:
656
- _c.trys.push([2, 4, , 5]);
657
- return [4 /*yield*/, axios({
658
- url: url,
659
- method: 'POST',
660
- headers: {
661
- 'content-type': 'text/plain',
662
- 'User-Agent': typeof fakeUa === 'function' ? fakeUa() : 'blockbook-client/1.0'
663
- },
664
- data: hex,
665
- })];
410
+ _b.trys.push([2, 4, , 5]);
411
+ return [4 /*yield*/, axios(body)];
666
412
  case 3:
667
- resp = _c.sent();
413
+ resp = _b.sent();
414
+ output.resp = resp;
668
415
  output.success = true;
669
- output.txid = ((_a = resp.data) === null || _a === void 0 ? void 0 : _a.result) || resp.data;
670
- output.resp = resp.data;
671
- log.info(tag, "Transaction broadcast successful: ".concat(output.txid));
672
416
  return [3 /*break*/, 5];
673
417
  case 4:
674
- e_7 = _c.sent();
675
- log.error(tag, "Broadcast error:", e_7.message || e_7);
418
+ e_7 = _b.sent();
419
+ log.error(tag, "Broadcast error: ", e_7.message || e_7);
676
420
  errorMessage = 'Unknown error occurred';
677
421
  statusCode = null;
678
422
  if (e_7.response) {
679
423
  statusCode = e_7.response.status;
680
- log.debug(tag, "HTTP Status:", statusCode);
681
- log.debug(tag, "Response headers:", e_7.response.headers);
424
+ log.debug(tag, "HTTP Status: ", statusCode);
425
+ log.debug(tag, "Response headers: ", e_7.response.headers);
682
426
  if (e_7.response.data) {
683
- log.debug(tag, "Response data:", e_7.response.data);
427
+ log.debug(tag, "Response data: ", e_7.response.data);
684
428
  if (e_7.response.data.error) {
685
429
  errorMessage = e_7.response.data.error;
430
+ log.error(tag, "API Error: ", errorMessage);
686
431
  }
687
432
  else if (typeof e_7.response.data === 'string') {
688
433
  errorMessage = e_7.response.data;
@@ -696,10 +441,12 @@ function broadcast_transaction(coin, hex) {
696
441
  }
697
442
  }
698
443
  else if (e_7.request) {
444
+ // Request was made but no response received
699
445
  errorMessage = 'Network error: No response received';
700
- log.debug(tag, "Request config:", (_b = e_7.config) === null || _b === void 0 ? void 0 : _b.url);
446
+ log.debug(tag, "Request config: ", (_a = e_7.config) === null || _a === void 0 ? void 0 : _a.url);
701
447
  }
702
448
  else {
449
+ // Something else happened
703
450
  errorMessage = e_7.message || 'Request setup error';
704
451
  }
705
452
  output.error = errorMessage;
@@ -707,23 +454,17 @@ function broadcast_transaction(coin, hex) {
707
454
  return [3 /*break*/, 5];
708
455
  case 5: return [2 /*return*/, output];
709
456
  case 6:
710
- e_8 = _c.sent();
711
- log.error(tag, 'Unexpected error:', e_8);
457
+ e_8 = _b.sent();
458
+ console.error(tag, 'error: ', e_8);
712
459
  throw e_8;
713
460
  case 7: return [2 /*return*/];
714
461
  }
715
462
  });
716
463
  });
717
- }
718
- /**
719
- * Get detailed information about a specific transaction
720
- * @param coin Coin symbol
721
- * @param txid Transaction ID
722
- * @returns Promise with transaction details
723
- */
724
- function get_transaction(coin, txid) {
464
+ };
465
+ var get_transaction = function (coin, txid) {
725
466
  return __awaiter(this, void 0, void 0, function () {
726
- var tag, cacheKey, cached, baseUrl, url, resp, txData, e_9;
467
+ var tag, url, body, resp, e_9;
727
468
  return __generator(this, function (_a) {
728
469
  switch (_a.label) {
729
470
  case 0:
@@ -731,98 +472,114 @@ function get_transaction(coin, txid) {
731
472
  _a.label = 1;
732
473
  case 1:
733
474
  _a.trys.push([1, 3, , 4]);
734
- cacheKey = "tx:".concat(coin, ":").concat(txid);
735
- cached = getCached(cacheKey);
736
- if (cached) {
737
- log.debug(tag, "Returning cached transaction ".concat(txid));
738
- return [2 /*return*/, cached];
739
- }
740
- baseUrl = BLOCKBOOK_URLS[coin.toUpperCase()];
741
- if (!baseUrl) {
742
- throw new Error("Unknown coin '".concat(coin, "' or missing BLOCKBOOK_URLS entry"));
743
- }
744
- url = "".concat(baseUrl, "/api/v2/tx/").concat(txid);
745
- log.debug(tag, "Fetching transaction from:", url);
746
- return [4 /*yield*/, axios({
747
- method: 'GET',
748
- url: url,
749
- headers: {
750
- 'content-type': 'application/json',
751
- 'User-Agent': typeof fakeUa === 'function' ? fakeUa() : 'blockbook-client/1.0'
752
- },
753
- })];
475
+ url = BLOCKBOOK_URLS[coin.toUpperCase()] + "/api/v2/tx/" + txid;
476
+ console.log("url: ", url);
477
+ body = {
478
+ method: 'GET',
479
+ url: url,
480
+ headers: {
481
+ 'content-type': 'application/json',
482
+ 'User-Agent': fakeUa()
483
+ },
484
+ };
485
+ return [4 /*yield*/, axios(body)];
754
486
  case 2:
755
487
  resp = _a.sent();
756
- txData = resp.data;
757
- // Cache confirmed transactions
758
- if (txData.confirmations > 0) {
759
- setCache(cacheKey, txData);
760
- }
761
- return [2 /*return*/, txData];
488
+ return [2 /*return*/, resp.data];
762
489
  case 3:
763
490
  e_9 = _a.sent();
764
- log.error(tag, "Failed to get transaction ".concat(txid, ":"), e_9);
491
+ console.error(tag, e_9);
765
492
  throw e_9;
766
493
  case 4: return [2 /*return*/];
767
494
  }
768
495
  });
769
496
  });
770
- }
771
- /**
772
- * Get UTXOs (Unspent Transaction Outputs) for an extended public key
773
- * @param coin Coin symbol
774
- * @param xpub Extended public key
775
- * @param confirmedOnly Whether to include only confirmed UTXOs (default false)
776
- * @returns Promise with array of UTXOs
777
- */
778
- function get_utxos_by_xpub(coin_1, xpub_1) {
779
- return __awaiter(this, arguments, void 0, function (coin, xpub, confirmedOnly) {
780
- var tag, baseUrl, url, resp, utxos, e_10;
781
- if (confirmedOnly === void 0) { confirmedOnly = false; }
782
- return __generator(this, function (_a) {
783
- switch (_a.label) {
497
+ };
498
+ var get_utxos_by_xpub = function (coin, xpub) {
499
+ return __awaiter(this, void 0, void 0, function () {
500
+ var tag, baseUrls, results, allUtxos, i, result, utxos, seen, uniqueUtxos, _i, allUtxos_1, utxo, key, url, body, resp, e_10;
501
+ var _this = this;
502
+ var _a;
503
+ return __generator(this, function (_b) {
504
+ switch (_b.label) {
784
505
  case 0:
785
- tag = TAG + " | get_utxos_by_xpub | ";
786
- _a.label = 1;
506
+ tag = TAG + " | FA get_utxos_by_xpub | ";
507
+ _b.label = 1;
787
508
  case 1:
788
- _a.trys.push([1, 3, , 4]);
789
- baseUrl = BLOCKBOOK_URLS[coin.toUpperCase()];
790
- if (!baseUrl) {
791
- throw new Error("Unknown coin '".concat(coin, "' or missing BLOCKBOOK_URLS entry"));
792
- }
793
- url = "".concat(baseUrl, "/api/v2/utxo/").concat(xpub);
794
- log.debug(tag, "Fetching UTXOs from:", url);
795
- return [4 /*yield*/, axios({
796
- method: 'GET',
797
- url: url,
798
- headers: __assign({ 'content-type': 'application/json', 'User-Agent': typeof fakeUa === 'function' ? fakeUa() : 'blockbook-client/1.0' }, (NOW_NODES_API && { 'api-key': NOW_NODES_API })),
799
- params: {
800
- confirmed: confirmedOnly
801
- }
802
- })];
509
+ _b.trys.push([1, 6, , 7]);
510
+ log.info(tag, "get_utxos_by_xpub: ", BLOCKBOOK_URLS);
511
+ baseUrls = BLOCKBOOK_URLS[coin.toUpperCase()];
512
+ if (!Array.isArray(baseUrls)) return [3 /*break*/, 3];
513
+ // Multiple nodes - query each and merge results
514
+ log.info(tag, "Querying ".concat(baseUrls.length, " nodes for ").concat(coin, "..."));
515
+ return [4 /*yield*/, Promise.allSettled(baseUrls.map(function (baseUrl) { return __awaiter(_this, void 0, void 0, function () {
516
+ var url, body, resp;
517
+ return __generator(this, function (_a) {
518
+ switch (_a.label) {
519
+ case 0:
520
+ url = baseUrl + "/api/v2/utxo/" + xpub + "?confirmed=false";
521
+ console.log("Querying node:", url);
522
+ body = {
523
+ method: 'GET',
524
+ url: url,
525
+ };
526
+ return [4 /*yield*/, axios(body)];
527
+ case 1:
528
+ resp = _a.sent();
529
+ return [2 /*return*/, resp.data];
530
+ }
531
+ });
532
+ }); }))];
803
533
  case 2:
804
- resp = _a.sent();
805
- utxos = resp.data;
806
- log.info(tag, "Found ".concat(utxos.length, " UTXOs for xpub"));
807
- return [2 /*return*/, utxos];
534
+ results = _b.sent();
535
+ allUtxos = [];
536
+ for (i = 0; i < results.length; i++) {
537
+ result = results[i];
538
+ if (result.status === 'fulfilled') {
539
+ utxos = result.value;
540
+ log.info(tag, "Node ".concat(i + 1, " returned ").concat(utxos.length, " UTXOs"));
541
+ allUtxos.push.apply(allUtxos, utxos);
542
+ }
543
+ else {
544
+ log.warn(tag, "Node ".concat(i + 1, " failed:"), (_a = result.reason) === null || _a === void 0 ? void 0 : _a.message);
545
+ }
546
+ }
547
+ seen = new Set();
548
+ uniqueUtxos = [];
549
+ for (_i = 0, allUtxos_1 = allUtxos; _i < allUtxos_1.length; _i++) {
550
+ utxo = allUtxos_1[_i];
551
+ key = "".concat(utxo.txid, ":").concat(utxo.vout);
552
+ if (!seen.has(key)) {
553
+ seen.add(key);
554
+ uniqueUtxos.push(utxo);
555
+ }
556
+ }
557
+ log.info(tag, "Returning ".concat(uniqueUtxos.length, " unique UTXOs from ").concat(allUtxos.length, " total"));
558
+ return [2 /*return*/, uniqueUtxos];
808
559
  case 3:
809
- e_10 = _a.sent();
810
- log.error(tag, "Failed to get UTXOs for xpub:", e_10);
560
+ url = baseUrls + "/api/v2/utxo/" + xpub + "?confirmed=false";
561
+ console.log("url:", url);
562
+ body = {
563
+ method: 'GET',
564
+ url: url,
565
+ };
566
+ return [4 /*yield*/, axios(body)];
567
+ case 4:
568
+ resp = _b.sent();
569
+ return [2 /*return*/, resp.data];
570
+ case 5: return [3 /*break*/, 7];
571
+ case 6:
572
+ e_10 = _b.sent();
573
+ console.error(tag, e_10);
811
574
  throw e_10;
812
- case 4: return [2 /*return*/];
575
+ case 7: return [2 /*return*/];
813
576
  }
814
577
  });
815
578
  });
816
- }
817
- /**
818
- * Get total balance for an extended public key in BTC (not satoshis)
819
- * @param coin Coin symbol
820
- * @param xpub Extended public key
821
- * @returns Promise with balance in BTC (not satoshis)
822
- */
823
- function get_balance_by_xpub(coin, xpub) {
579
+ };
580
+ var get_balance_by_xpub = function (coin, xpub) {
824
581
  return __awaiter(this, void 0, void 0, function () {
825
- var tag, utxos, balanceSatoshis, _i, utxos_1, utxo, value, balanceBTC, e_11;
582
+ var tag, output, balance, i, uxto, e_11;
826
583
  return __generator(this, function (_a) {
827
584
  switch (_a.label) {
828
585
  case 0:
@@ -830,53 +587,41 @@ function get_balance_by_xpub(coin, xpub) {
830
587
  _a.label = 1;
831
588
  case 1:
832
589
  _a.trys.push([1, 3, , 4]);
833
- log.debug(tag, "Getting balance for coin:", coin);
834
- log.debug(tag, "xpub:", xpub);
835
- return [4 /*yield*/, get_utxos_by_xpub(coin, xpub, false)];
590
+ log.debug(tag, "coin: ", coin);
591
+ log.debug(tag, "xpub: ", xpub);
592
+ return [4 /*yield*/, get_utxos_by_xpub(coin, xpub)];
836
593
  case 2:
837
- utxos = _a.sent();
838
- log.debug(tag, "Processing ".concat(utxos.length, " UTXOs"));
839
- balanceSatoshis = 0;
840
- for (_i = 0, utxos_1 = utxos; _i < utxos_1.length; _i++) {
841
- utxo = utxos_1[_i];
842
- value = parseInt(utxo.value, 10);
843
- if (!isNaN(value)) {
844
- balanceSatoshis += value;
845
- }
594
+ output = _a.sent();
595
+ log.debug(tag, "output: ", output);
596
+ balance = 0;
597
+ //tally
598
+ for (i = 0; i < output.length; i++) {
599
+ uxto = output[i];
600
+ balance = balance + parseInt(uxto.value);
846
601
  }
847
- balanceBTC = balanceSatoshis / 100000000;
848
- log.info(tag, "Total balance: ".concat(balanceBTC, " BTC (").concat(balanceSatoshis, " satoshis)"));
849
- return [2 /*return*/, balanceBTC];
602
+ return [2 /*return*/, balance / 100000000];
850
603
  case 3:
851
604
  e_11 = _a.sent();
852
- log.error(tag, "Failed to get balance for xpub:", e_11);
605
+ console.error(tag, e_11);
853
606
  throw e_11;
854
607
  case 4: return [2 /*return*/];
855
608
  }
856
609
  });
857
610
  });
858
- }
859
- /**
860
- * Get information about the Blockbook nodes
861
- * @returns Promise with node status information
862
- */
863
- function get_node_info() {
611
+ };
612
+ var get_node_info = function () {
864
613
  return __awaiter(this, void 0, void 0, function () {
865
614
  var tag;
866
615
  return __generator(this, function (_a) {
867
616
  tag = TAG + " | get_node_info | ";
868
617
  try {
869
- return [2 /*return*/, {
870
- initialized: Object.keys(BLOCKBOOK_URLS).length > 0,
871
- availableNodes: Object.keys(BLOCKBOOK_URLS),
872
- activeWebsockets: Object.keys(BLOCKBOOK_SOCKETS),
873
- }];
618
+ return [2 /*return*/, true];
874
619
  }
875
620
  catch (e) {
876
- log.error(tag, "Failed to get node info:", e);
621
+ console.error(tag, e);
877
622
  throw e;
878
623
  }
879
624
  return [2 /*return*/];
880
625
  });
881
626
  });
882
- }
627
+ };