@xdc.org/interaction-detector 1.0.0 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +202 -52
  2. package/dist/checkpoint/checkpoint.d.ts.map +1 -1
  3. package/dist/checkpoint/checkpoint.js +6 -2
  4. package/dist/checkpoint/checkpoint.js.map +1 -1
  5. package/dist/explorer/explorer-client.d.ts.map +1 -1
  6. package/dist/explorer/explorer-client.js +22 -13
  7. package/dist/explorer/explorer-client.js.map +1 -1
  8. package/dist/explorer/rate-limiter.d.ts +15 -3
  9. package/dist/explorer/rate-limiter.d.ts.map +1 -1
  10. package/dist/explorer/rate-limiter.js +15 -3
  11. package/dist/explorer/rate-limiter.js.map +1 -1
  12. package/dist/index.d.ts +2 -0
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +1 -0
  15. package/dist/index.js.map +1 -1
  16. package/dist/rpc/rpc-client.d.ts.map +1 -1
  17. package/dist/rpc/rpc-client.js +13 -9
  18. package/dist/rpc/rpc-client.js.map +1 -1
  19. package/dist/rpc/ws-manager.d.ts +23 -0
  20. package/dist/rpc/ws-manager.d.ts.map +1 -1
  21. package/dist/rpc/ws-manager.js +40 -4
  22. package/dist/rpc/ws-manager.js.map +1 -1
  23. package/dist/scanner/block-scanner.d.ts +14 -4
  24. package/dist/scanner/block-scanner.d.ts.map +1 -1
  25. package/dist/scanner/block-scanner.js +33 -12
  26. package/dist/scanner/block-scanner.js.map +1 -1
  27. package/dist/tracer/call-tree-parser.d.ts +2 -1
  28. package/dist/tracer/call-tree-parser.d.ts.map +1 -1
  29. package/dist/tracer/call-tree-parser.js +9 -5
  30. package/dist/tracer/call-tree-parser.js.map +1 -1
  31. package/dist/utils/address.js +1 -1
  32. package/dist/utils/address.js.map +1 -1
  33. package/dist/utils/format.d.ts +4 -2
  34. package/dist/utils/format.d.ts.map +1 -1
  35. package/dist/utils/format.js +12 -4
  36. package/dist/utils/format.js.map +1 -1
  37. package/dist/watcher/contract-watcher.d.ts +1 -0
  38. package/dist/watcher/contract-watcher.d.ts.map +1 -1
  39. package/dist/watcher/contract-watcher.js +20 -7
  40. package/dist/watcher/contract-watcher.js.map +1 -1
  41. package/dist/watcher/log-poller.d.ts +16 -0
  42. package/dist/watcher/log-poller.d.ts.map +1 -1
  43. package/dist/watcher/log-poller.js +20 -13
  44. package/dist/watcher/log-poller.js.map +1 -1
  45. package/package.json +9 -2
package/README.md CHANGED
@@ -17,9 +17,12 @@ Combines: **events** + **direct calls** + **internal calls** + **transaction tra
17
17
  - [1. ContractWatcher — Real-Time Monitoring](#1-contractwatcher--real-time-monitoring)
18
18
  - [2. BlockScanner — Historical Queries](#2-blockscanner--historical-queries)
19
19
  - [3. TransactionTracer — Deep Transaction Analysis](#3-transactiontracer--deep-transaction-analysis)
20
+ - [LogPoller — Standalone Log Fetching](#logpoller--standalone-log-fetching)
20
21
  - [Explorer API Client](#explorer-api-client)
21
22
  - [Event Decoder \& ABI Registry](#event-decoder--abi-registry)
22
23
  - [Checkpoint Persistence](#checkpoint-persistence)
24
+ - [Built-in Backends](#built-in-backends)
25
+ - [Custom Backends](#custom-backends)
23
26
  - [Utility Functions](#utility-functions)
24
27
  - [Configuration Reference](#configuration-reference)
25
28
  - [InteractionDetectorConfig (ContractWatcher)](#interactiondetectorconfig-contractwatcher)
@@ -51,17 +54,17 @@ Combines: **events** + **direct calls** + **internal calls** + **transaction tra
51
54
  ## Installation
52
55
 
53
56
  ```bash
54
- npm install xdc-interaction-detector
57
+ npm install @xdc.org/interaction-detector
55
58
  ```
56
59
 
57
- **Dependencies:** `ethers` v6, `axios`, `ws` — all installed automatically.
60
+ **Dependencies:** `ethers` v6, `ws` — all installed automatically. HTTP calls use Node.js native `fetch` (requires Node ≥ 18).
58
61
 
59
62
  ---
60
63
 
61
64
  ## Quick Start
62
65
 
63
66
  ```typescript
64
- import { ContractWatcher } from 'xdc-interaction-detector';
67
+ import { ContractWatcher } from '@xdc.org/interaction-detector';
65
68
 
66
69
  const watcher = new ContractWatcher({
67
70
  // RPC endpoints
@@ -80,8 +83,9 @@ const watcher = new ContractWatcher({
80
83
 
81
84
  // Explorer API — enables direct & internal call detection
82
85
  explorer: {
83
- apiUrl: 'https://xdc.blocksscan.io/api',
84
- apiKey: 'YOUR_API_KEY', // optional — higher rate limits
86
+ apiUrl: 'https://api.etherscan.io/v2/api',
87
+ apiKey: 'YOUR_ETHERSCAN_API_KEY', // optional — higher rate limits
88
+ chainId: 50, // XDC Mainnet
85
89
  rateLimitPerSec: 5,
86
90
  },
87
91
 
@@ -120,7 +124,7 @@ Watches one or more contract addresses for all interactions in real-time using t
120
124
  **Creating a watcher:**
121
125
 
122
126
  ```typescript
123
- import { ContractWatcher } from 'xdc-interaction-detector';
127
+ import { ContractWatcher } from '@xdc.org/interaction-detector';
124
128
 
125
129
  const watcher = new ContractWatcher({
126
130
  // ─── Required ───────────────────────────────────────────
@@ -141,9 +145,9 @@ const watcher = new ContractWatcher({
141
145
 
142
146
  // ─── Optional: Explorer API (direct + internal calls) ───
143
147
  explorer: {
144
- apiUrl: 'https://xdc.blocksscan.io/api',
145
- apiKey: 'YOUR_XDCSCAN_API_KEY', // optional — get higher rate limits
146
- chainId: 50, // required for Etherscan v2
148
+ apiUrl: 'https://api.etherscan.io/v2/api', // Etherscan v2 supports XDC
149
+ apiKey: 'YOUR_ETHERSCAN_API_KEY', // optional — get higher rate limits
150
+ chainId: 50, // XDC Mainnet (required for Etherscan v2)
147
151
  rateLimitPerSec: 5, // default: 5 req/s
148
152
  pollIntervalMs: 60_000, // how often to check explorer (default: 60s)
149
153
  },
@@ -254,7 +258,7 @@ Scans a block range for all events and interactions involving a contract. Automa
254
258
  **Scanning for events:**
255
259
 
256
260
  ```typescript
257
- import { BlockScanner } from 'xdc-interaction-detector';
261
+ import { BlockScanner } from '@xdc.org/interaction-detector';
258
262
 
259
263
  const scanner = new BlockScanner({
260
264
  rpcUrl: 'https://rpc.xinfin.network',
@@ -264,8 +268,9 @@ const scanner = new BlockScanner({
264
268
 
265
269
  // Optional: explorer for direct + internal tx enrichment
266
270
  explorer: {
267
- apiUrl: 'https://xdc.blocksscan.io/api',
268
- apiKey: 'YOUR_API_KEY',
271
+ apiUrl: 'https://api.etherscan.io/v2/api',
272
+ apiKey: 'YOUR_ETHERSCAN_API_KEY',
273
+ chainId: 50,
269
274
  },
270
275
  });
271
276
 
@@ -324,7 +329,7 @@ Traces a single transaction to extract the full execution story: call tree, stat
324
329
  **Full trace:**
325
330
 
326
331
  ```typescript
327
- import { TransactionTracer } from 'xdc-interaction-detector';
332
+ import { TransactionTracer } from '@xdc.org/interaction-detector';
328
333
 
329
334
  const tracer = new TransactionTracer({
330
335
  rpcUrl: 'https://archive-rpc.xinfin.network', // must support debug_traceTransaction
@@ -398,7 +403,7 @@ const { stateDiffs, balanceChanges } = await tracer.traceStateDiffs('0xTxHash');
398
403
  **Call tree utilities:**
399
404
 
400
405
  ```typescript
401
- import { flattenCallTree, findCallsTo, extractInvolvedContracts } from 'xdc-interaction-detector';
406
+ import { flattenCallTree, findCallsTo, extractInvolvedContracts } from '@xdc.org/interaction-detector';
402
407
 
403
408
  // Flatten the nested tree into a linear array
404
409
  const allCalls = flattenCallTree(result.callTree);
@@ -413,19 +418,67 @@ const addresses = extractInvolvedContracts(result.callTree);
413
418
 
414
419
  ---
415
420
 
421
+ ## LogPoller — Standalone Log Fetching
422
+
423
+ The `LogPoller` is used internally by `ContractWatcher` and `BlockScanner`, but is also exported for standalone use when you need direct control over `eth_getLogs` fetching with automatic chunking and concurrency.
424
+
425
+ ```typescript
426
+ import { LogPoller, RpcClient } from '@xdc.org/interaction-detector';
427
+ import type { FetchLogsResult } from '@xdc.org/interaction-detector';
428
+
429
+ const rpc = new RpcClient('https://rpc.xinfin.network');
430
+ const poller = new LogPoller(
431
+ rpc,
432
+ ['0x0000000000000000000000000000000000000088'], // addresses to monitor
433
+ { maxBlockRange: 100, concurrency: 3 }, // optional PollingConfig
434
+ 'info', // optional log level
435
+ );
436
+
437
+ // ── Basic usage — returns RawLog[] ──────────────────────────
438
+ const logs = await poller.fetchLogs(75_000_000, 75_001_000);
439
+ console.log(`Fetched ${logs.length} logs`);
440
+
441
+ // ── With failure tracking — returns FetchLogsResult ─────────
442
+ // Tracks which block ranges failed, so you can retry or alert
443
+ const result: FetchLogsResult = await poller.fetchLogs(75_000_000, 75_001_000, { trackFailures: true });
444
+
445
+ console.log(`Fetched ${result.logs.length} logs`);
446
+ if (result.failedRanges.length > 0) {
447
+ console.warn('Some ranges failed:');
448
+ for (const range of result.failedRanges) {
449
+ console.warn(` blocks ${range.from}–${range.to}: ${range.error}`);
450
+ }
451
+ }
452
+ ```
453
+
454
+ **`FetchLogsResult` type:**
455
+
456
+ ```typescript
457
+ interface FetchLogsResult {
458
+ /** Successfully fetched logs */
459
+ logs: RawLog[];
460
+ /** Block ranges that failed to fetch (data may be missing for these ranges) */
461
+ failedRanges: Array<{ from: number; to: number; error: string }>;
462
+ }
463
+ ```
464
+
465
+ > **Note:** The default `fetchLogs(from, to)` call (without `{ trackFailures: true }`) returns `RawLog[]` directly for backward compatibility. Failed chunks return empty arrays silently — use the `trackFailures` option when you need visibility into partial failures.
466
+
467
+ ---
468
+
416
469
  ## Explorer API Client
417
470
 
418
471
  Standalone Etherscan-compatible API client. Works with XDCScan, Etherscan v2, BSCScan, PolygonScan, and any Etherscan-compatible explorer.
419
472
 
420
473
  ```typescript
421
- import { ExplorerClient } from 'xdc-interaction-detector';
474
+ import { ExplorerClient } from '@xdc.org/interaction-detector';
422
475
 
423
476
  const explorer = new ExplorerClient({
424
- apiUrl: 'https://xdc.blocksscan.io/api', // XDCScan
425
- // apiUrl: 'https://api.etherscan.io/v2/api', // Etherscan v2 (80+ chains)
426
- // apiUrl: 'https://api.bscscan.com/api', // BSCScan
427
- apiKey: 'YOUR_API_KEY', // optional — higher rate limits
428
- chainId: 50, // required for Etherscan v2
477
+ apiUrl: 'https://api.etherscan.io/v2/api', // Etherscan v2 — supports XDC + 80 chains
478
+ // apiUrl: 'https://xdc.blocksscan.io/api', // XDCScan (alternative)
479
+ // apiUrl: 'https://api.bscscan.com/api', // BSCScan
480
+ apiKey: 'YOUR_ETHERSCAN_API_KEY', // optional — higher rate limits
481
+ chainId: 50, // XDC Mainnet (required for Etherscan v2)
429
482
  rateLimitPerSec: 5, // built-in token-bucket rate limiter
430
483
  });
431
484
  ```
@@ -480,13 +533,13 @@ explorer.destroy(); // Cleans up rate limiter timers
480
533
 
481
534
  **Explorer compatibility:**
482
535
 
483
- | Explorer | Base URL | Chain | Free Rate Limit |
484
- | ---------------- | --------------------------------- | ------------------------ | --------------- |
485
- | **XDCScan** | `https://xdc.blocksscan.io/api` | XDC Mainnet (50) | 5 req/s |
486
- | **Etherscan v2** | `https://api.etherscan.io/v2/api` | 80+ chains via `chainId` | 5 req/s |
487
- | **BSCScan** | `https://api.bscscan.com/api` | BSC (56) | 5 req/s |
488
- | **PolygonScan** | `https://api.polygonscan.com/api` | Polygon (137) | 5 req/s |
489
- | **Custom** | Any Etherscan-compatible URL | Any EVM chain | Configurable |
536
+ | Explorer | Base URL | Chain | Free Rate Limit |
537
+ | ------------------- | --------------------------------- | -------------------------------- | --------------- |
538
+ | **Etherscan v2**| `https://api.etherscan.io/v2/api` | XDC (50) + 80 chains via chainId | 5 req/s |
539
+ | **XDCScan** | `https://xdc.blocksscan.io/api` | XDC Mainnet (50) | 5 req/s |
540
+ | **BSCScan** | `https://api.bscscan.com/api` | BSC (56) | 5 req/s |
541
+ | **PolygonScan** | `https://api.polygonscan.com/api` | Polygon (137) | 5 req/s |
542
+ | **Custom** | Any Etherscan-compatible URL | Any EVM chain | Configurable |
490
543
 
491
544
  ---
492
545
 
@@ -495,7 +548,7 @@ explorer.destroy(); // Cleans up rate limiter timers
495
548
  The decoder handles both standard Solidity ABI encoding and XDC's non-standard encoding (where all params are packed into the `data` field).
496
549
 
497
550
  ```typescript
498
- import { AbiRegistry, EventDecoder } from 'xdc-interaction-detector';
551
+ import { AbiRegistry, EventDecoder } from '@xdc.org/interaction-detector';
499
552
 
500
553
  // ── Register ABIs ────────────────────────────────────────────
501
554
  const registry = new AbiRegistry();
@@ -513,8 +566,12 @@ registry.register(
513
566
  // Register from a JSON ABI array
514
567
  registry.register('0xAnotherContract', require('./MyContract.json').abi, 'MyContract');
515
568
 
516
- // Auto-fetch from block explorer (verified contracts only)
517
- const explorer = new ExplorerClient({ apiUrl: 'https://xdc.blocksscan.io/api' });
569
+ // Auto-fetch from block explorer (verified contracts only, requires API key)
570
+ const explorer = new ExplorerClient({
571
+ apiUrl: 'https://api.etherscan.io/v2/api',
572
+ apiKey: 'YOUR_ETHERSCAN_API_KEY',
573
+ chainId: 50,
574
+ });
518
575
  const success = await registry.registerFromExplorer('0xVerifiedContract', explorer, 'VerifiedToken');
519
576
  console.log(success ? 'ABI fetched!' : 'Contract not verified');
520
577
 
@@ -542,36 +599,112 @@ if (decoded) {
542
599
 
543
600
  Checkpoints let the watcher resume from where it left off after a restart.
544
601
 
602
+ | Backend | Storage | Survives Restart? | Best For |
603
+ | -------- | -------------------------------- | ----------------- | ------------------------------ |
604
+ | `memory` | JavaScript `Map` in RAM | ❌ No | Development, testing |
605
+ | `file` | `checkpoints.json` on disk | ✅ Yes | Simple production deployments |
606
+ | `custom` | Your own (Redis, SQL, InfluxDB…) | ✅ Yes | Distributed / production-grade |
607
+
608
+ ### Built-in Backends
609
+
545
610
  ```typescript
546
- import { MemoryCheckpoint, FileCheckpoint, createCheckpointBackend } from 'xdc-interaction-detector';
611
+ import { MemoryCheckpoint, FileCheckpoint, createCheckpointBackend } from '@xdc.org/interaction-detector';
547
612
 
548
613
  // ── Memory (development / testing) ───────────────────────────
614
+ // Stores in RAM only — lost when process stops
549
615
  const memCp = new MemoryCheckpoint();
550
616
  await memCp.save('watcher-key', 75_000_000);
551
617
  await memCp.load('watcher-key'); // 75000000
552
618
 
553
619
  // ── File (simple production) ─────────────────────────────────
620
+ // Auto-creates directory and file on first save
554
621
  const fileCp = new FileCheckpoint('./checkpoints');
555
622
  await fileCp.save('watcher-key', 75_000_000);
556
- // Persists to ./checkpoints/checkpoints.json
623
+ // Persists to ./checkpoints/checkpoints.json (relative to process.cwd())
557
624
  // Survives process restarts
558
625
 
559
- // ── Custom backend (bring your own) ──────────────────────────
560
- const customCp = {
561
- async save(key: string, blockNumber: number) {
562
- await redis.set(`checkpoint:${key}`, blockNumber);
626
+ // ── Factory function ─────────────────────────────────────────
627
+ const cp = createCheckpointBackend({ backend: 'file', path: './data' });
628
+ const cp2 = createCheckpointBackend({ backend: 'memory' });
629
+ ```
630
+
631
+ ### Custom Backends
632
+
633
+ Implement the `CheckpointBackend` interface — just two methods:
634
+
635
+ ```typescript
636
+ interface CheckpointBackend {
637
+ save(key: string, blockNumber: number): Promise<void>;
638
+ load(key: string): Promise<number | null>;
639
+ }
640
+ ```
641
+
642
+ **Redis:**
643
+
644
+ ```typescript
645
+ checkpoint: {
646
+ backend: 'custom',
647
+ custom: {
648
+ async save(key: string, blockNumber: number) {
649
+ await redis.set(`checkpoint:${key}`, blockNumber);
650
+ },
651
+ async load(key: string) {
652
+ const val = await redis.get(`checkpoint:${key}`);
653
+ return val ? parseInt(val) : null;
654
+ },
563
655
  },
564
- async load(key: string) {
565
- const val = await redis.get(`checkpoint:${key}`);
566
- return val ? parseInt(val) : null;
656
+ },
657
+ ```
658
+
659
+ **PostgreSQL / MySQL:**
660
+
661
+ ```typescript
662
+ checkpoint: {
663
+ backend: 'custom',
664
+ custom: {
665
+ async save(key: string, blockNumber: number) {
666
+ await pool.query(
667
+ `INSERT INTO checkpoints (key, block_number) VALUES ($1, $2)
668
+ ON CONFLICT (key) DO UPDATE SET block_number = $2`,
669
+ [key, blockNumber],
670
+ );
671
+ },
672
+ async load(key: string) {
673
+ const result = await pool.query(
674
+ 'SELECT block_number FROM checkpoints WHERE key = $1',
675
+ [key],
676
+ );
677
+ return result.rows[0]?.block_number ?? null;
678
+ },
567
679
  },
568
- };
680
+ },
681
+ ```
569
682
 
570
- // ── Factory function ─────────────────────────────────────────
571
- const cp = createCheckpointBackend({ backend: 'file', path: './data' });
572
- const cp2 = createCheckpointBackend({ backend: 'custom', custom: customCp });
683
+ **InfluxDB:**
684
+
685
+ ```typescript
686
+ checkpoint: {
687
+ backend: 'custom',
688
+ custom: {
689
+ async save(key: string, blockNumber: number) {
690
+ await influx.writePoints([{
691
+ measurement: 'checkpoints',
692
+ tags: { key },
693
+ fields: { block_number: blockNumber },
694
+ }]);
695
+ },
696
+ async load(key: string) {
697
+ const result = await influx.query(
698
+ `SELECT LAST(block_number) FROM checkpoints WHERE key = '${key}'`,
699
+ );
700
+ return result[0]?.block_number ?? null;
701
+ },
702
+ },
703
+ },
573
704
  ```
574
705
 
706
+ > **Recommendation:** Use **Redis** or **SQL** for checkpoint storage. InfluxDB is better suited for storing the detected events/interactions as time-series data rather than simple key-value checkpoint state.
707
+
575
708
  ---
576
709
 
577
710
  ## Utility Functions
@@ -585,9 +718,9 @@ import {
585
718
  isAddress, // validate hex address (20 bytes)
586
719
  addressEqual, // compare addresses (case-insensitive, prefix-aware)
587
720
 
588
- // Formatting
721
+ // Formatting (precision-safe for large BigInt values)
589
722
  formatXDC, // bigint wei → '1.23M XDC' / '456.78K XDC'
590
- formatWei, // bigint wei → '1.23M' (generic, no unit)
723
+ formatWei, // bigint wei → '1.23M' (generic, configurable decimals)
591
724
  parseHexOrDecimal, // '0x100' → 256, '256' → 256
592
725
  toHex, // 256 → '0x100'
593
726
  shortAddress, // '0x1234...abcd'
@@ -595,9 +728,21 @@ import {
595
728
 
596
729
  // Logger
597
730
  Logger, // new Logger('MyModule', 'info')
598
- } from 'xdc-interaction-detector';
731
+ } from '@xdc.org/interaction-detector';
732
+ ```
733
+
734
+ **Address normalization behavior:**
735
+
736
+ ```typescript
737
+ normalizeAddress('0xAbCdEf...'); // → '0xabcdef...' (lowercased)
738
+ normalizeAddress('xdcAbCdEf...'); // → '0xabcdef...' (xdc → 0x)
739
+ normalizeAddress(''); // → '0x0000000000000000000000000000000000000000' (zero address)
599
740
  ```
600
741
 
742
+ > **Note:** `normalizeAddress` returns the zero address for empty or falsy inputs, consistent with EVM conventions. This prevents empty strings from propagating as ghost entries in maps and sets.
743
+
744
+ **Formatting precision:** Both `formatXDC` and `formatWei` use bigint arithmetic internally, so large amounts (beyond JavaScript's `Number.MAX_SAFE_INTEGER`) are displayed correctly without loss of precision.
745
+
601
746
  ---
602
747
 
603
748
  ## Configuration Reference
@@ -670,30 +815,33 @@ import {
670
815
 
671
816
  - **Block range limit:** XDC RPC limits `eth_getLogs` to 100 blocks per request. The `LogPoller` and `BlockScanner` automatically chunk requests. Don't set `maxBlockRange` above 100 for XDC.
672
817
 
673
- - **Address prefix:** XDC uses the `xdc` prefix instead of `0x`. All library functions accept both formats. Internally, everything normalizes to lowercase `0x`.
818
+ - **Address prefix:** XDC uses the `xdc` prefix instead of `0x`. All library functions accept both formats. Internally, everything normalizes to lowercase `0x`. Empty/falsy inputs normalize to the zero address (`0x000...000`).
674
819
 
675
820
  - **Tracing:** `debug_traceTransaction` requires an archive node for historical transactions. For monitoring current blocks in real-time, a standard full node works fine.
676
821
 
822
+ - **Atomic checkpoints:** The `FileCheckpoint` backend uses atomic write-then-rename to prevent data corruption on process crash. Checkpoint data is always consistent.
823
+
677
824
  ---
678
825
 
679
826
  ## Architecture
680
827
 
681
828
  ```
682
829
  ┌──────────────────────────────────────────────────────────┐
683
- xdc-interaction-detector
830
+ @xdc.org/interaction-detector
684
831
  │ │
685
832
  │ ┌───────────────────────────────────────────────────┐ │
686
833
  │ │ ContractWatcher (real-time monitoring) │ │
687
834
  │ │ ├── WsManager (WebSocket subscription) │ │
688
- │ │ ├── LogPoller (eth_getLogs fallback) │ │
689
- │ │ ├── ExplorerClient (txlist + txlistinternal)│ │
835
+ │ │ ├── LogPoller* (eth_getLogs fallback) │ │
836
+ │ │ ├── ExplorerClient* (txlist + txlistinternal)│ │
690
837
  │ │ ├── EventDecoder (ABI + XDC fallback) │ │
691
838
  │ │ └── Checkpoint (pluggable persistence) │ │
692
839
  │ └───────────────────────────────────────────────────┘ │
693
840
  │ │
694
841
  │ ┌────────────────────────────────────────────────────┐ │
695
842
  │ │ BlockScanner (historical queries) │ │
696
- │ │ └── ExplorerClient (API adapter) │ │
843
+ │ │ ├── LogPoller* (chunked eth_getLogs) │ │
844
+ │ │ └── ExplorerClient* (API adapter) │ │
697
845
  │ └────────────────────────────────────────────────────┘ │
698
846
  │ │
699
847
  │ ┌────────────────────────────────────────────────────┐ │
@@ -707,6 +855,8 @@ import {
707
855
  │ │ (retry, timeout, │ │ (address normalize, │ │
708
856
  │ │ fallback, WS) │ │ format, logger, cache) │ │
709
857
  │ └────────────────────┘ └───────────────────────────┘ │
858
+ │ │
859
+ │ * = also exported as standalone classes │
710
860
  └──────────────────────────────────────────────────────────┘
711
861
  ```
712
862
 
@@ -755,7 +905,7 @@ npm install
755
905
  # Compile TypeScript
756
906
  npm run build
757
907
 
758
- # Run unit tests (23 tests)
908
+ # Run unit tests (114 tests across 11 test files)
759
909
  npm test
760
910
 
761
911
  # Watch mode (auto-recompile on save)
@@ -1 +1 @@
1
- {"version":3,"file":"checkpoint.d.ts","sourceRoot":"","sources":["../../src/checkpoint/checkpoint.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3D;;GAEG;AACH,qBAAa,gBAAiB,YAAW,iBAAiB;IACxD,OAAO,CAAC,KAAK,CAAkC;IAEzC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrD,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAGhD;AAED;;;GAGG;AACH,qBAAa,cAAe,YAAW,iBAAiB;IACtD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,OAAO,GAAE,MAAwB;IAOvC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMrD,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;YAKjC,QAAQ;CASvB;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,CAAC,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,iBAAiB,CAAA;CAAE,GACtE,iBAAiB,CAanB"}
1
+ {"version":3,"file":"checkpoint.d.ts","sourceRoot":"","sources":["../../src/checkpoint/checkpoint.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3D;;GAEG;AACH,qBAAa,gBAAiB,YAAW,iBAAiB;IACxD,OAAO,CAAC,KAAK,CAAkC;IAEzC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrD,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAGhD;AAED;;;GAGG;AACH,qBAAa,cAAe,YAAW,iBAAiB;IACtD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,OAAO,GAAE,MAAwB;IAOvC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQrD,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;YAKjC,QAAQ;CAWvB;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,CAAC,EAAE;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B,GAAG,iBAAiB,CAapB"}
@@ -30,7 +30,9 @@ export class FileCheckpoint {
30
30
  async save(key, blockNumber) {
31
31
  const data = await this.readFile();
32
32
  data[key] = blockNumber;
33
- fs.writeFileSync(this.filePath, JSON.stringify(data, null, 2));
33
+ const tmpPath = this.filePath + '.tmp';
34
+ fs.writeFileSync(tmpPath, JSON.stringify(data, null, 2));
35
+ fs.renameSync(tmpPath, this.filePath);
34
36
  }
35
37
  async load(key) {
36
38
  const data = await this.readFile();
@@ -43,7 +45,9 @@ export class FileCheckpoint {
43
45
  return JSON.parse(content);
44
46
  }
45
47
  }
46
- catch { /* ignore corrupt file */ }
48
+ catch {
49
+ /* ignore corrupt file */
50
+ }
47
51
  return {};
48
52
  }
49
53
  }
@@ -1 +1 @@
1
- {"version":3,"file":"checkpoint.js","sourceRoot":"","sources":["../../src/checkpoint/checkpoint.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAG7B;;GAEG;AACH,MAAM,OAAO,gBAAgB;IACnB,KAAK,GAAwB,IAAI,GAAG,EAAE,CAAC;IAE/C,KAAK,CAAC,IAAI,CAAC,GAAW,EAAE,WAAmB;QACzC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,GAAW;QACpB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;IACrC,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,cAAc;IACR,QAAQ,CAAS;IAElC,YAAY,UAAkB,eAAe;QAC3C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,GAAW,EAAE,WAAmB;QACzC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QACnC,IAAI,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC;QACxB,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACjE,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,GAAW;QACpB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QACnC,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;IAC3B,CAAC;IAEO,KAAK,CAAC,QAAQ;QACpB,IAAI,CAAC;YACH,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACjC,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBACxD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAC,yBAAyB,CAAC,CAAC;QACrC,OAAO,EAAE,CAAC;IACZ,CAAC;CACF;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB,CACrC,MAAuE;IAEvE,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,gBAAgB,EAAE,CAAC;IAE3C,QAAQ,MAAM,CAAC,OAAO,EAAE,CAAC;QACvB,KAAK,MAAM;YACT,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACzC,KAAK,QAAQ;YACX,IAAI,CAAC,MAAM,CAAC,MAAM;gBAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;YAC9E,OAAO,MAAM,CAAC,MAAM,CAAC;QACvB,KAAK,QAAQ,CAAC;QACd;YACE,OAAO,IAAI,gBAAgB,EAAE,CAAC;IAClC,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"checkpoint.js","sourceRoot":"","sources":["../../src/checkpoint/checkpoint.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAG7B;;GAEG;AACH,MAAM,OAAO,gBAAgB;IACnB,KAAK,GAAwB,IAAI,GAAG,EAAE,CAAC;IAE/C,KAAK,CAAC,IAAI,CAAC,GAAW,EAAE,WAAmB;QACzC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,GAAW;QACpB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;IACrC,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,cAAc;IACR,QAAQ,CAAS;IAElC,YAAY,UAAkB,eAAe;QAC3C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,GAAW,EAAE,WAAmB;QACzC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QACnC,IAAI,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC;QACxB,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC;QACvC,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACzD,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxC,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,GAAW;QACpB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QACnC,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;IAC3B,CAAC;IAEO,KAAK,CAAC,QAAQ;QACpB,IAAI,CAAC;YACH,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACjC,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBACxD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,yBAAyB;QAC3B,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;CACF;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAIvC;IACC,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,gBAAgB,EAAE,CAAC;IAE3C,QAAQ,MAAM,CAAC,OAAO,EAAE,CAAC;QACvB,KAAK,MAAM;YACT,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACzC,KAAK,QAAQ;YACX,IAAI,CAAC,MAAM,CAAC,MAAM;gBAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;YAC9E,OAAO,MAAM,CAAC,MAAM,CAAC;QACvB,KAAK,QAAQ,CAAC;QACd;YACE,OAAO,IAAI,gBAAgB,EAAE,CAAC;IAClC,CAAC;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"explorer-client.d.ts","sourceRoot":"","sources":["../../src/explorer/explorer-client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAEvF,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;gBAE9B,MAAM,EAAE,cAAc,EAAE,QAAQ,CAAC,EAAE,QAAQ;IAQvD;;OAEG;IACG,eAAe,CACnB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;KAAE,GAC1E,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAcjC;;OAEG;IACG,uBAAuB,CAC3B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;KAAE,GAC1E,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAcjC;;OAEG;IACG,2BAA2B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAWjF;;OAEG;IACG,OAAO,CACX,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAClE,OAAO,CAAC,GAAG,EAAE,CAAC;IAgBjB;;OAEG;IACG,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;IAmB5D;;OAEG;IACG,iBAAiB,CACrB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;KAAE,GAC1E,OAAO,CAAC,GAAG,EAAE,CAAC;IAajB;;OAEG;IACG,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAUlD;;OAEG;IACH,OAAO,IAAI,IAAI;YAMD,OAAO;CAoCtB"}
1
+ {"version":3,"file":"explorer-client.d.ts","sourceRoot":"","sources":["../../src/explorer/explorer-client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAEvF,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;gBAE9B,MAAM,EAAE,cAAc,EAAE,QAAQ,CAAC,EAAE,QAAQ;IAevD;;OAEG;IACG,eAAe,CACnB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;KAAE,GAC1E,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAcjC;;OAEG;IACG,uBAAuB,CAC3B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;KAAE,GAC1E,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAcjC;;OAEG;IACG,2BAA2B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAWjF;;OAEG;IACG,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAgBnH;;OAEG;IACG,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;IAmB5D;;OAEG;IACG,iBAAiB,CACrB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;KAAE,GAC1E,OAAO,CAAC,GAAG,EAAE,CAAC;IAajB;;OAEG;IACG,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAUlD;;OAEG;IACH,OAAO,IAAI,IAAI;YAMD,OAAO;CA0CtB"}
@@ -4,7 +4,6 @@
4
4
  * Works with: XDCScan, Etherscan v2, BSCScan, PolygonScan, and any
5
5
  * Etherscan-compatible API by changing the base URL.
6
6
  */
7
- import axios from 'axios';
8
7
  import { Logger } from '../utils/logger.js';
9
8
  import { RateLimiter } from './rate-limiter.js';
10
9
  export class ExplorerClient {
@@ -19,6 +18,10 @@ export class ExplorerClient {
19
18
  this.chainId = config.chainId;
20
19
  this.rateLimiter = new RateLimiter(config.rateLimitPerSec ?? 5);
21
20
  this.logger = new Logger('ExplorerClient', logLevel ?? 'info');
21
+ // Warn if using Etherscan v2 without an API key (required for all endpoints)
22
+ if (this.baseUrl.includes('etherscan.io') && !this.apiKey) {
23
+ this.logger.warn('Etherscan v2 requires an API key. Requests will fail without one. Get a free key at https://etherscan.io/myapikey');
24
+ }
22
25
  }
23
26
  /**
24
27
  * Get external transactions for an address (txlist).
@@ -33,7 +36,7 @@ export class ExplorerClient {
33
36
  sort: options?.sort ?? 'asc',
34
37
  };
35
38
  const results = await this.request(params);
36
- return (results ?? []).map((tx) => ({ ...tx, txType: 'external' }));
39
+ return (results ?? []).map(tx => ({ ...tx, txType: 'external' }));
37
40
  }
38
41
  /**
39
42
  * Get internal transactions for an address (txlistinternal).
@@ -48,7 +51,7 @@ export class ExplorerClient {
48
51
  sort: options?.sort ?? 'asc',
49
52
  };
50
53
  const results = await this.request(params);
51
- return (results ?? []).map((tx) => ({ ...tx, txType: 'internal' }));
54
+ return (results ?? []).map(tx => ({ ...tx, txType: 'internal' }));
52
55
  }
53
56
  /**
54
57
  * Get internal transactions within a specific transaction (txlistinternal by txhash).
@@ -60,7 +63,7 @@ export class ExplorerClient {
60
63
  txhash: txHash,
61
64
  };
62
65
  const results = await this.request(params);
63
- return (results ?? []).map((tx) => ({ ...tx, txType: 'internal' }));
66
+ return (results ?? []).map(tx => ({ ...tx, txType: 'internal' }));
64
67
  }
65
68
  /**
66
69
  * Get event logs for an address (getLogs).
@@ -140,17 +143,23 @@ export class ExplorerClient {
140
143
  params.chainid = String(this.chainId);
141
144
  }
142
145
  try {
143
- const response = await axios.get(this.baseUrl, {
144
- params,
145
- timeout: 15000,
146
+ const queryString = new URLSearchParams(params).toString();
147
+ const url = `${this.baseUrl}?${queryString}`;
148
+ const response = await fetch(url, {
149
+ method: 'GET',
150
+ signal: AbortSignal.timeout(15000),
146
151
  });
147
- const data = response.data;
148
- if (data.status === '0' && data.message === 'No transactions found') {
149
- return [];
152
+ if (!response.ok) {
153
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
150
154
  }
151
- if (data.status === '0' && data.message !== 'No transactions found') {
152
- const msg = data.result || data.message || 'Unknown error';
153
- this.logger.warn(`Explorer API error: ${msg}`);
155
+ const data = (await response.json());
156
+ if (data.status === '0') {
157
+ const msg = (data.message || '').toLowerCase();
158
+ if (msg.includes('no') && (msg.includes('found') || msg.includes('record') || msg.includes('transaction'))) {
159
+ return [];
160
+ }
161
+ const errorMsg = data.result || data.message || 'Unknown error';
162
+ this.logger.warn(`Explorer API error: ${errorMsg}`);
154
163
  return null;
155
164
  }
156
165
  return data.result;
@@ -1 +1 @@
1
- {"version":3,"file":"explorer-client.js","sourceRoot":"","sources":["../../src/explorer/explorer-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"explorer-client.js","sourceRoot":"","sources":["../../src/explorer/explorer-client.ts"],"names":[],"mappings":"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"}
@@ -10,22 +10,34 @@ export declare class RateLimiter {
10
10
  private queue;
11
11
  private drainTimer;
12
12
  /**
13
+ * Initializes the rate limiter with a given requests-per-second cap.
13
14
  * @param maxPerSecond Maximum requests per second (default: 5)
14
15
  */
15
16
  constructor(maxPerSecond?: number);
16
17
  /**
17
- * Acquire a token. Resolves when a request slot is available.
18
+ * Waits until a request slot is available, then consumes one token.
19
+ * If no tokens are available, the caller is queued and resolved later.
18
20
  */
19
21
  acquire(): Promise<void>;
20
22
  /**
21
- * Get the number of queued requests waiting.
23
+ * Returns how many requests are currently waiting in the queue.
22
24
  */
23
25
  get pending(): number;
24
26
  /**
25
- * Destroy the rate limiter and clear timers.
27
+ * Cleans up the rate limiter by clearing the drain timer
28
+ * and resolving all queued requests so nothing is left hanging.
26
29
  */
27
30
  destroy(): void;
31
+ /**
32
+ * Refills tokens based on elapsed time since the last refill,
33
+ * capping at the maximum bucket size.
34
+ */
28
35
  private refill;
36
+ /**
37
+ * Starts a periodic timer that refills tokens and resolves
38
+ * queued requests as slots become available. Stops automatically
39
+ * when the queue is empty.
40
+ */
29
41
  private startDrain;
30
42
  }
31
43
  //# sourceMappingURL=rate-limiter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../src/explorer/rate-limiter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,KAAK,CAAsC;IACnD,OAAO,CAAC,UAAU,CAA+B;IAEjD;;OAEG;gBACS,YAAY,GAAE,MAAU;IAOpC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAe9B;;OAEG;IACH,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED;;OAEG;IACH,OAAO,IAAI,IAAI;IAWf,OAAO,CAAC,MAAM;IAQd,OAAO,CAAC,UAAU;CAkBnB"}
1
+ {"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../src/explorer/rate-limiter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,KAAK,CAAsC;IACnD,OAAO,CAAC,UAAU,CAA+B;IAEjD;;;OAGG;gBACS,YAAY,GAAE,MAAU;IAOpC;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAe9B;;OAEG;IACH,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED;;;OAGG;IACH,OAAO,IAAI,IAAI;IAWf;;;OAGG;IACH,OAAO,CAAC,MAAM;IAQd;;;;OAIG;IACH,OAAO,CAAC,UAAU;CAkBnB"}