@xdc.org/interaction-detector 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +767 -0
- package/dist/checkpoint/checkpoint.d.ts +32 -0
- package/dist/checkpoint/checkpoint.d.ts.map +1 -0
- package/dist/checkpoint/checkpoint.js +68 -0
- package/dist/checkpoint/checkpoint.js.map +1 -0
- package/dist/decoder/abi-registry.d.ts +49 -0
- package/dist/decoder/abi-registry.d.ts.map +1 -0
- package/dist/decoder/abi-registry.js +88 -0
- package/dist/decoder/abi-registry.js.map +1 -0
- package/dist/decoder/event-decoder.d.ts +31 -0
- package/dist/decoder/event-decoder.d.ts.map +1 -0
- package/dist/decoder/event-decoder.js +142 -0
- package/dist/decoder/event-decoder.js.map +1 -0
- package/dist/explorer/explorer-client.d.ts +65 -0
- package/dist/explorer/explorer-client.d.ts.map +1 -0
- package/dist/explorer/explorer-client.js +164 -0
- package/dist/explorer/explorer-client.js.map +1 -0
- package/dist/explorer/rate-limiter.d.ts +31 -0
- package/dist/explorer/rate-limiter.d.ts.map +1 -0
- package/dist/explorer/rate-limiter.js +79 -0
- package/dist/explorer/rate-limiter.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/rpc/rpc-client.d.ts +70 -0
- package/dist/rpc/rpc-client.d.ts.map +1 -0
- package/dist/rpc/rpc-client.js +136 -0
- package/dist/rpc/rpc-client.js.map +1 -0
- package/dist/rpc/ws-manager.d.ts +27 -0
- package/dist/rpc/ws-manager.d.ts.map +1 -0
- package/dist/rpc/ws-manager.js +161 -0
- package/dist/rpc/ws-manager.js.map +1 -0
- package/dist/scanner/block-scanner.d.ts +45 -0
- package/dist/scanner/block-scanner.d.ts.map +1 -0
- package/dist/scanner/block-scanner.js +180 -0
- package/dist/scanner/block-scanner.js.map +1 -0
- package/dist/tracer/call-tree-parser.d.ts +25 -0
- package/dist/tracer/call-tree-parser.d.ts.map +1 -0
- package/dist/tracer/call-tree-parser.js +80 -0
- package/dist/tracer/call-tree-parser.js.map +1 -0
- package/dist/tracer/state-diff-parser.d.ts +13 -0
- package/dist/tracer/state-diff-parser.d.ts.map +1 -0
- package/dist/tracer/state-diff-parser.js +70 -0
- package/dist/tracer/state-diff-parser.js.map +1 -0
- package/dist/tracer/transaction-tracer.d.ts +52 -0
- package/dist/tracer/transaction-tracer.d.ts.map +1 -0
- package/dist/tracer/transaction-tracer.js +107 -0
- package/dist/tracer/transaction-tracer.js.map +1 -0
- package/dist/types/index.d.ts +262 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +8 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/address.d.ts +29 -0
- package/dist/utils/address.d.ts.map +1 -0
- package/dist/utils/address.js +49 -0
- package/dist/utils/address.js.map +1 -0
- package/dist/utils/format.d.ts +20 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +53 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/utils/logger.d.ts +16 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +58 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/watcher/contract-watcher.d.ts +56 -0
- package/dist/watcher/contract-watcher.d.ts.map +1 -0
- package/dist/watcher/contract-watcher.js +353 -0
- package/dist/watcher/contract-watcher.js.map +1 -0
- package/dist/watcher/log-poller.d.ts +24 -0
- package/dist/watcher/log-poller.d.ts.map +1 -0
- package/dist/watcher/log-poller.js +82 -0
- package/dist/watcher/log-poller.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple structured logger — no external dependencies.
|
|
3
|
+
* Supports log levels: debug, info, warn, error, silent.
|
|
4
|
+
*/
|
|
5
|
+
const LEVEL_ORDER = {
|
|
6
|
+
debug: 0,
|
|
7
|
+
info: 1,
|
|
8
|
+
warn: 2,
|
|
9
|
+
error: 3,
|
|
10
|
+
silent: 4,
|
|
11
|
+
};
|
|
12
|
+
const LEVEL_COLORS = {
|
|
13
|
+
debug: '\x1b[90m', // gray
|
|
14
|
+
info: '\x1b[36m', // cyan
|
|
15
|
+
warn: '\x1b[33m', // yellow
|
|
16
|
+
error: '\x1b[31m', // red
|
|
17
|
+
};
|
|
18
|
+
const RESET = '\x1b[0m';
|
|
19
|
+
export class Logger {
|
|
20
|
+
context;
|
|
21
|
+
level;
|
|
22
|
+
constructor(context, level = 'info') {
|
|
23
|
+
this.context = context;
|
|
24
|
+
this.level = LEVEL_ORDER[level];
|
|
25
|
+
}
|
|
26
|
+
debug(message, ...args) {
|
|
27
|
+
if (this.level <= LEVEL_ORDER.debug) {
|
|
28
|
+
this.log('debug', message, ...args);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
info(message, ...args) {
|
|
32
|
+
if (this.level <= LEVEL_ORDER.info) {
|
|
33
|
+
this.log('info', message, ...args);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
warn(message, ...args) {
|
|
37
|
+
if (this.level <= LEVEL_ORDER.warn) {
|
|
38
|
+
this.log('warn', message, ...args);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
error(message, ...args) {
|
|
42
|
+
if (this.level <= LEVEL_ORDER.error) {
|
|
43
|
+
this.log('error', message, ...args);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
log(level, message, ...args) {
|
|
47
|
+
const color = LEVEL_COLORS[level] ?? '';
|
|
48
|
+
const ts = new Date().toISOString().slice(11, 23); // HH:MM:SS.mmm
|
|
49
|
+
const prefix = `${color}[${ts}] [${level.toUpperCase()}] [${this.context}]${RESET}`;
|
|
50
|
+
if (args.length > 0) {
|
|
51
|
+
console.log(prefix, message, ...args);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
console.log(prefix, message);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,WAAW,GAA6B;IAC5C,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;IACR,MAAM,EAAE,CAAC;CACV,CAAC;AAEF,MAAM,YAAY,GAA2B;IAC3C,KAAK,EAAE,UAAU,EAAG,OAAO;IAC3B,IAAI,EAAE,UAAU,EAAI,OAAO;IAC3B,IAAI,EAAE,UAAU,EAAI,SAAS;IAC7B,KAAK,EAAE,UAAU,EAAG,MAAM;CAC3B,CAAC;AAEF,MAAM,KAAK,GAAG,SAAS,CAAC;AAExB,MAAM,OAAO,MAAM;IACA,OAAO,CAAS;IAChB,KAAK,CAAS;IAE/B,YAAY,OAAe,EAAE,QAAkB,MAAM;QACnD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,OAAe,EAAE,GAAG,IAAW;QACnC,IAAI,IAAI,CAAC,KAAK,IAAI,WAAW,CAAC,KAAK,EAAE,CAAC;YACpC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAED,IAAI,CAAC,OAAe,EAAE,GAAG,IAAW;QAClC,IAAI,IAAI,CAAC,KAAK,IAAI,WAAW,CAAC,IAAI,EAAE,CAAC;YACnC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAED,IAAI,CAAC,OAAe,EAAE,GAAG,IAAW;QAClC,IAAI,IAAI,CAAC,KAAK,IAAI,WAAW,CAAC,IAAI,EAAE,CAAC;YACnC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAe,EAAE,GAAG,IAAW;QACnC,IAAI,IAAI,CAAC,KAAK,IAAI,WAAW,CAAC,KAAK,EAAE,CAAC;YACpC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAEO,GAAG,CAAC,KAAa,EAAE,OAAe,EAAE,GAAG,IAAW;QACxD,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACxC,MAAM,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe;QAClE,MAAM,MAAM,GAAG,GAAG,KAAK,IAAI,EAAE,MAAM,KAAK,CAAC,WAAW,EAAE,MAAM,IAAI,CAAC,OAAO,IAAI,KAAK,EAAE,CAAC;QACpF,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;QACxC,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ContractWatcher — Real-time contract interaction monitoring.
|
|
3
|
+
*
|
|
4
|
+
* Combines three detection paths:
|
|
5
|
+
* 1. WebSocket subscription (eth_subscribe("logs")) — real-time push
|
|
6
|
+
* 2. HTTP polling (eth_getLogs) — reliable fallback
|
|
7
|
+
* 3. Explorer API (txlist + txlistinternal) — direct & internal call discovery
|
|
8
|
+
*
|
|
9
|
+
* Deduplication: events are keyed by `txHash-logIndex` to prevent double-counting
|
|
10
|
+
* when both WS and polling detect the same event.
|
|
11
|
+
*
|
|
12
|
+
* EventEmitter API: on('event'), on('interaction'), on('log'), on('connected'),
|
|
13
|
+
* on('disconnected'), on('error'), on('checkpoint').
|
|
14
|
+
*/
|
|
15
|
+
import { EventEmitter } from 'events';
|
|
16
|
+
import type { InteractionDetectorConfig } from '../types/index.js';
|
|
17
|
+
export declare class ContractWatcher extends EventEmitter {
|
|
18
|
+
private readonly logger;
|
|
19
|
+
private readonly logLevel;
|
|
20
|
+
private readonly rpc;
|
|
21
|
+
private readonly addresses;
|
|
22
|
+
private readonly decoder;
|
|
23
|
+
private readonly registry;
|
|
24
|
+
private readonly poller;
|
|
25
|
+
private readonly checkpoint;
|
|
26
|
+
private readonly checkpointKey;
|
|
27
|
+
private readonly pollIntervalMs;
|
|
28
|
+
private readonly explorerPollIntervalMs;
|
|
29
|
+
private wsManager;
|
|
30
|
+
private explorer;
|
|
31
|
+
private pollTimer;
|
|
32
|
+
private explorerTimer;
|
|
33
|
+
private lastProcessedBlock;
|
|
34
|
+
private lastExplorerBlock;
|
|
35
|
+
private seenEventKeys;
|
|
36
|
+
private seenTxHashes;
|
|
37
|
+
private running;
|
|
38
|
+
private blockTimestampCache;
|
|
39
|
+
constructor(config: InteractionDetectorConfig);
|
|
40
|
+
/**
|
|
41
|
+
* Start monitoring. Begins WS subscription + polling loop + optional explorer polling.
|
|
42
|
+
*/
|
|
43
|
+
start(): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Stop monitoring gracefully.
|
|
46
|
+
*/
|
|
47
|
+
stop(): Promise<void>;
|
|
48
|
+
private setupWsHandlers;
|
|
49
|
+
private startPolling;
|
|
50
|
+
private pollCycle;
|
|
51
|
+
private startExplorerPolling;
|
|
52
|
+
private explorerPollCycle;
|
|
53
|
+
private processLog;
|
|
54
|
+
private resolveTimestamp;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=contract-watcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract-watcher.d.ts","sourceRoot":"","sources":["../../src/watcher/contract-watcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAUtC,OAAO,KAAK,EACV,yBAAyB,EAM1B,MAAM,mBAAmB,CAAC;AAO3B,qBAAa,eAAgB,SAAQ,YAAY;IAC/C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAW;IACpC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAY;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAW;IACrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAc;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;IAC/C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAS;IAEhD,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,QAAQ,CAA+B;IAC/C,OAAO,CAAC,SAAS,CAA+B;IAChD,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,kBAAkB,CAAK;IAC/B,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,aAAa,CAA0B;IAC/C,OAAO,CAAC,YAAY,CAA0B;IAC9C,OAAO,CAAC,OAAO,CAAS;IAGxB,OAAO,CAAC,mBAAmB,CAAkC;gBAEjD,MAAM,EAAE,yBAAyB;IAkD7C;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAoC5B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAiC3B,OAAO,CAAC,eAAe;IA0BvB,OAAO,CAAC,YAAY;YAYN,SAAS;IA6CvB,OAAO,CAAC,oBAAoB;YAgBd,iBAAiB;YA8EjB,UAAU;YA+BV,gBAAgB;CAkB/B"}
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ContractWatcher — Real-time contract interaction monitoring.
|
|
3
|
+
*
|
|
4
|
+
* Combines three detection paths:
|
|
5
|
+
* 1. WebSocket subscription (eth_subscribe("logs")) — real-time push
|
|
6
|
+
* 2. HTTP polling (eth_getLogs) — reliable fallback
|
|
7
|
+
* 3. Explorer API (txlist + txlistinternal) — direct & internal call discovery
|
|
8
|
+
*
|
|
9
|
+
* Deduplication: events are keyed by `txHash-logIndex` to prevent double-counting
|
|
10
|
+
* when both WS and polling detect the same event.
|
|
11
|
+
*
|
|
12
|
+
* EventEmitter API: on('event'), on('interaction'), on('log'), on('connected'),
|
|
13
|
+
* on('disconnected'), on('error'), on('checkpoint').
|
|
14
|
+
*/
|
|
15
|
+
import { EventEmitter } from 'events';
|
|
16
|
+
import { Logger } from '../utils/logger.js';
|
|
17
|
+
import { normalizeAddress } from '../utils/address.js';
|
|
18
|
+
import { RpcClient } from '../rpc/rpc-client.js';
|
|
19
|
+
import { WsManager } from '../rpc/ws-manager.js';
|
|
20
|
+
import { LogPoller } from './log-poller.js';
|
|
21
|
+
import { EventDecoder } from '../decoder/event-decoder.js';
|
|
22
|
+
import { AbiRegistry } from '../decoder/abi-registry.js';
|
|
23
|
+
import { ExplorerClient } from '../explorer/explorer-client.js';
|
|
24
|
+
import { createCheckpointBackend } from '../checkpoint/checkpoint.js';
|
|
25
|
+
const POLL_DEFAULTS = {
|
|
26
|
+
intervalMs: 30_000,
|
|
27
|
+
maxBlockRange: 100,
|
|
28
|
+
};
|
|
29
|
+
export class ContractWatcher extends EventEmitter {
|
|
30
|
+
logger;
|
|
31
|
+
logLevel;
|
|
32
|
+
rpc;
|
|
33
|
+
addresses;
|
|
34
|
+
decoder;
|
|
35
|
+
registry;
|
|
36
|
+
poller;
|
|
37
|
+
checkpoint;
|
|
38
|
+
checkpointKey;
|
|
39
|
+
pollIntervalMs;
|
|
40
|
+
explorerPollIntervalMs;
|
|
41
|
+
wsManager = null;
|
|
42
|
+
explorer = null;
|
|
43
|
+
pollTimer = null;
|
|
44
|
+
explorerTimer = null;
|
|
45
|
+
lastProcessedBlock = 0;
|
|
46
|
+
lastExplorerBlock = 0;
|
|
47
|
+
seenEventKeys = new Set();
|
|
48
|
+
seenTxHashes = new Set();
|
|
49
|
+
running = false;
|
|
50
|
+
// Timestamp cache: block number → unix seconds
|
|
51
|
+
blockTimestampCache = new Map();
|
|
52
|
+
constructor(config) {
|
|
53
|
+
super();
|
|
54
|
+
this.logLevel = config.logLevel ?? 'info';
|
|
55
|
+
this.logger = new Logger('ContractWatcher', this.logLevel);
|
|
56
|
+
// Normalize addresses
|
|
57
|
+
this.addresses = config.contracts.map((c) => normalizeAddress(c.address));
|
|
58
|
+
// RPC client
|
|
59
|
+
this.rpc = new RpcClient(config.rpcUrl, {
|
|
60
|
+
fallbackUrls: config.fallbackRpcUrls,
|
|
61
|
+
logLevel: this.logLevel,
|
|
62
|
+
});
|
|
63
|
+
// ABI registry + decoder
|
|
64
|
+
this.registry = new AbiRegistry(this.logLevel);
|
|
65
|
+
for (const contract of config.contracts) {
|
|
66
|
+
if (contract.abi) {
|
|
67
|
+
this.registry.register(contract.address, contract.abi, contract.name);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
this.decoder = new EventDecoder(this.registry, this.logLevel);
|
|
71
|
+
// Log poller
|
|
72
|
+
this.poller = new LogPoller(this.rpc, this.addresses, config.polling, this.logLevel);
|
|
73
|
+
this.pollIntervalMs = config.polling?.intervalMs ?? POLL_DEFAULTS.intervalMs;
|
|
74
|
+
// Checkpoint
|
|
75
|
+
this.checkpoint = createCheckpointBackend(config.checkpoint);
|
|
76
|
+
this.checkpointKey = `watcher-${this.addresses.sort().join('-').slice(0, 60)}`;
|
|
77
|
+
// WebSocket (optional)
|
|
78
|
+
if (config.wsUrl && config.ws?.enabled !== false) {
|
|
79
|
+
this.wsManager = new WsManager(config.wsUrl, config.chainId ?? 50, config.ws, this.logLevel);
|
|
80
|
+
}
|
|
81
|
+
// Explorer (optional)
|
|
82
|
+
if (config.explorer) {
|
|
83
|
+
this.explorer = new ExplorerClient(config.explorer, this.logLevel);
|
|
84
|
+
this.explorerPollIntervalMs = config.explorer.pollIntervalMs ?? 60_000;
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
this.explorerPollIntervalMs = 0;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Start monitoring. Begins WS subscription + polling loop + optional explorer polling.
|
|
92
|
+
*/
|
|
93
|
+
async start() {
|
|
94
|
+
if (this.running)
|
|
95
|
+
return;
|
|
96
|
+
this.running = true;
|
|
97
|
+
this.logger.info(`Starting ContractWatcher for ${this.addresses.length} contract(s)`);
|
|
98
|
+
// Restore checkpoint
|
|
99
|
+
const savedBlock = await this.checkpoint.load(this.checkpointKey);
|
|
100
|
+
if (savedBlock) {
|
|
101
|
+
this.lastProcessedBlock = savedBlock;
|
|
102
|
+
this.lastExplorerBlock = savedBlock;
|
|
103
|
+
this.logger.info(`Resumed from checkpoint: block ${savedBlock}`);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
// Start from current block
|
|
107
|
+
this.lastProcessedBlock = (await this.rpc.getBlockNumber()) - 1;
|
|
108
|
+
this.lastExplorerBlock = this.lastProcessedBlock;
|
|
109
|
+
this.logger.info(`Starting from current block: ${this.lastProcessedBlock}`);
|
|
110
|
+
}
|
|
111
|
+
// Start WebSocket subscription
|
|
112
|
+
if (this.wsManager) {
|
|
113
|
+
this.setupWsHandlers();
|
|
114
|
+
this.wsManager.connect(this.addresses).catch((err) => {
|
|
115
|
+
this.logger.warn(`WS connect failed: ${err.message}`);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
// Start polling loop
|
|
119
|
+
this.startPolling();
|
|
120
|
+
// Start explorer polling
|
|
121
|
+
if (this.explorer) {
|
|
122
|
+
this.startExplorerPolling();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Stop monitoring gracefully.
|
|
127
|
+
*/
|
|
128
|
+
async stop() {
|
|
129
|
+
if (!this.running)
|
|
130
|
+
return;
|
|
131
|
+
this.running = false;
|
|
132
|
+
this.logger.info('Stopping ContractWatcher...');
|
|
133
|
+
if (this.pollTimer) {
|
|
134
|
+
clearInterval(this.pollTimer);
|
|
135
|
+
this.pollTimer = null;
|
|
136
|
+
}
|
|
137
|
+
if (this.explorerTimer) {
|
|
138
|
+
clearInterval(this.explorerTimer);
|
|
139
|
+
this.explorerTimer = null;
|
|
140
|
+
}
|
|
141
|
+
if (this.wsManager) {
|
|
142
|
+
await this.wsManager.disconnect();
|
|
143
|
+
}
|
|
144
|
+
if (this.explorer) {
|
|
145
|
+
this.explorer.destroy();
|
|
146
|
+
}
|
|
147
|
+
// Save final checkpoint
|
|
148
|
+
if (this.lastProcessedBlock > 0) {
|
|
149
|
+
await this.checkpoint.save(this.checkpointKey, this.lastProcessedBlock);
|
|
150
|
+
}
|
|
151
|
+
this.logger.info('ContractWatcher stopped');
|
|
152
|
+
}
|
|
153
|
+
// ─── WebSocket Handlers ──────────────────────────────────────────────
|
|
154
|
+
setupWsHandlers() {
|
|
155
|
+
if (!this.wsManager)
|
|
156
|
+
return;
|
|
157
|
+
this.wsManager.on('log', (log) => {
|
|
158
|
+
this.processLog(log, 'ws_logs').catch((err) => {
|
|
159
|
+
this.logger.error(`Error processing WS log: ${err.message}`);
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
this.wsManager.on('connected', (url) => {
|
|
163
|
+
this.logger.info(`WS connected: ${url}`);
|
|
164
|
+
this.emit('connected', { url, type: 'websocket' });
|
|
165
|
+
});
|
|
166
|
+
this.wsManager.on('disconnected', (url, reason) => {
|
|
167
|
+
this.logger.warn(`WS disconnected: ${url} (${reason})`);
|
|
168
|
+
this.emit('disconnected', { url, reason });
|
|
169
|
+
});
|
|
170
|
+
this.wsManager.on('error', (err) => {
|
|
171
|
+
this.emit('error', err);
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
// ─── Polling Loop ─────────────────────────────────────────────────────
|
|
175
|
+
startPolling() {
|
|
176
|
+
this.pollCycle().catch((err) => {
|
|
177
|
+
this.logger.error(`Initial poll failed: ${err.message}`);
|
|
178
|
+
});
|
|
179
|
+
this.pollTimer = setInterval(() => {
|
|
180
|
+
this.pollCycle().catch((err) => {
|
|
181
|
+
this.logger.error(`Poll cycle failed: ${err.message}`);
|
|
182
|
+
});
|
|
183
|
+
}, this.pollIntervalMs);
|
|
184
|
+
}
|
|
185
|
+
async pollCycle() {
|
|
186
|
+
if (!this.running)
|
|
187
|
+
return;
|
|
188
|
+
try {
|
|
189
|
+
const currentBlock = await this.rpc.getBlockNumber();
|
|
190
|
+
if (currentBlock <= this.lastProcessedBlock) {
|
|
191
|
+
this.logger.debug(`No new blocks (current: ${currentBlock}, last: ${this.lastProcessedBlock})`);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const fromBlock = this.lastProcessedBlock + 1;
|
|
195
|
+
const toBlock = currentBlock;
|
|
196
|
+
this.logger.debug(`Polling blocks ${fromBlock}–${toBlock} (${toBlock - fromBlock + 1} blocks)`);
|
|
197
|
+
const logs = await this.poller.fetchLogs(fromBlock, toBlock);
|
|
198
|
+
for (const log of logs) {
|
|
199
|
+
await this.processLog(log, 'rpc_logs');
|
|
200
|
+
}
|
|
201
|
+
this.lastProcessedBlock = toBlock;
|
|
202
|
+
// Save checkpoint
|
|
203
|
+
await this.checkpoint.save(this.checkpointKey, toBlock);
|
|
204
|
+
this.emit('checkpoint', toBlock);
|
|
205
|
+
// Prune old dedup keys
|
|
206
|
+
if (this.seenEventKeys.size > 15000) {
|
|
207
|
+
const keysArray = Array.from(this.seenEventKeys);
|
|
208
|
+
this.seenEventKeys = new Set(keysArray.slice(keysArray.length - 10000));
|
|
209
|
+
}
|
|
210
|
+
if (this.seenTxHashes.size > 15000) {
|
|
211
|
+
const txArray = Array.from(this.seenTxHashes);
|
|
212
|
+
this.seenTxHashes = new Set(txArray.slice(txArray.length - 10000));
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch (err) {
|
|
216
|
+
this.logger.error(`Poll cycle error: ${err.message}`);
|
|
217
|
+
this.emit('error', err);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// ─── Explorer Polling ─────────────────────────────────────────────────
|
|
221
|
+
startExplorerPolling() {
|
|
222
|
+
if (!this.explorer)
|
|
223
|
+
return;
|
|
224
|
+
setTimeout(() => {
|
|
225
|
+
this.explorerPollCycle().catch((err) => {
|
|
226
|
+
this.logger.error(`Initial explorer poll failed: ${err.message}`);
|
|
227
|
+
});
|
|
228
|
+
}, 5000);
|
|
229
|
+
this.explorerTimer = setInterval(() => {
|
|
230
|
+
this.explorerPollCycle().catch((err) => {
|
|
231
|
+
this.logger.error(`Explorer poll cycle failed: ${err.message}`);
|
|
232
|
+
});
|
|
233
|
+
}, this.explorerPollIntervalMs);
|
|
234
|
+
}
|
|
235
|
+
async explorerPollCycle() {
|
|
236
|
+
if (!this.running || !this.explorer)
|
|
237
|
+
return;
|
|
238
|
+
const currentBlock = this.lastProcessedBlock;
|
|
239
|
+
if (currentBlock <= this.lastExplorerBlock)
|
|
240
|
+
return;
|
|
241
|
+
for (const address of this.addresses) {
|
|
242
|
+
try {
|
|
243
|
+
// Fetch direct transactions
|
|
244
|
+
const txs = await this.explorer.getTransactions(address, {
|
|
245
|
+
startBlock: this.lastExplorerBlock + 1,
|
|
246
|
+
endBlock: currentBlock,
|
|
247
|
+
});
|
|
248
|
+
for (const tx of txs) {
|
|
249
|
+
if (this.seenTxHashes.has(tx.hash))
|
|
250
|
+
continue;
|
|
251
|
+
this.seenTxHashes.add(tx.hash);
|
|
252
|
+
const interaction = {
|
|
253
|
+
type: 'direct_call',
|
|
254
|
+
txHash: tx.hash,
|
|
255
|
+
blockNumber: parseInt(tx.blockNumber),
|
|
256
|
+
timestamp: parseInt(tx.timeStamp),
|
|
257
|
+
from: tx.from,
|
|
258
|
+
to: tx.to,
|
|
259
|
+
value: tx.value,
|
|
260
|
+
methodId: tx.methodId,
|
|
261
|
+
methodName: tx.functionName,
|
|
262
|
+
input: tx.input,
|
|
263
|
+
gasUsed: tx.gasUsed,
|
|
264
|
+
isError: tx.isError === '1',
|
|
265
|
+
source: 'explorer_txlist',
|
|
266
|
+
};
|
|
267
|
+
this.emit('interaction', interaction);
|
|
268
|
+
}
|
|
269
|
+
// Fetch internal transactions
|
|
270
|
+
const internalTxs = await this.explorer.getInternalTransactions(address, {
|
|
271
|
+
startBlock: this.lastExplorerBlock + 1,
|
|
272
|
+
endBlock: currentBlock,
|
|
273
|
+
});
|
|
274
|
+
for (const tx of internalTxs) {
|
|
275
|
+
if (this.seenTxHashes.has(`${tx.hash}-internal-${tx.from}-${tx.to}`))
|
|
276
|
+
continue;
|
|
277
|
+
this.seenTxHashes.add(`${tx.hash}-internal-${tx.from}-${tx.to}`);
|
|
278
|
+
const callType = tx.callType?.toLowerCase();
|
|
279
|
+
let interactionType = 'internal_call';
|
|
280
|
+
if (callType === 'delegatecall')
|
|
281
|
+
interactionType = 'delegate_call';
|
|
282
|
+
else if (callType === 'staticcall')
|
|
283
|
+
interactionType = 'static_call';
|
|
284
|
+
else if (callType === 'create')
|
|
285
|
+
interactionType = 'create';
|
|
286
|
+
const interaction = {
|
|
287
|
+
type: interactionType,
|
|
288
|
+
txHash: tx.hash,
|
|
289
|
+
blockNumber: parseInt(tx.blockNumber),
|
|
290
|
+
timestamp: parseInt(tx.timeStamp),
|
|
291
|
+
from: tx.from,
|
|
292
|
+
to: tx.to,
|
|
293
|
+
value: tx.value,
|
|
294
|
+
gasUsed: tx.gasUsed,
|
|
295
|
+
isError: tx.isError === '1',
|
|
296
|
+
source: 'explorer_internal',
|
|
297
|
+
};
|
|
298
|
+
this.emit('interaction', interaction);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
catch (err) {
|
|
302
|
+
this.logger.warn(`Explorer poll failed for ${address}: ${err.message}`);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
this.lastExplorerBlock = currentBlock;
|
|
306
|
+
}
|
|
307
|
+
// ─── Log Processing ───────────────────────────────────────────────────
|
|
308
|
+
async processLog(log, source) {
|
|
309
|
+
const logIndex = typeof log.logIndex === 'string'
|
|
310
|
+
? parseInt(log.logIndex, 16)
|
|
311
|
+
: log.logIndex;
|
|
312
|
+
const dedupKey = `${log.transactionHash}-${logIndex}`;
|
|
313
|
+
if (this.seenEventKeys.has(dedupKey))
|
|
314
|
+
return;
|
|
315
|
+
this.seenEventKeys.add(dedupKey);
|
|
316
|
+
this.emit('log', log);
|
|
317
|
+
const decoded = this.decoder.decode(log);
|
|
318
|
+
if (decoded) {
|
|
319
|
+
decoded.timestamp = await this.resolveTimestamp(decoded.blockNumber);
|
|
320
|
+
this.emit('event', decoded);
|
|
321
|
+
const interaction = {
|
|
322
|
+
type: 'event',
|
|
323
|
+
txHash: decoded.txHash,
|
|
324
|
+
blockNumber: decoded.blockNumber,
|
|
325
|
+
timestamp: decoded.timestamp,
|
|
326
|
+
from: '',
|
|
327
|
+
to: decoded.contract,
|
|
328
|
+
value: '0',
|
|
329
|
+
event: decoded,
|
|
330
|
+
source,
|
|
331
|
+
};
|
|
332
|
+
this.emit('interaction', interaction);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
async resolveTimestamp(blockNumber) {
|
|
336
|
+
const cached = this.blockTimestampCache.get(blockNumber);
|
|
337
|
+
if (cached !== undefined)
|
|
338
|
+
return cached;
|
|
339
|
+
try {
|
|
340
|
+
const timestamp = await this.rpc.getBlockTimestamp(blockNumber);
|
|
341
|
+
this.blockTimestampCache.set(blockNumber, timestamp);
|
|
342
|
+
if (this.blockTimestampCache.size > 600) {
|
|
343
|
+
const entries = Array.from(this.blockTimestampCache.entries());
|
|
344
|
+
this.blockTimestampCache = new Map(entries.slice(entries.length - 500));
|
|
345
|
+
}
|
|
346
|
+
return timestamp;
|
|
347
|
+
}
|
|
348
|
+
catch {
|
|
349
|
+
return Math.floor(Date.now() / 1000);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
//# sourceMappingURL=contract-watcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract-watcher.js","sourceRoot":"","sources":["../../src/watcher/contract-watcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log Poller — fetches logs via eth_getLogs in chunked block ranges.
|
|
3
|
+
*
|
|
4
|
+
* Handles XDC's 100-block-per-request limit with automatic chunking.
|
|
5
|
+
* Used by ContractWatcher as the reliable fallback to WebSocket.
|
|
6
|
+
*/
|
|
7
|
+
import { RpcClient } from '../rpc/rpc-client.js';
|
|
8
|
+
import type { RawLog, PollingConfig, LogLevel } from '../types/index.js';
|
|
9
|
+
export declare class LogPoller {
|
|
10
|
+
private readonly logger;
|
|
11
|
+
private readonly rpc;
|
|
12
|
+
private readonly addresses;
|
|
13
|
+
private readonly maxBlockRange;
|
|
14
|
+
private readonly concurrency;
|
|
15
|
+
constructor(rpc: RpcClient, addresses: string[], config?: PollingConfig, logLevel?: LogLevel);
|
|
16
|
+
/**
|
|
17
|
+
* Fetch all logs from `fromBlock` to `toBlock` for the monitored addresses.
|
|
18
|
+
* Automatically chunks into maxBlockRange-sized requests.
|
|
19
|
+
*/
|
|
20
|
+
fetchLogs(fromBlock: number, toBlock: number): Promise<RawLog[]>;
|
|
21
|
+
private fetchChunk;
|
|
22
|
+
private toNumber;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=log-poller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-poller.d.ts","sourceRoot":"","sources":["../../src/watcher/log-poller.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAEzE,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAY;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAW;IACrC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;gBAGnC,GAAG,EAAE,SAAS,EACd,SAAS,EAAE,MAAM,EAAE,EACnB,MAAM,CAAC,EAAE,aAAa,EACtB,QAAQ,CAAC,EAAE,QAAQ;IASrB;;;OAGG;IACG,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;YAyCxD,UAAU;IAexB,OAAO,CAAC,QAAQ;CAKjB"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log Poller — fetches logs via eth_getLogs in chunked block ranges.
|
|
3
|
+
*
|
|
4
|
+
* Handles XDC's 100-block-per-request limit with automatic chunking.
|
|
5
|
+
* Used by ContractWatcher as the reliable fallback to WebSocket.
|
|
6
|
+
*/
|
|
7
|
+
import { Logger } from '../utils/logger.js';
|
|
8
|
+
export class LogPoller {
|
|
9
|
+
logger;
|
|
10
|
+
rpc;
|
|
11
|
+
addresses;
|
|
12
|
+
maxBlockRange;
|
|
13
|
+
concurrency;
|
|
14
|
+
constructor(rpc, addresses, config, logLevel) {
|
|
15
|
+
this.rpc = rpc;
|
|
16
|
+
this.addresses = addresses;
|
|
17
|
+
this.maxBlockRange = config?.maxBlockRange ?? 100;
|
|
18
|
+
this.concurrency = config?.concurrency ?? 3;
|
|
19
|
+
this.logger = new Logger('LogPoller', logLevel ?? 'info');
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Fetch all logs from `fromBlock` to `toBlock` for the monitored addresses.
|
|
23
|
+
* Automatically chunks into maxBlockRange-sized requests.
|
|
24
|
+
*/
|
|
25
|
+
async fetchLogs(fromBlock, toBlock) {
|
|
26
|
+
if (fromBlock > toBlock)
|
|
27
|
+
return [];
|
|
28
|
+
const totalBlocks = toBlock - fromBlock + 1;
|
|
29
|
+
if (totalBlocks <= this.maxBlockRange) {
|
|
30
|
+
return this.fetchChunk(fromBlock, toBlock);
|
|
31
|
+
}
|
|
32
|
+
// Split into chunks
|
|
33
|
+
const chunks = [];
|
|
34
|
+
let current = fromBlock;
|
|
35
|
+
while (current <= toBlock) {
|
|
36
|
+
const chunkEnd = Math.min(current + this.maxBlockRange - 1, toBlock);
|
|
37
|
+
chunks.push({ from: current, to: chunkEnd });
|
|
38
|
+
current = chunkEnd + 1;
|
|
39
|
+
}
|
|
40
|
+
this.logger.debug(`Fetching logs: ${chunks.length} chunks (blocks ${fromBlock}–${toBlock})`);
|
|
41
|
+
// Execute chunks with concurrency control
|
|
42
|
+
const allLogs = [];
|
|
43
|
+
for (let i = 0; i < chunks.length; i += this.concurrency) {
|
|
44
|
+
const batch = chunks.slice(i, i + this.concurrency);
|
|
45
|
+
const results = await Promise.all(batch.map((chunk) => this.fetchChunk(chunk.from, chunk.to)));
|
|
46
|
+
for (const logs of results) {
|
|
47
|
+
allLogs.push(...logs);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Sort by block number, then log index
|
|
51
|
+
allLogs.sort((a, b) => {
|
|
52
|
+
const blockDiff = this.toNumber(a.blockNumber) - this.toNumber(b.blockNumber);
|
|
53
|
+
if (blockDiff !== 0)
|
|
54
|
+
return blockDiff;
|
|
55
|
+
return this.toNumber(a.logIndex) - this.toNumber(b.logIndex);
|
|
56
|
+
});
|
|
57
|
+
return allLogs;
|
|
58
|
+
}
|
|
59
|
+
async fetchChunk(fromBlock, toBlock) {
|
|
60
|
+
try {
|
|
61
|
+
const logs = await this.rpc.getLogs({
|
|
62
|
+
address: this.addresses,
|
|
63
|
+
fromBlock,
|
|
64
|
+
toBlock,
|
|
65
|
+
});
|
|
66
|
+
this.logger.debug(`Fetched ${logs.length} logs from blocks ${fromBlock}–${toBlock}`);
|
|
67
|
+
return logs;
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
this.logger.error(`Failed to fetch logs ${fromBlock}–${toBlock}: ${err.message}`);
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
toNumber(value) {
|
|
75
|
+
if (typeof value === 'number')
|
|
76
|
+
return value;
|
|
77
|
+
if (value.startsWith('0x') || value.startsWith('0X'))
|
|
78
|
+
return parseInt(value, 16);
|
|
79
|
+
return parseInt(value, 10);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=log-poller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-poller.js","sourceRoot":"","sources":["../../src/watcher/log-poller.ts"],"names":[],"mappings":"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"}
|