@pioneer-platform/blockbook 8.27.2 → 8.27.5
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/CHANGELOG.md +22 -0
- package/lib/index.d.ts +21 -2
- package/lib/index.js +194 -90
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @pioneer-platform/blockbook
|
|
2
2
|
|
|
3
|
+
## 8.27.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- chore: fix: transaction event channel mismatch + add networkId to event payload
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @pioneer-platform/nodes@8.26.2
|
|
10
|
+
|
|
11
|
+
## 8.27.4
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- fix: transaction event channel mismatch + add networkId to event payload
|
|
16
|
+
- Updated dependencies
|
|
17
|
+
- @pioneer-platform/nodes@8.26.1
|
|
18
|
+
|
|
19
|
+
## 8.27.3
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- chore: chore: fix(utxo): calculate change index from used addresses only, not derived addresses
|
|
24
|
+
|
|
3
25
|
## 8.27.2
|
|
4
26
|
|
|
5
27
|
### Patch Changes
|
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
declare const TAG = " | blockbook-client | ";
|
|
2
|
-
declare const Blockbook: any;
|
|
3
2
|
declare const log: any;
|
|
4
3
|
/**
|
|
5
4
|
* Stringify error for single-line logging
|
|
@@ -16,6 +15,7 @@ declare const axiosLib: any;
|
|
|
16
15
|
declare const Axios: any;
|
|
17
16
|
declare const https: any;
|
|
18
17
|
declare const nodes: any;
|
|
18
|
+
declare const utxoCrypto: any;
|
|
19
19
|
declare const axios: any;
|
|
20
20
|
declare let NOW_NODES_API: string | undefined;
|
|
21
21
|
interface NodeConfig {
|
|
@@ -33,8 +33,27 @@ interface CoinNodes {
|
|
|
33
33
|
[symbol: string]: NodeConfig[];
|
|
34
34
|
}
|
|
35
35
|
declare let BLOCKBOOK_NODES: CoinNodes;
|
|
36
|
-
declare let BLOCKBOOK_SOCKETS: any;
|
|
37
36
|
declare let BLOCKBOOK_URLS: any;
|
|
37
|
+
/**
|
|
38
|
+
* Fallback: Derive addresses locally when NowNodes returns 500 for fresh xpubs
|
|
39
|
+
*
|
|
40
|
+
* NowNodes API has a bug where fresh/unused xpubs return "Internal server error" (500)
|
|
41
|
+
* instead of deriving addresses. This fallback derives addresses client-side.
|
|
42
|
+
*
|
|
43
|
+
* @param coin - Coin symbol (BTC, LTC, DOGE, etc.)
|
|
44
|
+
* @param xpub - Extended public key (xpub/ypub/zpub/tpub/upub/vpub)
|
|
45
|
+
* @param gap - Number of addresses to derive (default: 20, matching BIP44 gap limit)
|
|
46
|
+
* @returns Balance object with derived tokens array matching NowNodes format
|
|
47
|
+
*/
|
|
48
|
+
declare const deriveAddressesFromXpub: (coin: string, xpub: string, gap?: number) => Promise<{
|
|
49
|
+
balance: string;
|
|
50
|
+
unconfirmedBalance: string;
|
|
51
|
+
totalReceived: string;
|
|
52
|
+
totalSent: string;
|
|
53
|
+
txs: number;
|
|
54
|
+
usedTokens: number;
|
|
55
|
+
tokens: any[];
|
|
56
|
+
}>;
|
|
38
57
|
declare let add_custom_node: (coin: string, url: string, priority?: number) => boolean;
|
|
39
58
|
declare let remove_node: (coin: string, url: string) => boolean;
|
|
40
59
|
declare let set_node_priority: (coin: string, url: string, priority: number) => boolean;
|
package/lib/index.js
CHANGED
|
@@ -40,7 +40,6 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
40
40
|
}
|
|
41
41
|
};
|
|
42
42
|
var TAG = " | blockbook-client | ";
|
|
43
|
-
var Blockbook = require('blockbook-client').Blockbook;
|
|
44
43
|
var log = require('@pioneer-platform/loggerdog')();
|
|
45
44
|
/**
|
|
46
45
|
* Stringify error for single-line logging
|
|
@@ -108,6 +107,7 @@ var axiosLib = require('axios');
|
|
|
108
107
|
var Axios = axiosLib.default || axiosLib;
|
|
109
108
|
var https = require('https');
|
|
110
109
|
var nodes = require("@pioneer-platform/nodes");
|
|
110
|
+
var utxoCrypto = require('@pioneer-platform/utxo-crypto');
|
|
111
111
|
var axios = Axios.create({
|
|
112
112
|
httpsAgent: new https.Agent({
|
|
113
113
|
rejectUnauthorized: false
|
|
@@ -118,9 +118,105 @@ var axios = Axios.create({
|
|
|
118
118
|
var NOW_NODES_API = process.env['NOW_NODES_API'] || process.env['NOWNODES_API_KEY'];
|
|
119
119
|
// Enhanced node management
|
|
120
120
|
var BLOCKBOOK_NODES = {};
|
|
121
|
-
var BLOCKBOOK_SOCKETS = {};
|
|
122
121
|
// Legacy compatibility - will be populated from BLOCKBOOK_NODES
|
|
123
122
|
var BLOCKBOOK_URLS = {};
|
|
123
|
+
/**
|
|
124
|
+
* Fallback: Derive addresses locally when NowNodes returns 500 for fresh xpubs
|
|
125
|
+
*
|
|
126
|
+
* NowNodes API has a bug where fresh/unused xpubs return "Internal server error" (500)
|
|
127
|
+
* instead of deriving addresses. This fallback derives addresses client-side.
|
|
128
|
+
*
|
|
129
|
+
* @param coin - Coin symbol (BTC, LTC, DOGE, etc.)
|
|
130
|
+
* @param xpub - Extended public key (xpub/ypub/zpub/tpub/upub/vpub)
|
|
131
|
+
* @param gap - Number of addresses to derive (default: 20, matching BIP44 gap limit)
|
|
132
|
+
* @returns Balance object with derived tokens array matching NowNodes format
|
|
133
|
+
*/
|
|
134
|
+
var deriveAddressesFromXpub = function (coin_1, xpub_1) {
|
|
135
|
+
return __awaiter(this, arguments, void 0, function (coin, xpub, gap) {
|
|
136
|
+
var tag, tokens, isZpub, isYpub, isXpub, i, address, path, convertedXpub, pubkey, pubkey, error_1;
|
|
137
|
+
if (gap === void 0) { gap = 20; }
|
|
138
|
+
return __generator(this, function (_a) {
|
|
139
|
+
switch (_a.label) {
|
|
140
|
+
case 0:
|
|
141
|
+
tag = TAG + ' | deriveAddressesFromXpub | ';
|
|
142
|
+
log.info(tag, "Deriving ".concat(gap, " addresses locally for ").concat(coin, " ").concat(xpub.substring(0, 20), "..."));
|
|
143
|
+
tokens = [];
|
|
144
|
+
_a.label = 1;
|
|
145
|
+
case 1:
|
|
146
|
+
_a.trys.push([1, 14, , 15]);
|
|
147
|
+
isZpub = xpub.startsWith('zpub');
|
|
148
|
+
isYpub = xpub.startsWith('ypub');
|
|
149
|
+
isXpub = xpub.startsWith('xpub');
|
|
150
|
+
i = 0;
|
|
151
|
+
_a.label = 2;
|
|
152
|
+
case 2:
|
|
153
|
+
if (!(i < gap)) return [3 /*break*/, 13];
|
|
154
|
+
address = void 0;
|
|
155
|
+
path = void 0;
|
|
156
|
+
if (!isZpub) return [3 /*break*/, 4];
|
|
157
|
+
return [4 /*yield*/, utxoCrypto.generateAddressZpub(xpub, i, false, 'bech32')];
|
|
158
|
+
case 3:
|
|
159
|
+
// Native Segwit (bech32) - m/84'/0'/0'/0/i
|
|
160
|
+
address = _a.sent();
|
|
161
|
+
path = "m/84'/0'/0'/0/".concat(i);
|
|
162
|
+
return [3 /*break*/, 11];
|
|
163
|
+
case 4:
|
|
164
|
+
if (!isYpub) return [3 /*break*/, 8];
|
|
165
|
+
return [4 /*yield*/, utxoCrypto.xpubConvert(xpub, 'xpub')];
|
|
166
|
+
case 5:
|
|
167
|
+
convertedXpub = _a.sent();
|
|
168
|
+
return [4 /*yield*/, utxoCrypto.generatePubkey(convertedXpub, i, false, 'p2sh')];
|
|
169
|
+
case 6:
|
|
170
|
+
pubkey = _a.sent();
|
|
171
|
+
return [4 /*yield*/, utxoCrypto.generateAddress(coin, pubkey, 'legacy')];
|
|
172
|
+
case 7:
|
|
173
|
+
address = _a.sent();
|
|
174
|
+
path = "m/49'/0'/0'/0/".concat(i);
|
|
175
|
+
return [3 /*break*/, 11];
|
|
176
|
+
case 8: return [4 /*yield*/, utxoCrypto.generatePubkey(xpub, i, false, 'legacy')];
|
|
177
|
+
case 9:
|
|
178
|
+
pubkey = _a.sent();
|
|
179
|
+
return [4 /*yield*/, utxoCrypto.generateAddress(coin, pubkey, 'legacy')];
|
|
180
|
+
case 10:
|
|
181
|
+
address = _a.sent();
|
|
182
|
+
path = "m/44'/0'/0'/0/".concat(i);
|
|
183
|
+
_a.label = 11;
|
|
184
|
+
case 11:
|
|
185
|
+
// Match NowNodes token format: { name, path, transfers, decimals, balance }
|
|
186
|
+
tokens.push({
|
|
187
|
+
name: address,
|
|
188
|
+
path: path,
|
|
189
|
+
transfers: 0,
|
|
190
|
+
decimals: 8,
|
|
191
|
+
balance: '0',
|
|
192
|
+
totalReceived: '0',
|
|
193
|
+
totalSent: '0'
|
|
194
|
+
});
|
|
195
|
+
_a.label = 12;
|
|
196
|
+
case 12:
|
|
197
|
+
i++;
|
|
198
|
+
return [3 /*break*/, 2];
|
|
199
|
+
case 13:
|
|
200
|
+
log.info(tag, "\u2705 Derived ".concat(tokens.length, " addresses locally for fresh xpub"));
|
|
201
|
+
// Return in NowNodes format
|
|
202
|
+
return [2 /*return*/, {
|
|
203
|
+
balance: '0',
|
|
204
|
+
unconfirmedBalance: '0',
|
|
205
|
+
totalReceived: '0',
|
|
206
|
+
totalSent: '0',
|
|
207
|
+
txs: 0,
|
|
208
|
+
usedTokens: 0,
|
|
209
|
+
tokens: tokens
|
|
210
|
+
}];
|
|
211
|
+
case 14:
|
|
212
|
+
error_1 = _a.sent();
|
|
213
|
+
log.error(tag, "Failed to derive addresses locally: ".concat(stringifyError(error_1)));
|
|
214
|
+
throw error_1;
|
|
215
|
+
case 15: return [2 /*return*/];
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
};
|
|
124
220
|
module.exports = {
|
|
125
221
|
init: function (servers) {
|
|
126
222
|
return init_network(servers);
|
|
@@ -146,9 +242,6 @@ module.exports = {
|
|
|
146
242
|
getBlockbooks: function () {
|
|
147
243
|
return BLOCKBOOK_URLS;
|
|
148
244
|
},
|
|
149
|
-
getBlockbookSockets: function () {
|
|
150
|
-
return BLOCKBOOK_SOCKETS;
|
|
151
|
-
},
|
|
152
245
|
getFees: function (coin) {
|
|
153
246
|
return get_fees(coin);
|
|
154
247
|
},
|
|
@@ -294,7 +387,7 @@ var update_legacy_urls = function (symbol) {
|
|
|
294
387
|
};
|
|
295
388
|
var init_network = function (servers) {
|
|
296
389
|
return __awaiter(this, void 0, void 0, function () {
|
|
297
|
-
var tag, SEED_NODES, blockbooks, i, blockbook, symbol,
|
|
390
|
+
var tag, SEED_NODES, blockbooks, i, blockbook, symbol, serviceUrl, priority, symbol, nodes_1, e_1;
|
|
298
391
|
return __generator(this, function (_a) {
|
|
299
392
|
switch (_a.label) {
|
|
300
393
|
case 0:
|
|
@@ -328,52 +421,34 @@ var init_network = function (servers) {
|
|
|
328
421
|
console.log('[DEBUG] Processing blockbook', i + 1, '/', blockbooks.length, ':', blockbook.symbol);
|
|
329
422
|
if (blockbook && blockbook.service) {
|
|
330
423
|
symbol = blockbook.symbol.toUpperCase();
|
|
424
|
+
serviceUrl = blockbook.service;
|
|
425
|
+
// CRITICAL FIX: Replace {API_KEY} placeholder with actual API key for NowNodes
|
|
426
|
+
if (serviceUrl.includes('nownodes.io') && serviceUrl.includes('{API_KEY}')) {
|
|
427
|
+
if (NOW_NODES_API) {
|
|
428
|
+
serviceUrl = serviceUrl.replace('{API_KEY}', NOW_NODES_API);
|
|
429
|
+
console.log('[DEBUG] Replaced {API_KEY} in service URL for', blockbook.symbol);
|
|
430
|
+
log.info(tag, "Configured NowNodes HTTP service for ".concat(blockbook.symbol, " with API key"));
|
|
431
|
+
}
|
|
432
|
+
else {
|
|
433
|
+
log.error(tag, "\u26A0\uFE0F CRITICAL: NowNodes service URL contains {API_KEY} but NOW_NODES_API env var is not set for ".concat(blockbook.symbol));
|
|
434
|
+
console.error('[ERROR] Missing NOW_NODES_API environment variable - service will fail!');
|
|
435
|
+
}
|
|
436
|
+
}
|
|
331
437
|
priority = 50;
|
|
332
|
-
if (
|
|
438
|
+
if (serviceUrl.includes('nownodes.io')) {
|
|
333
439
|
priority = 0; // Highest priority for NowNodes (fastest)
|
|
334
440
|
}
|
|
335
|
-
else if (
|
|
441
|
+
else if (serviceUrl.includes('zelcore.io')) {
|
|
336
442
|
priority = 10; // Lower priority for Zelcore (slower)
|
|
337
443
|
}
|
|
338
|
-
else if (
|
|
444
|
+
else if (serviceUrl.includes('shapeshift.com')) {
|
|
339
445
|
priority = 20; // Even lower for ShapeShift
|
|
340
446
|
}
|
|
341
|
-
// Add node with proper priority
|
|
342
|
-
add_custom_node(symbol,
|
|
343
|
-
}
|
|
344
|
-
if (blockbook && blockbook.websocket) {
|
|
345
|
-
wsUrl = blockbook.websocket;
|
|
346
|
-
console.log('[DEBUG] Found WebSocket for', blockbook.symbol, ':', wsUrl);
|
|
347
|
-
// Ensure proper wss:// protocol
|
|
348
|
-
if (!wsUrl.startsWith('wss://') && !wsUrl.startsWith('ws://')) {
|
|
349
|
-
wsUrl = 'wss://' + wsUrl;
|
|
350
|
-
}
|
|
351
|
-
// Append NowNodes API key if needed
|
|
352
|
-
if (wsUrl.includes('nownodes.io') && NOW_NODES_API && !wsUrl.includes(NOW_NODES_API)) {
|
|
353
|
-
// NowNodes format: wss://btc.nownodes.io/wss/API_KEY/websocket
|
|
354
|
-
// Remove any existing /wss/ suffix, then add /wss/API_KEY
|
|
355
|
-
wsUrl = wsUrl.replace(/\/wss\/?$/, ''); // Remove trailing /wss or /wss/
|
|
356
|
-
wsUrl = wsUrl + '/wss/' + NOW_NODES_API;
|
|
357
|
-
console.log('[DEBUG] Added API key to', blockbook.symbol, 'WebSocket');
|
|
358
|
-
log.info(tag, "Configured NowNodes websocket for ".concat(blockbook.symbol, " with API key"));
|
|
359
|
-
}
|
|
360
|
-
// Ensure /websocket suffix (only if not already there)
|
|
361
|
-
if (!wsUrl.endsWith('/websocket')) {
|
|
362
|
-
wsUrl = wsUrl + '/websocket';
|
|
363
|
-
}
|
|
364
|
-
console.log('[DEBUG] Final WebSocket URL for', blockbook.symbol, ':', wsUrl);
|
|
365
|
-
log.info(tag, "WebSocket URL for ".concat(blockbook.symbol, ": ").concat(wsUrl));
|
|
366
|
-
// Use blockbook-client package
|
|
367
|
-
BLOCKBOOK_SOCKETS[blockbook.symbol.toUpperCase()] = new Blockbook({
|
|
368
|
-
nodes: [wsUrl],
|
|
369
|
-
disableTypeValidation: true,
|
|
370
|
-
});
|
|
371
|
-
console.log('[DEBUG] Created Blockbook socket for', blockbook.symbol);
|
|
372
|
-
}
|
|
373
|
-
else {
|
|
374
|
-
console.log('[DEBUG] NO WebSocket for', blockbook.symbol);
|
|
375
|
-
log.info(tag, "no websocket for: ", blockbook.symbol);
|
|
447
|
+
// Add node with proper priority (using the URL with API key replaced)
|
|
448
|
+
add_custom_node(symbol, serviceUrl, priority);
|
|
376
449
|
}
|
|
450
|
+
// WebSocket connections are handled by Rust watchtower
|
|
451
|
+
// Pioneer-server ONLY uses Blockbook REST API
|
|
377
452
|
}
|
|
378
453
|
// Log final configuration
|
|
379
454
|
for (symbol in BLOCKBOOK_NODES) {
|
|
@@ -384,7 +459,6 @@ var init_network = function (servers) {
|
|
|
384
459
|
});
|
|
385
460
|
}
|
|
386
461
|
log.debug(tag, "BLOCKBOOK_URLS: ", BLOCKBOOK_URLS);
|
|
387
|
-
log.debug(tag, "BLOCKBOOK_SOCKETS: ", BLOCKBOOK_SOCKETS);
|
|
388
462
|
return [2 /*return*/, true];
|
|
389
463
|
case 3:
|
|
390
464
|
e_1 = _a.sent();
|
|
@@ -435,15 +509,15 @@ var get_fees = function (coin) {
|
|
|
435
509
|
};
|
|
436
510
|
var get_info_by_pubkey = function (coin, pubkey, page) {
|
|
437
511
|
return __awaiter(this, void 0, void 0, function () {
|
|
438
|
-
var tag, symbol, isXpub, url, body, resp, e_3, e_4;
|
|
439
|
-
var _a;
|
|
440
|
-
return __generator(this, function (
|
|
441
|
-
switch (
|
|
512
|
+
var tag, symbol, isXpub, url, addressForApi, body, resp, e_3, derivedBalance, deriveError_1, e_4;
|
|
513
|
+
var _a, _b;
|
|
514
|
+
return __generator(this, function (_c) {
|
|
515
|
+
switch (_c.label) {
|
|
442
516
|
case 0:
|
|
443
517
|
tag = TAG + " | get_info_by_pubkey | ";
|
|
444
|
-
|
|
518
|
+
_c.label = 1;
|
|
445
519
|
case 1:
|
|
446
|
-
|
|
520
|
+
_c.trys.push([1, 10, , 11]);
|
|
447
521
|
if (!page)
|
|
448
522
|
page = "1";
|
|
449
523
|
symbol = coin.toUpperCase();
|
|
@@ -472,9 +546,13 @@ var get_info_by_pubkey = function (coin, pubkey, page) {
|
|
|
472
546
|
log.debug(tag, "Using xpub endpoint for ".concat(pubkey.substring(0, 20), "..."));
|
|
473
547
|
}
|
|
474
548
|
else {
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
549
|
+
addressForApi = pubkey;
|
|
550
|
+
if (coin.toUpperCase() === 'BCH' && (pubkey.startsWith('q') || pubkey.startsWith('p'))) {
|
|
551
|
+
addressForApi = "bitcoincash:".concat(pubkey);
|
|
552
|
+
log.debug(tag, "Adding bitcoincash: prefix for BCH CashAddr: ".concat(addressForApi));
|
|
553
|
+
}
|
|
554
|
+
url = BLOCKBOOK_URLS[symbol] + "/api/v2/address/" + addressForApi + "?details=txs&page=" + page;
|
|
555
|
+
log.debug(tag, "Using address endpoint for ".concat(addressForApi));
|
|
478
556
|
}
|
|
479
557
|
log.debug(tag, "url: ", url);
|
|
480
558
|
body = {
|
|
@@ -486,15 +564,15 @@ var get_info_by_pubkey = function (coin, pubkey, page) {
|
|
|
486
564
|
},
|
|
487
565
|
};
|
|
488
566
|
resp = void 0;
|
|
489
|
-
|
|
567
|
+
_c.label = 2;
|
|
490
568
|
case 2:
|
|
491
|
-
|
|
569
|
+
_c.trys.push([2, 4, , 9]);
|
|
492
570
|
return [4 /*yield*/, axios(body)];
|
|
493
571
|
case 3:
|
|
494
|
-
resp =
|
|
495
|
-
return [3 /*break*/,
|
|
572
|
+
resp = _c.sent();
|
|
573
|
+
return [3 /*break*/, 9];
|
|
496
574
|
case 4:
|
|
497
|
-
e_3 =
|
|
575
|
+
e_3 = _c.sent();
|
|
498
576
|
// Handle 404 - pubkey doesn't exist on chain yet (no transactions)
|
|
499
577
|
if (((_a = e_3.response) === null || _a === void 0 ? void 0 : _a.status) === 404 || e_3.status === 404) {
|
|
500
578
|
log.debug(tag, "Pubkey not found (404) for ".concat(coin, " - treating as zero balance"));
|
|
@@ -508,10 +586,26 @@ var get_info_by_pubkey = function (coin, pubkey, page) {
|
|
|
508
586
|
tokens: []
|
|
509
587
|
}];
|
|
510
588
|
}
|
|
511
|
-
|
|
589
|
+
if (!((((_b = e_3.response) === null || _b === void 0 ? void 0 : _b.status) === 500 || e_3.status === 500) && isXpub)) return [3 /*break*/, 8];
|
|
590
|
+
log.warn(tag, "\u26A0\uFE0F NowNodes returned 500 for ".concat(coin, " xpub - falling back to local derivation"));
|
|
591
|
+
log.warn(tag, "This is a known NowNodes bug with fresh/unused xpubs");
|
|
592
|
+
_c.label = 5;
|
|
593
|
+
case 5:
|
|
594
|
+
_c.trys.push([5, 7, , 8]);
|
|
595
|
+
return [4 /*yield*/, deriveAddressesFromXpub(symbol, pubkey, 20)];
|
|
596
|
+
case 6:
|
|
597
|
+
derivedBalance = _c.sent();
|
|
598
|
+
log.info(tag, "\u2705 Successfully derived ".concat(derivedBalance.tokens.length, " addresses locally"));
|
|
599
|
+
return [2 /*return*/, derivedBalance];
|
|
600
|
+
case 7:
|
|
601
|
+
deriveError_1 = _c.sent();
|
|
602
|
+
log.error(tag, "Failed to derive addresses locally: ".concat(stringifyError(deriveError_1)));
|
|
603
|
+
return [3 /*break*/, 8];
|
|
604
|
+
case 8:
|
|
605
|
+
// Log detailed error information for other errors
|
|
512
606
|
log.error(tag, "getPubkeyInfo failed for ".concat(coin, ": ").concat(stringifyError(e_3)));
|
|
513
607
|
throw e_3;
|
|
514
|
-
case
|
|
608
|
+
case 9:
|
|
515
609
|
log.debug(tag, "resp: ", resp);
|
|
516
610
|
// Normalize response format based on endpoint type
|
|
517
611
|
if (isXpub) {
|
|
@@ -535,18 +629,18 @@ var get_info_by_pubkey = function (coin, pubkey, page) {
|
|
|
535
629
|
}
|
|
536
630
|
}
|
|
537
631
|
return [2 /*return*/, resp.data];
|
|
538
|
-
case
|
|
539
|
-
e_4 =
|
|
632
|
+
case 10:
|
|
633
|
+
e_4 = _c.sent();
|
|
540
634
|
log.error(tag, stringifyError(e_4));
|
|
541
635
|
throw e_4;
|
|
542
|
-
case
|
|
636
|
+
case 11: return [2 /*return*/];
|
|
543
637
|
}
|
|
544
638
|
});
|
|
545
639
|
});
|
|
546
640
|
};
|
|
547
641
|
var get_txids_by_address = function (coin, address, page) {
|
|
548
642
|
return __awaiter(this, void 0, void 0, function () {
|
|
549
|
-
var tag, url, body, resp, e_5;
|
|
643
|
+
var tag, addressForApi, url, body, resp, e_5;
|
|
550
644
|
return __generator(this, function (_a) {
|
|
551
645
|
switch (_a.label) {
|
|
552
646
|
case 0:
|
|
@@ -556,7 +650,12 @@ var get_txids_by_address = function (coin, address, page) {
|
|
|
556
650
|
_a.trys.push([1, 3, , 4]);
|
|
557
651
|
if (!page)
|
|
558
652
|
page = 1;
|
|
559
|
-
|
|
653
|
+
addressForApi = address;
|
|
654
|
+
if (coin.toUpperCase() === 'BCH' && (address.startsWith('q') || address.startsWith('p'))) {
|
|
655
|
+
addressForApi = "bitcoincash:".concat(address);
|
|
656
|
+
log.debug(tag, "Adding bitcoincash: prefix for BCH CashAddr: ".concat(addressForApi));
|
|
657
|
+
}
|
|
658
|
+
url = BLOCKBOOK_URLS[coin.toUpperCase()] + "/api/v2/address/" + addressForApi + "?page=" + page + "&details=all";
|
|
560
659
|
log.debug(tag, "url: ", url);
|
|
561
660
|
body = {
|
|
562
661
|
method: 'GET',
|
|
@@ -584,7 +683,7 @@ var get_txids_by_address = function (coin, address, page) {
|
|
|
584
683
|
};
|
|
585
684
|
var get_info_by_address = function (coin, address, filter, options) {
|
|
586
685
|
return __awaiter(this, void 0, void 0, function () {
|
|
587
|
-
var tag, url, params, body, resp, e_6;
|
|
686
|
+
var tag, addressForApi, url, params, body, resp, e_6;
|
|
588
687
|
return __generator(this, function (_a) {
|
|
589
688
|
switch (_a.label) {
|
|
590
689
|
case 0:
|
|
@@ -596,7 +695,12 @@ var get_info_by_address = function (coin, address, filter, options) {
|
|
|
596
695
|
filter = "all";
|
|
597
696
|
if (!BLOCKBOOK_URLS[coin.toUpperCase()])
|
|
598
697
|
throw Error("invalid coin: " + coin);
|
|
599
|
-
|
|
698
|
+
addressForApi = address;
|
|
699
|
+
if (coin.toUpperCase() === 'BCH' && (address.startsWith('q') || address.startsWith('p'))) {
|
|
700
|
+
addressForApi = "bitcoincash:".concat(address);
|
|
701
|
+
log.debug(tag, "Adding bitcoincash: prefix for BCH CashAddr: ".concat(addressForApi));
|
|
702
|
+
}
|
|
703
|
+
url = BLOCKBOOK_URLS[coin.toUpperCase()] + "/api/v2/address/" + addressForApi;
|
|
600
704
|
params = [];
|
|
601
705
|
if (filter === 'txs' || filter === 'all') {
|
|
602
706
|
params.push('details=txs');
|
|
@@ -696,7 +800,7 @@ var broadcast_transaction = function (coin, hex) {
|
|
|
696
800
|
if (!(retry < MAX_RETRIES)) return [3 /*break*/, 9];
|
|
697
801
|
log.info(tag, "Broadcast attempt ".concat(retry + 1, "/").concat(MAX_RETRIES));
|
|
698
802
|
_loop_1 = function (i) {
|
|
699
|
-
var node, startTime, url, body, resp, responseTime, txid,
|
|
803
|
+
var node, startTime, url, body, resp, responseTime, txid, error_2, responseTime, errorMessage_1, statusCode, isNodeFailure, txValidationErrors, attemptInfo;
|
|
700
804
|
return __generator(this, function (_d) {
|
|
701
805
|
switch (_d.label) {
|
|
702
806
|
case 0:
|
|
@@ -730,26 +834,26 @@ var broadcast_transaction = function (coin, hex) {
|
|
|
730
834
|
txid: txid
|
|
731
835
|
} }];
|
|
732
836
|
case 3:
|
|
733
|
-
|
|
837
|
+
error_2 = _d.sent();
|
|
734
838
|
responseTime = Date.now() - startTime;
|
|
735
839
|
errorMessage_1 = 'Unknown error occurred';
|
|
736
840
|
statusCode = null;
|
|
737
841
|
isNodeFailure = true;
|
|
738
|
-
if (
|
|
739
|
-
statusCode =
|
|
842
|
+
if (error_2.response) {
|
|
843
|
+
statusCode = error_2.response.status;
|
|
740
844
|
log.error(tag, "Node ".concat(i + 1, " HTTP Status: "), statusCode);
|
|
741
|
-
log.error(tag, "Node ".concat(i + 1, " Response headers: "),
|
|
742
|
-
if (
|
|
743
|
-
log.error(tag, "Node ".concat(i + 1, " Response data: "),
|
|
744
|
-
if (
|
|
745
|
-
errorMessage_1 =
|
|
845
|
+
log.error(tag, "Node ".concat(i + 1, " Response headers: "), error_2.response.headers);
|
|
846
|
+
if (error_2.response.data) {
|
|
847
|
+
log.error(tag, "Node ".concat(i + 1, " Response data: "), error_2.response.data);
|
|
848
|
+
if (error_2.response.data.error) {
|
|
849
|
+
errorMessage_1 = error_2.response.data.error;
|
|
746
850
|
}
|
|
747
|
-
else if (typeof
|
|
748
|
-
errorMessage_1 =
|
|
851
|
+
else if (typeof error_2.response.data === 'string') {
|
|
852
|
+
errorMessage_1 = error_2.response.data;
|
|
749
853
|
}
|
|
750
854
|
else {
|
|
751
|
-
errorMessage_1 = "HTTP ".concat(statusCode, ": ").concat(
|
|
752
|
-
log.error(tag, "Node ".concat(i + 1, " Full response object: "), JSON.stringify(
|
|
855
|
+
errorMessage_1 = "HTTP ".concat(statusCode, ": ").concat(error_2.response.statusText || 'Request failed');
|
|
856
|
+
log.error(tag, "Node ".concat(i + 1, " Full response object: "), JSON.stringify(error_2.response.data));
|
|
753
857
|
}
|
|
754
858
|
txValidationErrors = [
|
|
755
859
|
'min relay fee',
|
|
@@ -768,15 +872,15 @@ var broadcast_transaction = function (coin, hex) {
|
|
|
768
872
|
}
|
|
769
873
|
}
|
|
770
874
|
else {
|
|
771
|
-
errorMessage_1 = "HTTP ".concat(statusCode, ": ").concat(
|
|
875
|
+
errorMessage_1 = "HTTP ".concat(statusCode, ": ").concat(error_2.response.statusText || 'Request failed');
|
|
772
876
|
}
|
|
773
877
|
}
|
|
774
|
-
else if (
|
|
878
|
+
else if (error_2.request) {
|
|
775
879
|
errorMessage_1 = 'Network error: No response received';
|
|
776
|
-
log.error(tag, "Node ".concat(i + 1, " Request config: "), (_b =
|
|
880
|
+
log.error(tag, "Node ".concat(i + 1, " Request config: "), (_b = error_2.config) === null || _b === void 0 ? void 0 : _b.url);
|
|
777
881
|
}
|
|
778
882
|
else {
|
|
779
|
-
errorMessage_1 =
|
|
883
|
+
errorMessage_1 = error_2.message || 'Request setup error';
|
|
780
884
|
}
|
|
781
885
|
// Update node performance metrics ONLY if this was an actual node failure
|
|
782
886
|
// Don't penalize nodes for transaction validation errors
|
|
@@ -865,7 +969,7 @@ var get_transaction = function (coin, txid) {
|
|
|
865
969
|
// Enhanced UTXO function with priority-based sequential failover
|
|
866
970
|
var get_utxos_by_xpub = function (coin, xpub) {
|
|
867
971
|
return __awaiter(this, void 0, void 0, function () {
|
|
868
|
-
var tag, symbol, isBitcoin, b58, data, payload, xpubPrefix, convertedData, convertedXpub, nodes_3, activeNodes, i, node, startTime, url, body, resp, responseTime,
|
|
972
|
+
var tag, symbol, isBitcoin, b58, data, payload, xpubPrefix, convertedData, convertedXpub, nodes_3, activeNodes, i, node, startTime, url, body, resp, responseTime, error_3, responseTime, errorMessage, e_10;
|
|
869
973
|
var _a;
|
|
870
974
|
return __generator(this, function (_b) {
|
|
871
975
|
switch (_b.label) {
|
|
@@ -964,18 +1068,18 @@ var get_utxos_by_xpub = function (coin, xpub) {
|
|
|
964
1068
|
// Return both data and the node URL that was used
|
|
965
1069
|
return [2 /*return*/, { data: resp.data, nodeUrl: node.url }];
|
|
966
1070
|
case 5:
|
|
967
|
-
|
|
1071
|
+
error_3 = _b.sent();
|
|
968
1072
|
responseTime = Date.now() - startTime;
|
|
969
1073
|
// Update node performance metrics
|
|
970
1074
|
update_node_performance(symbol, node.url, false, responseTime);
|
|
971
|
-
errorMessage =
|
|
1075
|
+
errorMessage = error_3 instanceof Error ? error_3.message : String(error_3);
|
|
972
1076
|
log.warn(tag, "\u274C Node ".concat(i + 1, " failed after ").concat(responseTime, "ms:"), errorMessage);
|
|
973
1077
|
if (isBitcoin) {
|
|
974
1078
|
log.error(tag, '🔍 [BITCOIN BLOCKBOOK] Node failed with error:', {
|
|
975
1079
|
nodeUrl: node.url,
|
|
976
1080
|
errorMessage: errorMessage,
|
|
977
|
-
errorType:
|
|
978
|
-
fullError:
|
|
1081
|
+
errorType: error_3 instanceof Error ? error_3.constructor.name : typeof error_3,
|
|
1082
|
+
fullError: error_3
|
|
979
1083
|
});
|
|
980
1084
|
}
|
|
981
1085
|
// If this is the last node, throw the error
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pioneer-platform/blockbook",
|
|
3
|
-
"version": "8.27.
|
|
3
|
+
"version": "8.27.5",
|
|
4
4
|
"main": "./lib/index.js",
|
|
5
5
|
"types": "./lib/index.d.ts",
|
|
6
6
|
"scripts": {
|
|
@@ -12,8 +12,9 @@
|
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@pioneer-platform/loggerdog": "^8.11.0",
|
|
15
|
-
"@pioneer-platform/nodes": "^8.26.
|
|
15
|
+
"@pioneer-platform/nodes": "^8.26.2",
|
|
16
16
|
"@pioneer-platform/pioneer-caip": "^9.19.0",
|
|
17
|
+
"@pioneer-platform/utxo-crypto": "^8.11.0",
|
|
17
18
|
"@types/request-promise-native": "^1.0.17",
|
|
18
19
|
"axiom": "^0.1.6",
|
|
19
20
|
"axios": "^1.6.0",
|