@pioneer-platform/blockbook 8.10.0 → 8.11.1

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.
@@ -0,0 +1,347 @@
1
+ # Blockbook API Documentation
2
+
3
+ Comprehensive documentation of Blockbook REST API endpoints relevant to UTXO blockchain operations.
4
+
5
+ ## API Base URL Structure
6
+
7
+ Blockbook servers use the following URL structure:
8
+ ```
9
+ https://{server}/api/v2/{endpoint}
10
+ ```
11
+
12
+ ## Core Endpoints
13
+
14
+ ### 1. XPUB Information (`/api/v2/xpub/{xpub}`)
15
+
16
+ Get extended public key (xpub) information including derived addresses, balances, and transaction history.
17
+
18
+ **Endpoint**: `GET /api/v2/xpub/{xpub}`
19
+
20
+ **Query Parameters**:
21
+
22
+ | Parameter | Type | Values | Default | Description |
23
+ |-----------|------|--------|---------|-------------|
24
+ | `page` | int | ≥0 | 0 | Page number for pagination |
25
+ | `pageSize` | int | 1-1000 | 1000 | Number of transactions per page |
26
+ | `from` | int | block height | 0 | Filter transactions from this block height |
27
+ | `to` | int | block height | 0 | Filter transactions to this block height |
28
+ | `details` | string | `basic`, `tokens`, `tokenBalances`, `txids`, `txslight`, `txs` | `txids` | Level of detail to return |
29
+ | `tokens` | string | `nonzero`, `used`, `derived` | `nonzero` | Which derived addresses to return |
30
+ | `gap` | int | ≥0 | 0 | BIP44 gap limit for address derivation |
31
+ | `secondary` | string | fiat currency | - | Secondary currency for fiat conversion |
32
+
33
+ **Details Parameter Values**:
34
+ - `basic` - Only basic account information (balance, txs count)
35
+ - `tokens` - Basic info + list of derived addresses (tokens array)
36
+ - `tokenBalances` - Basic info + addresses with their balances
37
+ - `txids` - Basic info + addresses + transaction IDs (paginated)
38
+ - `txslight` - Basic info + addresses + light transaction data (paginated)
39
+ - `txs` - Basic info + addresses + full transaction data (paginated)
40
+
41
+ **Tokens Parameter Values** (⚠️ CRITICAL for address index calculation):
42
+ - `nonzero` - **DEFAULT** - Only returns addresses with current non-zero balance
43
+ - `used` - Returns addresses that have been used (had transactions), even if balance is zero now
44
+ - `derived` - Returns ALL derived addresses up to gap limit
45
+
46
+ **Response Structure**:
47
+ ```typescript
48
+ {
49
+ address: string, // The xpub itself
50
+ balance: string, // Current balance in satoshis
51
+ totalReceived: string, // Total ever received
52
+ totalSent: string, // Total ever sent
53
+ unconfirmedBalance: string, // Unconfirmed balance
54
+ unconfirmedTxs: number, // Number of unconfirmed txs
55
+ txs: number, // Total transaction count
56
+ usedTokens: number, // Number of addresses that have been used
57
+ tokens: Array<{
58
+ type: string, // "XPUBAddress" (string, not numeric!)
59
+ name: string, // The derived address
60
+ path: string, // BIP44 path: m/purpose'/coin'/account'/change/index
61
+ transfers: number, // Number of transfers for this address
62
+ decimals: number // Token decimals (8 for BTC)
63
+ }>
64
+ }
65
+ ```
66
+
67
+ **BIP44 Path Format**: `m/purpose'/coin_type'/account'/change/address_index`
68
+ - `purpose` - 44 (legacy), 49 (wrapped segwit), 84 (native segwit)
69
+ - `coin_type` - 0 (BTC), 2 (LTC), 3 (DOGE), 5 (DASH), 145 (BCH), etc.
70
+ - `account` - Usually 0
71
+ - `change` - **0 for receive addresses, 1 for change addresses**
72
+ - `address_index` - Sequential index starting from 0
73
+
74
+ **CRITICAL ISSUE**: By default, blockbook uses `tokens=nonzero` which only returns addresses with current balance. For wallets that have spent all their funds, this returns NO addresses even if they have transaction history!
75
+
76
+ **SOLUTION**: Always use `?details=tokens&tokens=used` or `?details=tokens&tokens=derived` to get complete address information.
77
+
78
+ **Example Requests**:
79
+
80
+ ```bash
81
+ # Get basic info only (no addresses)
82
+ GET /api/v2/xpub/{xpub}?details=basic
83
+
84
+ # Get ALL used addresses (RECOMMENDED for address index calculation)
85
+ GET /api/v2/xpub/{xpub}?details=tokens&tokens=used
86
+
87
+ # Get ALL derived addresses up to gap limit
88
+ GET /api/v2/xpub/{xpub}?details=tokens&tokens=derived&gap=20
89
+
90
+ # Get full transaction history with used addresses
91
+ GET /api/v2/xpub/{xpub}?details=txs&tokens=used&page=0&pageSize=50
92
+ ```
93
+
94
+ ### 2. Address Information (`/api/v2/address/{address}`)
95
+
96
+ Get information about a single address.
97
+
98
+ **Endpoint**: `GET /api/v2/address/{address}`
99
+
100
+ **Query Parameters**: Same as xpub endpoint
101
+
102
+ **Response Structure**: Similar to xpub but for single address
103
+
104
+ ### 3. UTXO Query (`/api/v2/utxo/{xpub_or_address}`)
105
+
106
+ Get unspent transaction outputs for an address or xpub.
107
+
108
+ **Endpoint**: `GET /api/v2/utxo/{xpub_or_address}`
109
+
110
+ **Query Parameters**:
111
+
112
+ | Parameter | Type | Values | Default | Description |
113
+ |-----------|------|--------|---------|-------------|
114
+ | `confirmed` | boolean | true/false | false | Return only confirmed UTXOs |
115
+ | `gap` | int | ≥0 | 0 | BIP44 gap limit for xpub derivation |
116
+
117
+ **Response Structure**:
118
+ ```typescript
119
+ Array<{
120
+ txid: string,
121
+ vout: number,
122
+ value: string, // Value in satoshis
123
+ height: number,
124
+ confirmations: number,
125
+ address: string,
126
+ path: string, // BIP44 path (for xpub queries)
127
+ lockTime: number,
128
+ coinbase: boolean
129
+ }>
130
+ ```
131
+
132
+ ### 4. Transaction Query (`/api/v2/tx/{txid}`)
133
+
134
+ Get detailed information about a specific transaction.
135
+
136
+ **Endpoint**: `GET /api/v2/tx/{txid}`
137
+
138
+ **Response**: Full transaction details including inputs, outputs, confirmations
139
+
140
+ ### 5. Fee Estimation (`/api/v2/estimatefee/{blocks}`)
141
+
142
+ Get estimated fee rate for confirmation within specified number of blocks.
143
+
144
+ **Endpoint**: `GET /api/v2/estimatefee/{blocks}`
145
+
146
+ **Example**: `/api/v2/estimatefee/1` (fastest), `/api/v2/estimatefee/6` (average)
147
+
148
+ **Response**:
149
+ ```typescript
150
+ {
151
+ result: string // Fee rate in BTC/kB (or -1 if unavailable)
152
+ }
153
+ ```
154
+
155
+ **Note**: Fee estimation may return `-1` if the node doesn't have enough data. Always have fallback default fees.
156
+
157
+ ### 6. Fee Statistics (`/api/v2/feestats/`)
158
+
159
+ Get comprehensive fee statistics from recent blocks.
160
+
161
+ **Endpoint**: `GET /api/v2/feestats/`
162
+
163
+ **Response**: Detailed fee statistics for different confirmation targets
164
+
165
+ ### 7. Broadcast Transaction (`/api/v2/sendtx/`)
166
+
167
+ Broadcast a signed transaction to the network.
168
+
169
+ **Endpoint**: `POST /api/v2/sendtx/`
170
+
171
+ **Body**: Raw transaction hex (text/plain)
172
+
173
+ **Response**:
174
+ ```typescript
175
+ {
176
+ result: string // Transaction ID (txid) if successful
177
+ }
178
+ ```
179
+
180
+ ### 8. Block Information (`/api/v2/block/{height_or_hash}`)
181
+
182
+ Get information about a specific block.
183
+
184
+ **Endpoint**: `GET /api/v2/block/{height_or_hash}`
185
+
186
+ ### 9. Balance History (`/api/v2/balancehistory/{xpub_or_address}`)
187
+
188
+ Get historical balance data for charting and analytics.
189
+
190
+ **Endpoint**: `GET /api/v2/balancehistory/{xpub_or_address}`
191
+
192
+ **Query Parameters**:
193
+
194
+ | Parameter | Type | Description |
195
+ |-----------|------|-------------|
196
+ | `from` | timestamp | Start time (unix timestamp) |
197
+ | `to` | timestamp | End time (unix timestamp) |
198
+ | `groupBy` | int | Group interval in seconds (default: 3600) |
199
+ | `fiatcurrency` | string | Currency code for fiat conversion |
200
+ | `gap` | int | BIP44 gap limit for xpub |
201
+
202
+ ## Common Issues and Solutions
203
+
204
+ ### Issue 1: Empty `tokens` Array Despite Transaction History
205
+
206
+ **Problem**: Calling `/api/v2/xpub/{xpub}?details=tokens` returns `usedTokens: 0` and empty `tokens: []` array even though `txs: 25`.
207
+
208
+ **Cause**: Default `tokens=nonzero` parameter only returns addresses with current non-zero balance. If wallet has spent all funds, no addresses are returned.
209
+
210
+ **Solution**: Always use `tokens=used` or `tokens=derived`:
211
+ ```bash
212
+ GET /api/v2/xpub/{xpub}?details=tokens&tokens=used
213
+ ```
214
+
215
+ ### Issue 2: Incorrect Change Address Index Calculation
216
+
217
+ **Problem**: Change address index is calculated as 0 when it should be higher.
218
+
219
+ **Cause**: Using the `type` field (which is a string "XPUBAddress") instead of parsing the BIP44 path.
220
+
221
+ **Solution**: Parse the `path` field to determine if address is receive (change=0) or change (change=1):
222
+ ```javascript
223
+ const pathParts = token.path.split('/'); // e.g. "m/44'/0'/0'/1/5"
224
+ const changeIndicator = parseInt(pathParts[3], 10); // 0 = receive, 1 = change
225
+ const addressIndex = parseInt(pathParts[4], 10); // 5
226
+ ```
227
+
228
+ ### Issue 3: Missing Pagination for Large Wallets
229
+
230
+ **Problem**: Only getting first page of transactions for active wallets.
231
+
232
+ **Cause**: Not implementing pagination logic.
233
+
234
+ **Solution**: Check `totalPages` in response and loop through all pages:
235
+ ```javascript
236
+ let page = 0;
237
+ let allTxs = [];
238
+ do {
239
+ const response = await getXpubInfo(xpub, {details: 'txs', page, pageSize: 50});
240
+ allTxs = allTxs.concat(response.transactions);
241
+ page++;
242
+ } while (page < response.totalPages);
243
+ ```
244
+
245
+ ## Performance Considerations
246
+
247
+ ### Node Selection and Failover
248
+
249
+ - NowNodes: Priority 0 (fastest, rate limited)
250
+ - Zelcore: Priority 10 (slower, unlimited)
251
+ - ShapeShift: Priority 20 (slower, public)
252
+
253
+ Implement failover logic to try multiple nodes in priority order.
254
+
255
+ ### Response Time Optimization
256
+
257
+ - Use `details=basic` or `details=tokens` for quick queries (no transaction data)
258
+ - Use `details=txids` instead of `details=txs` when only txids are needed
259
+ - Implement caching for frequently accessed xpubs
260
+ - Use pagination to avoid large responses
261
+
262
+ ### Rate Limiting
263
+
264
+ Public blockbook nodes have rate limits:
265
+ - Implement exponential backoff for retries
266
+ - Distribute requests across multiple nodes
267
+ - Cache responses appropriately
268
+
269
+ ## Integration Best Practices
270
+
271
+ ### 1. Always Request Used Addresses
272
+
273
+ ```javascript
274
+ const xpubInfo = await blockbook.getPubkeyInfo(coin, xpub);
275
+ // Add tokens=used to the URL
276
+ ```
277
+
278
+ ### 2. Parse Paths, Not Type Field
279
+
280
+ ```javascript
281
+ // WRONG - type is a string "XPUBAddress"
282
+ if (token.type === 1) { /* change address */ }
283
+
284
+ // CORRECT - parse the BIP44 path
285
+ const pathParts = token.path.split('/');
286
+ const changeIndicator = parseInt(pathParts[3].replace("'", ""), 10);
287
+ if (changeIndicator === 1) { /* change address */ }
288
+ ```
289
+
290
+ ### 3. Handle Empty Responses
291
+
292
+ ```javascript
293
+ if (!data.tokens || data.tokens.length === 0) {
294
+ if (data.txs > 0) {
295
+ console.warn(`Wallet has ${data.txs} transactions but no address data!`);
296
+ console.warn(`Did you forget tokens=used parameter?`);
297
+ }
298
+ return { changeIndex: 0 }; // Safe fallback
299
+ }
300
+ ```
301
+
302
+ ### 4. Implement Failover Logic
303
+
304
+ ```javascript
305
+ const nodes = ['node1.example.com', 'node2.example.com', 'node3.example.com'];
306
+ for (const node of nodes) {
307
+ try {
308
+ return await fetchFromNode(node, xpub);
309
+ } catch (err) {
310
+ console.error(`Node ${node} failed:`, err);
311
+ continue; // Try next node
312
+ }
313
+ }
314
+ throw new Error('All nodes failed');
315
+ ```
316
+
317
+ ## Migration Guide
318
+
319
+ ### From Current Implementation to Fixed Implementation
320
+
321
+ **Current (Broken)**:
322
+ ```javascript
323
+ // Doesn't request used addresses
324
+ const url = `${BLOCKBOOK_URL}/api/v2/xpub/${xpub}`;
325
+
326
+ // Relies on numeric type field
327
+ if (token.type === 1) { /* change */ }
328
+ ```
329
+
330
+ **Fixed (Working)**:
331
+ ```javascript
332
+ // Requests all used addresses
333
+ const url = `${BLOCKBOOK_URL}/api/v2/xpub/${xpub}?details=tokens&tokens=used`;
334
+
335
+ // Parses BIP44 path correctly
336
+ const pathParts = token.path.split('/');
337
+ const changeIndicator = parseInt(pathParts[3].replace("'", ""), 10);
338
+ if (changeIndicator === 1) { /* change */ }
339
+ ```
340
+
341
+ ## Additional Resources
342
+
343
+ - [Blockbook GitHub Repository](https://github.com/trezor/blockbook)
344
+ - [BIP32 - Hierarchical Deterministic Wallets](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)
345
+ - [BIP44 - Multi-Account Hierarchy](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)
346
+ - [BIP49 - Derivation for P2WPKH-nested-in-P2SH](https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki)
347
+ - [BIP84 - Derivation for P2WPKH](https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki)
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @pioneer-platform/blockbook
2
2
 
3
+ ## 8.11.1
4
+
5
+ ### Patch Changes
6
+
7
+ - cache work
8
+
9
+ ## 8.11.0
10
+
11
+ ### Minor Changes
12
+
13
+ - Automated minor version bump for all packages
14
+
15
+ ### Patch Changes
16
+
17
+ - Updated dependencies
18
+ - @pioneer-platform/loggerdog@8.11.0
19
+ - @pioneer-platform/nodes@8.11.0
20
+ - @pioneer-platform/pioneer-caip@9.10.0
21
+
3
22
  ## 8.10.0
4
23
 
5
24
  ### Minor Changes
package/lib/index.d.ts CHANGED
@@ -36,7 +36,7 @@ declare let init_network: (servers?: any[]) => Promise<boolean>;
36
36
  declare let get_fees: (coin: string) => Promise<any>;
37
37
  declare let get_info_by_pubkey: (coin: string, pubkey: string, page?: string | undefined) => Promise<any>;
38
38
  declare let get_txids_by_address: (coin: string, address: string, page?: number) => Promise<any>;
39
- declare let get_info_by_address: (coin: string, address: string, filter?: string) => Promise<any>;
39
+ declare let get_info_by_address: (coin: string, address: string, filter?: string, options?: any) => Promise<any>;
40
40
  declare let get_txs_by_xpub: (coin: string, xpub: string) => Promise<any>;
41
41
  declare let broadcast_transaction: (coin: string, hex: string) => Promise<{
42
42
  success: boolean;
package/lib/index.js CHANGED
@@ -94,8 +94,8 @@ module.exports = {
94
94
  getTransaction: function (coin, txid) {
95
95
  return get_transaction(coin, txid);
96
96
  },
97
- getAddressInfo: function (coin, address, filter) {
98
- return get_info_by_address(coin, address, filter);
97
+ getAddressInfo: function (coin, address, filter, options) {
98
+ return get_info_by_address(coin, address, filter, options);
99
99
  },
100
100
  getPubkeyInfo: function (coin, pubkey, filter) {
101
101
  return get_info_by_pubkey(coin, pubkey, filter);
@@ -357,7 +357,7 @@ var get_info_by_pubkey = function (coin, pubkey, page) {
357
357
  _a.trys.push([1, 3, , 4]);
358
358
  if (!page)
359
359
  page = "1";
360
- url = BLOCKBOOK_URLS[coin.toUpperCase()] + "/api/v2/xpub/" + pubkey;
360
+ url = BLOCKBOOK_URLS[coin.toUpperCase()] + "/api/v2/xpub/" + pubkey + "?details=tokens&tokens=used&page=" + page;
361
361
  log.debug(tag, "url: ", url);
362
362
  body = {
363
363
  method: 'GET',
@@ -371,7 +371,15 @@ var get_info_by_pubkey = function (coin, pubkey, page) {
371
371
  case 2:
372
372
  resp = _a.sent();
373
373
  log.debug(tag, "resp: ", resp);
374
- //TODO paginate?
374
+ // Validate that we got the tokens array
375
+ if (!resp.data.tokens || !Array.isArray(resp.data.tokens)) {
376
+ log.warn(tag, "\u26A0\uFE0F Blockbook response missing tokens array for ".concat(coin, " xpub ").concat(pubkey.substring(0, 20), "..."));
377
+ log.warn(tag, "Response has ".concat(resp.data.txs || 0, " transactions but no address details"));
378
+ log.warn(tag, "This should not happen with tokens=used parameter!");
379
+ }
380
+ else {
381
+ log.info(tag, "\u2705 Got ".concat(resp.data.tokens.length, " used address tokens for xpub (txs: ").concat(resp.data.txs, ", usedTokens: ").concat(resp.data.usedTokens, ")"));
382
+ }
375
383
  return [2 /*return*/, resp.data];
376
384
  case 3:
377
385
  e_3 = _a.sent();
@@ -420,9 +428,9 @@ var get_txids_by_address = function (coin, address, page) {
420
428
  });
421
429
  });
422
430
  };
423
- var get_info_by_address = function (coin, address, filter) {
431
+ var get_info_by_address = function (coin, address, filter, options) {
424
432
  return __awaiter(this, void 0, void 0, function () {
425
- var tag, url, body, resp, e_5;
433
+ var tag, url, params, body, resp, e_5;
426
434
  return __generator(this, function (_a) {
427
435
  switch (_a.label) {
428
436
  case 0:
@@ -432,10 +440,25 @@ var get_info_by_address = function (coin, address, filter) {
432
440
  _a.trys.push([1, 3, , 4]);
433
441
  if (!filter)
434
442
  filter = "all";
435
- //let url = ETH_BLOCKBOOK_URL+"/api/v2/address/"+address+"?="+filter
436
443
  if (!BLOCKBOOK_URLS[coin.toUpperCase()])
437
444
  throw Error("invalid coin: " + coin);
438
- url = BLOCKBOOK_URLS[coin.toUpperCase()] + "/api/v2/address/" + address + "?details=all";
445
+ url = BLOCKBOOK_URLS[coin.toUpperCase()] + "/api/v2/address/" + address;
446
+ params = [];
447
+ if (filter === 'txs' || filter === 'all') {
448
+ params.push('details=txs');
449
+ }
450
+ else {
451
+ params.push('details=' + filter);
452
+ }
453
+ // Add pagination if provided
454
+ if (options === null || options === void 0 ? void 0 : options.page)
455
+ params.push('page=' + options.page);
456
+ if (options === null || options === void 0 ? void 0 : options.pageSize)
457
+ params.push('pageSize=' + options.pageSize);
458
+ if (params.length > 0) {
459
+ url += '?' + params.join('&');
460
+ }
461
+ log.debug(tag, "Fetching ".concat(coin, " address ").concat(address.substring(0, 10), "... from: ").concat(url));
439
462
  body = {
440
463
  method: 'GET',
441
464
  url: url,
@@ -444,12 +467,9 @@ var get_info_by_address = function (coin, address, filter) {
444
467
  'User-Agent': fakeUa()
445
468
  },
446
469
  };
447
- return [4 /*yield*/, axios(body)
448
- //TODO paginate?
449
- ];
470
+ return [4 /*yield*/, axios(body)];
450
471
  case 2:
451
472
  resp = _a.sent();
452
- //TODO paginate?
453
473
  return [2 /*return*/, resp.data];
454
474
  case 3:
455
475
  e_5 = _a.sent();
@@ -470,7 +490,7 @@ var get_txs_by_xpub = function (coin, xpub) {
470
490
  _a.label = 1;
471
491
  case 1:
472
492
  _a.trys.push([1, 3, , 4]);
473
- url = BLOCKBOOK_URLS[coin.toUpperCase()] + "/api/v2/xpub/" + xpub + "?details=all";
493
+ url = BLOCKBOOK_URLS[coin.toUpperCase()] + "/api/v2/xpub/" + xpub + "?details=txs";
474
494
  body = {
475
495
  method: 'GET',
476
496
  url: url,
@@ -660,16 +680,20 @@ var get_transaction = function (coin, txid) {
660
680
  // Enhanced UTXO function with priority-based sequential failover
661
681
  var get_utxos_by_xpub = function (coin, xpub) {
662
682
  return __awaiter(this, void 0, void 0, function () {
663
- var tag, symbol, nodes_3, activeNodes, i, node, startTime, url, body, resp, responseTime, error_2, responseTime, errorMessage, e_9;
664
- return __generator(this, function (_a) {
665
- switch (_a.label) {
683
+ var tag, symbol, isBitcoin, nodes_3, activeNodes, i, node, startTime, url, body, resp, responseTime, error_2, responseTime, errorMessage, e_9;
684
+ var _a;
685
+ return __generator(this, function (_b) {
686
+ switch (_b.label) {
666
687
  case 0:
667
688
  tag = TAG + " | get_utxos_by_xpub | ";
668
- _a.label = 1;
669
- case 1:
670
- _a.trys.push([1, 8, , 9]);
671
689
  symbol = coin.toUpperCase();
690
+ isBitcoin = symbol === 'BTC';
691
+ _b.label = 1;
692
+ case 1:
693
+ _b.trys.push([1, 8, , 9]);
672
694
  nodes_3 = BLOCKBOOK_NODES[symbol];
695
+ if (isBitcoin)
696
+ log.info(tag, '🔍 [BITCOIN BLOCKBOOK] Starting UTXO query for xpub:', xpub.substring(0, 20) + '...');
673
697
  if (!nodes_3 || nodes_3.length === 0) {
674
698
  throw new Error("No nodes configured for ".concat(symbol));
675
699
  }
@@ -678,37 +702,77 @@ var get_utxos_by_xpub = function (coin, xpub) {
678
702
  throw new Error("No active nodes available for ".concat(symbol));
679
703
  }
680
704
  log.info(tag, "Attempting UTXO query for ".concat(symbol, " with ").concat(activeNodes.length, " nodes available"));
705
+ if (isBitcoin) {
706
+ log.info(tag, '🔍 [BITCOIN BLOCKBOOK] Available nodes:', activeNodes.map(function (n) { return ({
707
+ url: n.url,
708
+ priority: n.priority,
709
+ isActive: n.isActive
710
+ }); }));
711
+ }
681
712
  i = 0;
682
- _a.label = 2;
713
+ _b.label = 2;
683
714
  case 2:
684
715
  if (!(i < activeNodes.length)) return [3 /*break*/, 7];
685
716
  node = activeNodes[i];
686
717
  startTime = Date.now();
687
- _a.label = 3;
718
+ _b.label = 3;
688
719
  case 3:
689
- _a.trys.push([3, 5, , 6]);
720
+ _b.trys.push([3, 5, , 6]);
690
721
  log.info(tag, "Trying node ".concat(i + 1, "/").concat(activeNodes.length, ": ").concat(node.url, " (priority: ").concat(node.priority, ")"));
691
722
  url = node.url + "/api/v2/utxo/" + xpub + "?confirmed=false";
692
723
  body = {
693
724
  method: 'GET',
694
725
  url: url,
726
+ headers: {
727
+ 'content-type': 'application/json',
728
+ 'User-Agent': fakeUa()
729
+ },
695
730
  timeout: 15000 // 15s timeout per node
696
731
  };
732
+ if (isBitcoin) {
733
+ log.info(tag, '🔍 [BITCOIN BLOCKBOOK] Request details:', {
734
+ url: url,
735
+ method: body.method,
736
+ timeout: body.timeout,
737
+ headers: body.headers
738
+ });
739
+ }
697
740
  return [4 /*yield*/, axios(body)];
698
741
  case 4:
699
- resp = _a.sent();
742
+ resp = _b.sent();
700
743
  responseTime = Date.now() - startTime;
744
+ if (isBitcoin) {
745
+ log.info(tag, '🔍 [BITCOIN BLOCKBOOK] Raw API response:', {
746
+ status: resp.status,
747
+ statusText: resp.statusText,
748
+ dataType: typeof resp.data,
749
+ dataIsArray: Array.isArray(resp.data),
750
+ dataLength: (_a = resp.data) === null || _a === void 0 ? void 0 : _a.length,
751
+ data: resp.data
752
+ });
753
+ }
701
754
  // Update node performance metrics
702
755
  update_node_performance(symbol, node.url, true, responseTime);
703
756
  log.info(tag, "\u2705 Node ".concat(i + 1, " succeeded in ").concat(responseTime, "ms, returned ").concat(resp.data.length, " UTXOs"));
757
+ if (isBitcoin) {
758
+ log.info(tag, '🔍 [BITCOIN BLOCKBOOK] Returning UTXOs:', resp.data);
759
+ }
704
760
  return [2 /*return*/, resp.data];
705
761
  case 5:
706
- error_2 = _a.sent();
762
+ error_2 = _b.sent();
707
763
  responseTime = Date.now() - startTime;
708
764
  // Update node performance metrics
709
765
  update_node_performance(symbol, node.url, false, responseTime);
710
766
  errorMessage = error_2 instanceof Error ? error_2.message : String(error_2);
711
767
  log.warn(tag, "\u274C Node ".concat(i + 1, " failed after ").concat(responseTime, "ms:"), errorMessage);
768
+ if (isBitcoin) {
769
+ log.error(tag, '🔍 [BITCOIN BLOCKBOOK] Node failed with error:', {
770
+ nodeUrl: node.url,
771
+ errorMessage: errorMessage,
772
+ errorType: error_2 instanceof Error ? error_2.constructor.name : typeof error_2,
773
+ fullError: error_2
774
+ });
775
+ }
712
776
  // If this is the last node, throw the error
713
777
  if (i === activeNodes.length - 1) {
714
778
  throw new Error("All ".concat(activeNodes.length, " nodes failed for ").concat(symbol, ". Last error: ").concat(errorMessage));
@@ -720,7 +784,10 @@ var get_utxos_by_xpub = function (coin, xpub) {
720
784
  return [3 /*break*/, 2];
721
785
  case 7: return [3 /*break*/, 9];
722
786
  case 8:
723
- e_9 = _a.sent();
787
+ e_9 = _b.sent();
788
+ if (isBitcoin) {
789
+ log.error(tag, '🔍 [BITCOIN BLOCKBOOK] Final error after all nodes failed:', e_9);
790
+ }
724
791
  console.error(tag, e_9);
725
792
  throw e_9;
726
793
  case 9: return [2 /*return*/];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pioneer-platform/blockbook",
3
- "version": "8.10.0",
3
+ "version": "8.11.1",
4
4
  "main": "./lib/index.js",
5
5
  "types": "./lib/index.d.ts",
6
6
  "scripts": {
@@ -11,9 +11,9 @@
11
11
  "build:live": "nodemon --watch 'src/**/*.ts' --exec 'ts-node' src/index.ts"
12
12
  },
13
13
  "dependencies": {
14
- "@pioneer-platform/loggerdog": "^8.10.0",
15
- "@pioneer-platform/nodes": "^8.10.0",
16
- "@pioneer-platform/pioneer-caip": "^9.9.0",
14
+ "@pioneer-platform/loggerdog": "^8.11.0",
15
+ "@pioneer-platform/nodes": "^8.11.10",
16
+ "@pioneer-platform/pioneer-caip": "^9.10.0",
17
17
  "@types/request-promise-native": "^1.0.17",
18
18
  "axiom": "^0.1.6",
19
19
  "axios": "^1.6.0",
@@ -32,4 +32,4 @@
32
32
  ],
33
33
  "author": "highlander",
34
34
  "license": "MIT"
35
- }
35
+ }