forked from stable-jack/events-filter
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Deniz Umut Dereli
committed
Jul 1, 2024
0 parents
commit 73c7b16
Showing
14 changed files
with
675 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
NODE_ENV=development | ||
APP_NAME=evm-event-tracker | ||
LOG_DIR=../logs | ||
LOG_SERVER= | ||
DB_HOST=localhost | ||
DB_PORT=5432 | ||
DB_USERNAME=dev_user | ||
DB_PASSWORD=dev_password | ||
DB_NAME=event_tracker_dev | ||
REDIS_HOST=localhost | ||
REDIS_PORT=6379 | ||
CONTRACT_ADDRESS=0x7ceb23fd6bc0add59e62ac25578270cff1b9f619 | ||
CONTRACT_ABI_PATH=./src/abi/WETH.json | ||
CONTRACT_EVENT_NAMES=Approval,Transfer | ||
RPC_URL=https://polygon-mainnet.infura.io/v3/INFURA_ID | ||
POLL_INTERVAL_MS=60000 | ||
STARTING_BLOCK_NUMBER=58799213 | ||
RESCAN=true | ||
RESCAN_TIMER=600000 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
node_modules | ||
.env | ||
.env.production | ||
.env.development | ||
|
||
/log | ||
/logs | ||
|
||
package-lock.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
version: '3.8' | ||
|
||
services: | ||
postgres: | ||
image: postgres:14 | ||
environment: | ||
POSTGRES_DB: ${DB_NAME} | ||
POSTGRES_USER: ${DB_USERNAME} | ||
POSTGRES_PASSWORD: ${DB_PASSWORD} | ||
volumes: | ||
- postgres_data:/var/lib/postgresql/data | ||
ports: | ||
- "${DB_PORT}:5432" | ||
|
||
redis: | ||
image: redis:6 | ||
ports: | ||
- "${REDIS_PORT}:6379" | ||
volumes: | ||
- redis_data:/data | ||
|
||
volumes: | ||
postgres_data: | ||
redis_data: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
{ | ||
"name": "evm-event-tracker", | ||
"author": { | ||
"name": "Deniz Umut Dereli", | ||
"email": "deniz.umut.dereli@gmail.com"}, | ||
"version": "1.0.0", | ||
"description": "EVM event tracker using TypeScript, PostgreSQL, and Redis", | ||
"main": "dist/index.js", | ||
"scripts": { | ||
"start": "node dist/index.js", | ||
"dev": "ts-node-dev --respawn --transpile-only src/index.ts", | ||
"build": "tsc", | ||
"typeorm": "typeorm-ts-node-commonjs" | ||
}, | ||
"dependencies": { | ||
"commander": "^12.1.0", | ||
"dotenv": "^16.0.3", | ||
"ethers": "^6.7.1", | ||
"inquirer": "^9.3.1", | ||
"pg": "^8.10.0", | ||
"redis": "^3.1.2", | ||
"reflect-metadata": "^0.1.13", | ||
"typeorm": "^0.3.15", | ||
"winston": "^3.13.0", | ||
"winston-daily-rotate-file": "^5.0.0", | ||
"winston-syslog": "^2.7.0" | ||
}, | ||
"devDependencies": { | ||
"@types/inquirer": "^9.0.7", | ||
"@types/node": "^18.15.11", | ||
"@types/redis": "^2.8.32", | ||
"@types/winston-syslog": "^2.4.3", | ||
"ts-node": "^10.9.1", | ||
"ts-node-dev": "^2.0.0", | ||
"typescript": "^5.0.4" | ||
}, | ||
"engines": { | ||
"node": ">=14.0.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"status": "1", | ||
"message": "OK-Missing/Invalid API Key, rate limit of 1/5sec applied", | ||
"result": "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"childChainManager\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"userAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address payable\",\"name\":\"relayerAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"functionSignature\",\"type\":\"bytes\"}],\"name\":\"MetaTransactionExecuted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"CHILD_CHAIN_ID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"CHILD_CHAIN_ID_BYTES\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEPOSITOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ERC712_VERSION\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ROOT_CHAIN_ID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ROOT_CHAIN_ID_BYTES\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"subtractedValue\",\"type\":\"uint256\"}],\"name\":\"decreaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"depositData\",\"type\":\"bytes\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"userAddress\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"functionSignature\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"sigR\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"sigS\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"sigV\",\"type\":\"uint8\"}],\"name\":\"executeMetaTransaction\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDomainSeperator\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"getNonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"addedValue\",\"type\":\"uint256\"}],\"name\":\"increaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import { Command } from 'commander'; | ||
import dotenv from 'dotenv'; | ||
import path from 'path'; | ||
import { Config } from 'src/interfaces'; | ||
|
||
const envFile = process.env.NODE_ENV === 'production' ? '.env.production' : '.env.development'; | ||
dotenv.config({ path: path.resolve(process.cwd(), envFile) }); | ||
|
||
const program = new Command(); | ||
const genesis = '0'; | ||
|
||
program | ||
.option('--appname <appname>', 'Application name') | ||
.option('--rpc <url>', 'RPC URL') | ||
.option('--abi <path>', 'ABI path') | ||
.option('--events <names>', 'Event names, comma separated') | ||
.option('--block <number>', 'Starting block number', (value) => parseInt(value, 10)) | ||
.option('--contract <address>', 'Contract address') | ||
.option('--rescan <rescan>', 'Enable rescan feature', (value) => value === 'true'); | ||
|
||
const options = program.opts(); | ||
|
||
const eventNames: string[] = options.events | ||
? options.events.split(',').map((event: string) => event.trim()) | ||
: (process.env.CONTRACT_EVENT_NAMES | ||
? process.env.CONTRACT_EVENT_NAMES.split(',').map((event: string) => event.trim()) | ||
: []); | ||
|
||
const pollIntervalMs = parseInt(process.env.POLL_INTERVAL_MS || '60000', 10); | ||
const rescanTimer = parseInt(process.env.RESCAN_TIMER || '600000', 10); | ||
|
||
if (rescanTimer <= pollIntervalMs) { | ||
console.error("RESCAN_TIMER must be greater than POLL_INTERVAL_MS"); | ||
process.exit(1); | ||
} | ||
|
||
export const config:Config = { | ||
nodeEnv: process.env.NODE_ENV || 'development', | ||
appName: options.appname || (process.env.APP_NAME || 'event-tracker'), | ||
logDir: process.env.LOG_DIR || 'logs', | ||
logServer: process.env.LOG_SERVER, | ||
database: { | ||
host: process.env.DB_HOST || 'localhost', | ||
port: parseInt(process.env.DB_PORT || '5432', 10), | ||
username: process.env.DB_USERNAME || 'postgres', | ||
password: process.env.DB_PASSWORD || 'password', | ||
name: process.env.DB_NAME || 'evm-event-tracker', | ||
}, | ||
redis: { | ||
host: process.env.REDIS_HOST || 'localhost', | ||
port: parseInt(process.env.REDIS_PORT || '6379', 10), | ||
}, | ||
contract: { | ||
address: options.contract || process.env.CONTRACT_ADDRESS, | ||
rpcUrl: options.rpc || process.env.RPC_URL, | ||
abiPath: options.abi || process.env.CONTRACT_ABI_PATH || '', | ||
eventNames: eventNames, | ||
}, | ||
pollIntervalMs: pollIntervalMs, | ||
rescan: options.rescan, | ||
rescanTimer: rescanTimer, | ||
startBlockNumber: options.block || parseInt(process.env.STARTING_BLOCK_NUMBER || genesis, 10), | ||
}; | ||
|
||
console.log(`Running with config: ${JSON.stringify(config, null, 2)}`); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm'; | ||
|
||
@Entity() | ||
@Index(['transactionHash', 'logIndex'], { unique: true }) | ||
export class Event { | ||
@PrimaryGeneratedColumn() | ||
id: number; | ||
|
||
@Column() | ||
eventName: string; | ||
|
||
@Column() | ||
eventSignature: string; | ||
|
||
@Column({ type: 'text' }) | ||
eventData: string; | ||
|
||
@Column() | ||
blockNumber: number; | ||
|
||
@Column() | ||
transactionHash: string; | ||
|
||
@Column() | ||
logIndex: number; | ||
|
||
@Column({ type: 'text', nullable: true }) | ||
parsedData: string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { ethers } from 'ethers'; | ||
import fs from 'fs'; | ||
import { config } from '../config/config'; | ||
import { logger } from '../logger/logger'; | ||
|
||
export interface EventDefinition { | ||
name: string; | ||
signature: string; | ||
} | ||
|
||
interface AbiInput { | ||
internalType: string; | ||
name: string; | ||
type: string; | ||
} | ||
|
||
interface AbiEvent { | ||
anonymous: boolean; | ||
inputs: AbiInput[]; | ||
name: string; | ||
type: string; | ||
} | ||
|
||
const abiPath = config.contract.abiPath; | ||
const abiContent = fs.readFileSync(abiPath, 'utf8'); | ||
const abiJson = JSON.parse(abiContent); | ||
const abi: AbiEvent[] = JSON.parse(abiJson.result); | ||
|
||
const extractEventsFromAbi = (abi: AbiEvent[]): EventDefinition[] => { | ||
return abi | ||
.filter(item => item.type === 'event') | ||
.map(event => ({ | ||
name: event.name, | ||
signature: `${event.name}(${event.inputs.map((input: AbiInput) => input.type).join(',')})`, | ||
})); | ||
}; | ||
|
||
export const allContractEvents: EventDefinition[] = extractEventsFromAbi(abi); | ||
|
||
export function generateEventSignatures(events: EventDefinition[]): string[] { | ||
return events.map(event => ethers.keccak256(ethers.toUtf8Bytes(event.signature))); | ||
} | ||
|
||
const wantedEventNames = new Set([...config.contract.eventNames]); | ||
const filteredEvents = allContractEvents.filter(event => wantedEventNames.has(event.name)); | ||
|
||
wantedEventNames.forEach(eventName => { | ||
if (!filteredEvents.some(event => event.name === eventName)) { | ||
logger.error(`Warning: Event name "${eventName}" not found in the ABI.`); | ||
process.exit(1); | ||
} | ||
}); | ||
|
||
export const contractEvents = filteredEvents; | ||
|
||
export const eventSignatures = generateEventSignatures(contractEvents); | ||
|
||
logger.info(`Filtered contract events: ${JSON.stringify(contractEvents)}`); | ||
logger.info(`Event signatures: ${JSON.stringify(eventSignatures)}`); | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import Redis from 'redis'; | ||
import { DataSource } from 'typeorm'; | ||
import { promisify } from 'util'; | ||
import { config } from './config/config'; | ||
import { Event } from './entities/Event'; | ||
import { logger } from './logger/logger'; | ||
import { EventTracker } from './services/EventTracker'; | ||
|
||
async function getLatestBlockFromDb(dataSource: DataSource): Promise<number> { | ||
const latestBlock = await dataSource.query(`SELECT MAX("blockNumber") AS "latestBlock" FROM event`); | ||
return latestBlock[0].latestBlock || config.startBlockNumber; | ||
} | ||
|
||
async function main() { | ||
const dataSource = new DataSource({ | ||
type: 'postgres', | ||
host: config.database.host, | ||
port: config.database.port, | ||
username: config.database.username, | ||
password: config.database.password, | ||
database: config.database.name, | ||
entities: [Event], | ||
synchronize: true, | ||
}); | ||
|
||
await dataSource.initialize(); | ||
logger.debug('Database connection established'); | ||
|
||
const redisClient = Redis.createClient({ | ||
host: config.redis.host, | ||
port: config.redis.port, | ||
}); | ||
|
||
const redisGetAsync = promisify(redisClient.get).bind(redisClient); | ||
const currentBlock = await getLatestBlockFromDb(dataSource); | ||
|
||
if (config.startBlockNumber > currentBlock) { | ||
console.error(`Configured start block number ${config.startBlockNumber} is bigger than the latest processed block ${currentBlock}. Aborting.`); | ||
process.exit(1); | ||
} else { | ||
config.startBlockNumber = currentBlock; | ||
} | ||
|
||
const eventTracker = new EventTracker(dataSource, config.pollIntervalMs); | ||
await eventTracker.initialize(); | ||
logger.debug('Event tracker initialized'); | ||
|
||
// graceful shutdown | ||
process.on('SIGINT', async () => { | ||
logger.debug('Stopping event tracker...'); | ||
eventTracker.stop(); | ||
await dataSource.destroy(); | ||
redisClient.quit(); | ||
logger.debug('Database connection closed'); | ||
process.exit(0); | ||
}); | ||
} | ||
|
||
main().catch((error) => { | ||
console.error('Error:', error); | ||
process.exit(1); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
export interface Config { | ||
nodeEnv: string; | ||
appName: string; | ||
logDir: string; | ||
logServer?: string; | ||
database: { | ||
host: string; | ||
port: number; | ||
username: string; | ||
password: string; | ||
name: string; | ||
}; | ||
redis: { | ||
host: string; | ||
port: number; | ||
}; | ||
contract: { | ||
address?: string; | ||
rpcUrl?: string; | ||
abiPath: string; | ||
eventNames: string[]; | ||
}; | ||
pollIntervalMs: number; | ||
rescan: boolean; | ||
rescanTimer: number; | ||
startBlockNumber: number; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from "./config.interface"; | ||
|
Oops, something went wrong.