@polygonlabs/servercore 1.0.0-dev.3 → 1.0.0-dev.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/consumers/abstract_event_consumer.ts"],"sourcesContent":["import type { ConsumerError } from \"../errors\";\nimport { EventEmitter } from \"events\";\n\nexport class AbstractEventConsumer extends EventEmitter {\n /**\n * @public\n *\n * Method to register listener for events. The Abstract Event Consumer emits fatalError\n * event.\n *\n * @param {\"fatalError\"} eventName - Event name to register listener for.\n * @param listener - Listener to be called when emitting the event.\n *\n * @returns {this} - Returns an instance of the class.\n */\n on(\n eventName: \"fatalError\",\n listener: (error: Error | ConsumerError) => void\n ): this {\n return super.on(eventName, listener);\n }\n /**\n * @public\n *\n * Method to register listener for events that will be called only once. The Abstract Event Consumer emits fatalError\n * event.\n *\n * @param {\"fatalError\"} eventName - Event name to register listener for.\n * @param listener - Listener to be called when emitting the event.\n *\n * @returns {this} - Returns an instance of the class.\n */\n once(\n eventName: \"fatalError\",\n listener: (error: Error | ConsumerError) => void\n ): this {\n return super.on(eventName, listener);\n }\n\n protected onFatalError(error: Error | ConsumerError): void {\n this.emit(\"fatalError\", error);\n }\n}\n"],"mappings":"AACA,SAAS,oBAAoB;AAEtB,MAAM,8BAA8B,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYpD,GACI,WACA,UACI;AACJ,WAAO,MAAM,GAAG,WAAW,QAAQ;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,KACI,WACA,UACI;AACJ,WAAO,MAAM,GAAG,WAAW,QAAQ;AAAA,EACvC;AAAA,EAEU,aAAa,OAAoC;AACvD,SAAK,KAAK,cAAc,KAAK;AAAA,EACjC;AACJ;","names":[]}
@@ -10,8 +10,9 @@ declare class EventConsumer<T, U> extends AbstractEventConsumer {
10
10
  private config;
11
11
  private consumerRunning;
12
12
  protected client: PublicClient | null;
13
- protected observer: IObserver<object, ConsumerError, object> | null;
13
+ protected observer: IObserver<T, ConsumerError, U> | null;
14
14
  constructor(config: IEventConsumerConfig);
15
+ private _backfillEvents;
15
16
  start(observer: IObserver<T, ConsumerError, U>): Promise<void>;
16
17
  /**
17
18
  * Private method which updates the connection status of consumer to disconnected, and removes all listeners.
@@ -1,7 +1,11 @@
1
- import { createPublicClient, http } from "viem";
1
+ import {
2
+ createPublicClient,
3
+ http
4
+ } from "viem";
2
5
  import { ConsumerError, ExternalDependencyError } from "../errors";
3
6
  import { AbstractEventConsumer } from "./abstract_event_consumer";
4
7
  import { errorCodes } from "../constants";
8
+ import { Logger } from "../logger";
5
9
  class EventConsumer extends AbstractEventConsumer {
6
10
  constructor(config) {
7
11
  super();
@@ -19,16 +23,49 @@ class EventConsumer extends AbstractEventConsumer {
19
23
  consumerRunning = false;
20
24
  client = null;
21
25
  observer = null;
26
+ async _backfillEvents(fromBlock, toBlock, step) {
27
+ Logger.info({
28
+ location: "event_consumer",
29
+ functon: "_backfillEvents",
30
+ status: `[Backfill] Starting backfill from block ${fromBlock} to ${toBlock}`
31
+ });
32
+ for (let start = fromBlock; start <= toBlock; start += step) {
33
+ const end = start + step - 1n > toBlock ? toBlock : start + step - 1n;
34
+ console.log(
35
+ `[Backfill] Fetching logs from block ${start} to ${end}`
36
+ );
37
+ const getLogsConfig = {
38
+ address: this.config.contractAddress,
39
+ fromBlock: start,
40
+ toBlock: end
41
+ };
42
+ if (this.config.events.length > 1) {
43
+ getLogsConfig.event = this.config.events[0];
44
+ } else {
45
+ getLogsConfig.events = this.config.events;
46
+ }
47
+ const logs = await this.client?.getLogs(getLogsConfig);
48
+ await this.observer?.next(logs);
49
+ }
50
+ }
22
51
  async start(observer) {
23
52
  try {
24
- this.client?.watchContractEvent({
53
+ this.observer = observer;
54
+ const latestBlock = await this.client?.getBlockNumber() ?? BigInt(0);
55
+ if (latestBlock - this.config.startBlock > this.config.pollBatchSize) {
56
+ await this._backfillEvents(
57
+ this.config.startBlock,
58
+ latestBlock,
59
+ this.config.pollBatchSize
60
+ );
61
+ }
62
+ this.client?.watchEvent({
25
63
  address: this.config.contractAddress,
26
- abi: this.config.abi,
27
- eventName: this.config.eventName,
64
+ events: this.config.events,
28
65
  fromBlock: this.config.startBlock,
29
66
  onLogs: (logs) => {
30
67
  const transformedLogs = logs;
31
- observer.next(transformedLogs);
68
+ this.observer?.next(transformedLogs);
32
69
  },
33
70
  onError: (error) => {
34
71
  this.onDisconnect();
@@ -38,7 +75,7 @@ class EventConsumer extends AbstractEventConsumer {
38
75
  code: 1001,
39
76
  isFatal: true,
40
77
  origin: "EventConsumer",
41
- context: { eventName: this.config.eventName }
78
+ context: { eventName: this.config.events }
42
79
  })
43
80
  );
44
81
  }
@@ -53,7 +90,7 @@ class EventConsumer extends AbstractEventConsumer {
53
90
  externalCode: errorCodes.external.UNKNOWN_EXTERNAL_DEPENDENCY_ERROR,
54
91
  rawError: error,
55
92
  origin: "EventConsumer",
56
- context: { eventName: this.config.eventName }
93
+ context: { eventName: this.config.events }
57
94
  }
58
95
  )
59
96
  );
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/consumers/event_consumer.ts"],"sourcesContent":["import {\n createPublicClient,\n http,\n type PublicClient,\n type WatchEventParameters,\n} from \"viem\";\nimport { ConsumerError, ExternalDependencyError } from \"../errors\";\nimport type { IEventConsumerConfig, IObserver } from \"../types\";\nimport { AbstractEventConsumer } from \"./abstract_event_consumer\";\nimport { errorCodes } from \"../constants\";\nimport { Logger } from \"../logger\";\n\nexport class EventConsumer<T, U> extends AbstractEventConsumer {\n private consumerRunning: boolean = false;\n protected client: PublicClient | null = null;\n protected observer: IObserver<T, ConsumerError, U> | null = null;\n\n constructor(private config: IEventConsumerConfig) {\n super();\n this.client = createPublicClient({\n chain: {\n id: this.config.chainId,\n name: \"custom\",\n rpcUrls: { default: { http: [this.config.rpcUrl] } },\n nativeCurrency: this.config.nativeCurrency,\n },\n transport: http(this.config.rpcUrl),\n });\n }\n\n private async _backfillEvents(\n fromBlock: bigint,\n toBlock: bigint,\n step: bigint\n ): Promise<void> {\n Logger.info({\n location: \"event_consumer\",\n functon: \"_backfillEvents\",\n status: `[Backfill] Starting backfill from block ${fromBlock} to ${toBlock}`,\n });\n\n for (let start = fromBlock; start <= toBlock; start += step) {\n const end =\n start + step - 1n > toBlock ? toBlock : start + step - 1n;\n console.log(\n `[Backfill] Fetching logs from block ${start} to ${end}`\n );\n const getLogsConfig: any = {\n address: this.config.contractAddress,\n fromBlock: start,\n toBlock: end,\n };\n if (this.config.events.length > 1) {\n getLogsConfig.event = this.config.events[0];\n } else {\n getLogsConfig.events = this.config.events;\n }\n const logs = await this.client?.getLogs(getLogsConfig);\n await this.observer?.next(logs as T);\n }\n }\n\n public async start(\n observer: IObserver<T, ConsumerError, U>\n ): Promise<void> {\n try {\n this.observer = observer;\n const latestBlock: bigint =\n (await this.client?.getBlockNumber()) ?? BigInt(0);\n if (\n latestBlock - this.config.startBlock >\n this.config.pollBatchSize\n ) {\n await this._backfillEvents(\n this.config.startBlock,\n latestBlock,\n this.config.pollBatchSize\n );\n }\n\n this.client?.watchEvent({\n address: this.config.contractAddress,\n events: this.config.events,\n fromBlock: this.config.startBlock,\n onLogs: (logs) => {\n const transformedLogs = logs as T;\n this.observer?.next(transformedLogs);\n },\n onError: (error) => {\n this.onDisconnect();\n this.onFatalError(\n new ConsumerError(error.name, {\n name: \"CONSUMER_ERROR\",\n code: 1001,\n isFatal: true,\n origin: \"EventConsumer\",\n context: { eventName: this.config.events },\n })\n );\n },\n });\n } catch (error) {\n this.onDisconnect();\n this.onFatalError(\n new ExternalDependencyError(\n this.config.rpcUrl,\n \"Failed to start the event consumer\",\n {\n externalCode:\n errorCodes.external\n .UNKNOWN_EXTERNAL_DEPENDENCY_ERROR,\n rawError: error as Error,\n origin: \"EventConsumer\",\n context: { eventName: this.config.events },\n }\n )\n );\n }\n }\n\n /**\n * Private method which updates the connection status of consumer to disconnected, and removes all listeners.\n *\n * @returns {void}\n */\n private onDisconnect(): void {\n if (this.consumerRunning) {\n this.consumerRunning = false;\n this.observer?.closed();\n this.removeAllListeners();\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,8 @@
1
+ export { EventConsumer } from './event_consumer.js';
2
+ import 'viem';
3
+ import '../errors/consumer_errors.js';
4
+ import '../errors/base_error.js';
5
+ import '../types/observer.js';
6
+ import '../types/event_consumer_config.js';
7
+ import './abstract_event_consumer.js';
8
+ import 'events';
@@ -0,0 +1,2 @@
1
+ export * from "./event_consumer";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/consumers/index.ts"],"sourcesContent":["export * from \"./event_consumer\";\n"],"mappings":"AAAA,cAAc;","names":[]}
package/dist/index.d.ts CHANGED
@@ -13,6 +13,9 @@ export { ExternalDependencyError } from './errors/external_dependency_error.js';
13
13
  export { BaseError } from './errors/base_error.js';
14
14
  export { ConsumerError } from './errors/consumer_errors.js';
15
15
  export { Database } from './database/db_interface.js';
16
+ export { EventConsumer } from './consumers/event_consumer.js';
16
17
  import 'zod';
17
18
  import 'winston';
18
19
  import 'viem';
20
+ import './consumers/abstract_event_consumer.js';
21
+ import 'events';
package/dist/index.js CHANGED
@@ -4,4 +4,5 @@ export * from "./constants";
4
4
  export * from "./types";
5
5
  export * from "./errors";
6
6
  export * from "./database";
7
+ export * from "./consumers";
7
8
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from \"./api\";\nexport * from \"./logger\";\nexport * from \"./constants\";\nexport * from \"./types\";\nexport * from \"./errors\";\nexport * from \"./database\";\n"],"mappings":"AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from \"./api\";\nexport * from \"./logger\";\nexport * from \"./constants\";\nexport * from \"./types\";\nexport * from \"./errors\";\nexport * from \"./database\";\nexport * from \"./consumers\";\n"],"mappings":"AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;","names":[]}
@@ -1,4 +1,4 @@
1
- import { Abi } from 'viem';
1
+ import { Address, AbiEvent } from 'viem';
2
2
 
3
3
  type ChainNativeCurrency = {
4
4
  name: string;
@@ -6,13 +6,14 @@ type ChainNativeCurrency = {
6
6
  decimals: number;
7
7
  };
8
8
  interface IEventConsumerConfig {
9
- contractAddress: `0x${string}`;
10
- eventName: string;
11
- abi: Abi;
9
+ contractAddress: Address | Address[];
10
+ events: AbiEvent[];
12
11
  chainId: number;
13
12
  rpcUrl: string;
14
13
  nativeCurrency: ChainNativeCurrency;
15
14
  startBlock: bigint;
15
+ pollBatchSize: bigint;
16
+ pollInterval: number;
16
17
  }
17
18
 
18
19
  export type { ChainNativeCurrency, IEventConsumerConfig };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polygonlabs/servercore",
3
- "version": "1.0.0-dev.3",
3
+ "version": "1.0.0-dev.5",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/consumer/abstract_event_consumer.ts"],"sourcesContent":["import type { ConsumerError } from \"../errors\";\nimport { EventEmitter } from \"events\";\n\nexport class AbstractEventConsumer extends EventEmitter {\n /**\n * @public\n *\n * Method to register listener for events. The Abstract Event Consumer emits fatalError\n * event.\n *\n * @param {\"fatalError\"} eventName - Event name to register listener for.\n * @param listener - Listener to be called when emitting the event.\n *\n * @returns {this} - Returns an instance of the class.\n */\n on(\n eventName: \"fatalError\",\n listener: (error: Error | ConsumerError) => void\n ): this {\n return super.on(eventName, listener);\n }\n /**\n * @public\n *\n * Method to register listener for events that will be called only once. The Abstract Event Consumer emits fatalError\n * event.\n *\n * @param {\"fatalError\"} eventName - Event name to register listener for.\n * @param listener - Listener to be called when emitting the event.\n *\n * @returns {this} - Returns an instance of the class.\n */\n once(\n eventName: \"fatalError\",\n listener: (error: Error | ConsumerError) => void\n ): this {\n return super.on(eventName, listener);\n }\n\n protected onFatalError(error: Error | ConsumerError): void {\n this.emit(\"fatalError\", error);\n }\n}\n"],"mappings":"AACA,SAAS,oBAAoB;AAEtB,MAAM,8BAA8B,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYpD,GACI,WACA,UACI;AACJ,WAAO,MAAM,GAAG,WAAW,QAAQ;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,KACI,WACA,UACI;AACJ,WAAO,MAAM,GAAG,WAAW,QAAQ;AAAA,EACvC;AAAA,EAEU,aAAa,OAAoC;AACvD,SAAK,KAAK,cAAc,KAAK;AAAA,EACjC;AACJ;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/consumer/event_consumer.ts"],"sourcesContent":["import { createPublicClient, http, type PublicClient } from \"viem\";\nimport { ConsumerError, ExternalDependencyError } from \"../errors\";\nimport type { IEventConsumerConfig, IObserver } from \"../types\";\nimport { AbstractEventConsumer } from \"./abstract_event_consumer\";\nimport { errorCodes } from \"../constants\";\n\nexport class EventConsumer<T, U> extends AbstractEventConsumer {\n private consumerRunning: boolean = false;\n protected client: PublicClient | null = null;\n protected observer: IObserver<object, ConsumerError, object> | null = null;\n\n constructor(private config: IEventConsumerConfig) {\n super();\n this.client = createPublicClient({\n chain: {\n id: this.config.chainId,\n name: \"custom\",\n rpcUrls: { default: { http: [this.config.rpcUrl] } },\n nativeCurrency: this.config.nativeCurrency,\n },\n transport: http(this.config.rpcUrl),\n });\n }\n\n public async start(\n observer: IObserver<T, ConsumerError, U>\n ): Promise<void> {\n try {\n this.client?.watchContractEvent({\n address: this.config.contractAddress,\n abi: this.config.abi,\n eventName: this.config.eventName,\n fromBlock: this.config.startBlock,\n onLogs: (logs) => {\n const transformedLogs = logs as T;\n observer.next(transformedLogs);\n },\n onError: (error) => {\n this.onDisconnect();\n this.onFatalError(\n new ConsumerError(error.name, {\n name: \"CONSUMER_ERROR\",\n code: 1001,\n isFatal: true,\n origin: \"EventConsumer\",\n context: { eventName: this.config.eventName },\n })\n );\n },\n });\n } catch (error) {\n this.onDisconnect();\n this.onFatalError(\n new ExternalDependencyError(\n this.config.rpcUrl,\n \"Failed to start the event consumer\",\n {\n externalCode:\n errorCodes.external\n .UNKNOWN_EXTERNAL_DEPENDENCY_ERROR,\n rawError: error as Error,\n origin: \"EventConsumer\",\n context: { eventName: this.config.eventName },\n }\n )\n );\n }\n }\n\n /**\n * Private method which updates the connection status of consumer to disconnected, and removes all listeners.\n *\n * @returns {void}\n */\n private onDisconnect(): void {\n if (this.consumerRunning) {\n this.consumerRunning = false;\n this.observer?.closed();\n this.removeAllListeners();\n }\n }\n}\n"],"mappings":"AAAA,SAAS,oBAAoB,YAA+B;AAC5D,SAAS,eAAe,+BAA+B;AAEvD,SAAS,6BAA6B;AACtC,SAAS,kBAAkB;AAEpB,MAAM,sBAA4B,sBAAsB;AAAA,EAK3D,YAAoB,QAA8B;AAC9C,UAAM;AADU;AAEhB,SAAK,SAAS,mBAAmB;AAAA,MAC7B,OAAO;AAAA,QACH,IAAI,KAAK,OAAO;AAAA,QAChB,MAAM;AAAA,QACN,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC,KAAK,OAAO,MAAM,EAAE,EAAE;AAAA,QACnD,gBAAgB,KAAK,OAAO;AAAA,MAChC;AAAA,MACA,WAAW,KAAK,KAAK,OAAO,MAAM;AAAA,IACtC,CAAC;AAAA,EACL;AAAA,EAfQ,kBAA2B;AAAA,EACzB,SAA8B;AAAA,EAC9B,WAA4D;AAAA,EAetE,MAAa,MACT,UACa;AACb,QAAI;AACA,WAAK,QAAQ,mBAAmB;AAAA,QAC5B,SAAS,KAAK,OAAO;AAAA,QACrB,KAAK,KAAK,OAAO;AAAA,QACjB,WAAW,KAAK,OAAO;AAAA,QACvB,WAAW,KAAK,OAAO;AAAA,QACvB,QAAQ,CAAC,SAAS;AACd,gBAAM,kBAAkB;AACxB,mBAAS,KAAK,eAAe;AAAA,QACjC;AAAA,QACA,SAAS,CAAC,UAAU;AAChB,eAAK,aAAa;AAClB,eAAK;AAAA,YACD,IAAI,cAAc,MAAM,MAAM;AAAA,cAC1B,MAAM;AAAA,cACN,MAAM;AAAA,cACN,SAAS;AAAA,cACT,QAAQ;AAAA,cACR,SAAS,EAAE,WAAW,KAAK,OAAO,UAAU;AAAA,YAChD,CAAC;AAAA,UACL;AAAA,QACJ;AAAA,MACJ,CAAC;AAAA,IACL,SAAS,OAAO;AACZ,WAAK,aAAa;AAClB,WAAK;AAAA,QACD,IAAI;AAAA,UACA,KAAK,OAAO;AAAA,UACZ;AAAA,UACA;AAAA,YACI,cACI,WAAW,SACN;AAAA,YACT,UAAU;AAAA,YACV,QAAQ;AAAA,YACR,SAAS,EAAE,WAAW,KAAK,OAAO,UAAU;AAAA,UAChD;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,eAAqB;AACzB,QAAI,KAAK,iBAAiB;AACtB,WAAK,kBAAkB;AACvB,WAAK,UAAU,OAAO;AACtB,WAAK,mBAAmB;AAAA,IAC5B;AAAA,EACJ;AACJ;","names":[]}