From 5004cd4dce03f2f08686c55bfb16659b44e59e09 Mon Sep 17 00:00:00 2001 From: CounterFire2023 <136581895+CounterFire2023@users.noreply.github.com> Date: Thu, 29 Jun 2023 10:29:43 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0arbitrm=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E7=9A=84=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/launch.json | 13 +++++++++ package.json | 3 +- src/chain/allchain.ts | 2 +- src/config/events.json | 11 +++---- src/models/FtTransferEvent.ts | 41 ++++++++++++++++++++------ src/models/NftTransferEvent.ts | 47 +++++++++++++++++++++--------- src/models/ScheduleConfirmEvent.ts | 3 +- src/monitor.ts | 7 ++--- src/service/event.sync.service.ts | 15 ++++++---- src/utils/contract.util.ts | 7 +++-- 10 files changed, 105 insertions(+), 44 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 370882e..a607322 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -17,5 +17,18 @@ ], "type": "pwa-node" }, + { + "name": "Debug Monitor", + "request": "launch", + "runtimeArgs": [ + "run-script", + "dev:monitor" + ], + "runtimeExecutable": "npm", + "skipFiles": [ + "/**" + ], + "type": "pwa-node" + }, ] } \ No newline at end of file diff --git a/package.json b/package.json index bf9f4a8..f2a5fda 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "dev:api": "npx ts-node src/api.ts", "lint": "eslint --ext .ts src/**", "format": "eslint --ext .ts src/** --fix", - "dev:monitor": "NODE_ENV=development ts-node -r tsconfig-paths/register src/monitor.ts", + "dev:monitor": "npx ts-node src/monitor.ts", + "dev:monitor2": "NODE_ENV=development ts-node -r tsconfig-paths/register src/monitor.ts", "prod:monitor": "NODE_PATH=./dist node dist/monitor.js" }, "author": "z", diff --git a/src/chain/allchain.ts b/src/chain/allchain.ts index ef84e25..5591f93 100644 --- a/src/chain/allchain.ts +++ b/src/chain/allchain.ts @@ -210,7 +210,7 @@ export const AllChains = [ { name: 'Arbitrum One', type: 'Mainnet', - rpc: 'https://endpoints.omniatech.io/v1/arbitrum/one/public|https://rpc.ankr.com/arbitrum', + rpc: 'https://arb-mainnet.g.alchemy.com/v2/tFPlLg-MT8uGkM5wKHyoBqEHWJJ0o3Nt|https://endpoints.omniatech.io/v1/arbitrum/one/public|https://rpc.ankr.com/arbitrum', id: 42161, network: 'ARBITRUM', symbol: 'ETH', diff --git a/src/config/events.json b/src/config/events.json index cb62d99..fea775a 100644 --- a/src/config/events.json +++ b/src/config/events.json @@ -1,9 +1,10 @@ [ { - "address": "0x8135D4F16A7AAA269cbf61CE9659D3A272BF541f", - "event": "Confirmation", - "abi": "BEMultiSigWallet", - "fromBlock": 34353697, - "eventProcesser": "ScheduleConfirmEvent" + "address": "0x3F13F83E6363D97d0353cAAfACA08B05D9BF3637", + "chain": 42161, + "event": "Transfer", + "abi": "ERC721", + "fromBlock": 105016690, + "eventProcesser": "NftTransferEvent" } ] diff --git a/src/models/FtTransferEvent.ts b/src/models/FtTransferEvent.ts index 1f47a7d..b48c689 100644 --- a/src/models/FtTransferEvent.ts +++ b/src/models/FtTransferEvent.ts @@ -3,12 +3,14 @@ import { dbconn } from 'decorators/dbconn' import { BaseModule } from './Base' @dbconn() -@index({ address: 1 }, { unique: false }) -@index({ transactionHash: 1, from: 1, to: 1 }, { unique: true }) +@index({ address: 1, chain: 1 }, { unique: false }) +@index({ chain: 1, transactionHash: 1, address: 1, from: 1, to: 1 }, { unique: true }) @modelOptions({ schemaOptions: { collection: 'ft_transfer_event', timestamps: true }, }) export class FtTransferEventClass extends BaseModule { + @prop() + public chain: number @prop({ required: true }) public address!: string @prop() @@ -16,6 +18,10 @@ export class FtTransferEventClass extends BaseModule { @prop({ required: true }) public transactionHash: string @prop() + public transactionIndex: number + @prop() + public logIndex: number + @prop() public blockNumber: number @prop() public blockHash: string @@ -28,6 +34,8 @@ export class FtTransferEventClass extends BaseModule { @prop() public amount: string @prop() + public eventId: string + @prop() public blockTime: number public static async saveEvent(event: any) { @@ -35,21 +43,36 @@ export class FtTransferEventClass extends BaseModule { if (amount == undefined) { return } - const from = event.returnValues?.from - const to = event.returnValues?.to + const from = (event.source || event.returnValues?.from).toLowerCase() + const to = (event.target || event.returnValues?.to).toLowerCase() + const address = (event.address || event.tokenAddress).toLowerCase() const data = { - address: event.address, - blockNumber: event.blockNumber, + chain: event.chain, + address, + blockNumber: event.blockHeight || event.blockNumber, blockHash: event.blockHash, removed: event.removed, event: event.event, from, to, - transactionHash: event.transactionHash, + transactionHash: event.transactionHash || event.hash, + transactionIndex: event.transactionIndex, amount, - blockTime: event.timestamp * 1000 + eventId: event.id, + logIndex: event.logIndex, + blockTime: event.timestamp, + $inc: { version: 1 }, } - return FtTransferEvent.insertOrUpdate({ transactionHash: event.transactionHash, amount, from, to }, data) + return FtTransferEvent.insertOrUpdate( + { + chain: event.chain, + address, + amount, + from, + to, + }, + data, + ) } } diff --git a/src/models/NftTransferEvent.ts b/src/models/NftTransferEvent.ts index 61ed427..7d53c62 100644 --- a/src/models/NftTransferEvent.ts +++ b/src/models/NftTransferEvent.ts @@ -3,12 +3,14 @@ import { dbconn } from 'decorators/dbconn' import { BaseModule } from './Base' @dbconn() -@index({ tokenId: 1 }, { unique: false }) -@index({ transactionHash: 1, tokenId: 1, from: 1, to: 1 }, { unique: true }) +@index({ address: 1, chain: 1 }, { unique: false }) +@index({ chain: 1, transactionHash: 1, address: 1, tokenId: 1, from: 1, to: 1 }, { unique: true }) @modelOptions({ schemaOptions: { collection: 'nft_transfer_event', timestamps: true }, }) export class NftTransferEventClass extends BaseModule { + @prop({ required: true }) + public chain: number @prop({ required: true }) public address!: string @prop() @@ -16,6 +18,10 @@ export class NftTransferEventClass extends BaseModule { @prop({ required: true }) public transactionHash: string @prop() + public transactionIndex: number + @prop() + public logIndex: number + @prop() public blockNumber: number @prop() public blockHash: string @@ -28,33 +34,48 @@ export class NftTransferEventClass extends BaseModule { @prop() public tokenId: string @prop() + public eventId: string + @prop() public blockTime: number @prop({ default: 0 }) public version: number public static async saveEvent(event: any) { - if (!event.success) { - return - } - const tokenId = event.tokenId + const tokenId = event.tokenId || event.returnValues?.tokenId if (!tokenId) { return } - const from = event.source - const to = event.target + const from = (event.source || event.returnValues?.from).toLowerCase() + const to = (event.target || event.returnValues?.to).toLowerCase() + const address = (event.address || event.tokenAddress).toLowerCase() const data = { - address: event.tokenAddress, - blockNumber: event.blockHeight, + chain: event.chain, + address, + blockNumber: event.blockHeight || event.blockNumber, + blockHash: event.blockHash, removed: event.removed, from, to, - transactionHash: event.hash, + transactionHash: event.transactionHash || event.hash, + transactionIndex: event.transactionIndex, tokenId, - blockTime: new Date(event.time).getTime(), + eventId: event.id, + logIndex: event.logIndex, + blockTime: event.timestamp, $inc: { version: 1 }, } - return NftTransferEvent.insertOrUpdate({ transactionHash: event.hash, tokenId, from, to }, data) + return NftTransferEvent.insertOrUpdate( + { + chain: event.chain, + transactionHash: event.transactionHash || event.hash, + address, + tokenId, + from, + to, + }, + data, + ) } } diff --git a/src/models/ScheduleConfirmEvent.ts b/src/models/ScheduleConfirmEvent.ts index 8922f0c..e61d1e8 100644 --- a/src/models/ScheduleConfirmEvent.ts +++ b/src/models/ScheduleConfirmEvent.ts @@ -1,7 +1,6 @@ import { getModelForClass, index, modelOptions, prop } from '@typegoose/typegoose' import { dbconn } from 'decorators/dbconn' import logger from 'logger/logger' -import { TaskSvr } from 'service/task.service' import { BaseModule } from './Base' @dbconn() @@ -52,7 +51,7 @@ export class ScheduleConfirmEventClass extends BaseModule { if (record.version === 1) { logger.log('receive events: ' + JSON.stringify(record.scheduleIds)) for (let id of record.scheduleIds) { - await new TaskSvr().parseOneSchedule(id) + // await new TaskSvr().parseOneSchedule(id) } } return record diff --git a/src/monitor.ts b/src/monitor.ts index 226ad42..8814e52 100644 --- a/src/monitor.ts +++ b/src/monitor.ts @@ -6,8 +6,6 @@ dotenv.config({ path: envFile }) import { EventSyncSvr } from 'service/event.sync.service' import { NftTransferEvent } from 'models/NftTransferEvent' import { FtTransferEvent } from 'models/FtTransferEvent' -import { ScheduleConfirmEvent } from 'models/ScheduleConfirmEvent' -import { ScheduleExecutedEvent } from 'models/ScheduleExecutedEvent' import 'common/Extend' @@ -17,8 +15,6 @@ let lock = false let eventProcessers = { NftTransferEvent: NftTransferEvent, FtTransferEvent: FtTransferEvent, - ScheduleConfirmEvent: ScheduleConfirmEvent, - ScheduleExecutedEvent: ScheduleExecutedEvent, } const events = require('config/events.json') @@ -27,7 +23,8 @@ async function initEventSvrs() { // let nfts = [{ address: '0x37c30a2945799a53c5358636a721b442458fa691' }] for (let event of events) { let eventSvr = new EventSyncSvr({ - address: event.address, + chain: event.chain, + address: event.address.toLowerCase(), event: event.event, abi: require('abis/' + event.abi + '.json').abi, fromBlock: event.fromBlock, diff --git a/src/service/event.sync.service.ts b/src/service/event.sync.service.ts index 8dc0cd2..a695c53 100644 --- a/src/service/event.sync.service.ts +++ b/src/service/event.sync.service.ts @@ -2,7 +2,6 @@ import assert from 'assert' import { AllChains } from 'chain/allchain' import { HttpRetryProvider } from 'chain/HttpRetryProvider' import logger from 'logger/logger' -import { NftTransferEvent } from 'models/NftTransferEvent' import { RedisClient } from 'redis/RedisClient' import { clearTimeCache, getPastEventsIter, processEvents } from 'utils/contract.util' @@ -17,24 +16,27 @@ export class EventSyncSvr { event: string blockKey = '' address: string + chain: number eventProcesser: any constructor({ + chain, address, event, abi, fromBlock, eventProcesser, }: { + chain: number address: string event: string abi: any fromBlock: number eventProcesser: any }) { - const defaultChain = parseInt(process.env.CHAIN_DEFAULT) - const chainData = AllChains.find(o => o.id === defaultChain) - assert(chainData, `chain data with ${defaultChain} not found`) + this.chain = chain + const chainData = AllChains.find(o => o.id === chain) + assert(chainData, `chain data with ${this.chain} not found`) this.provider = new HttpRetryProvider(chainData.rpc.split('|')) // @ts-ignore this.web3 = new Web3(this.provider) @@ -42,7 +44,7 @@ export class EventSyncSvr { this.address = this.contract.options.address this.event = event this.fromBlock = fromBlock - this.blockKey = `${address.toLowerCase()}_${event}` + this.blockKey = `${chain}_${address.toLowerCase()}_${event}` this.eventProcesser = eventProcesser } @@ -58,13 +60,14 @@ export class EventSyncSvr { } logger.log(`query events:: ${this.event} address: ${this.address} from: ${this.fromBlock} to: ${this.toBlock}`) let events = getPastEventsIter({ + chain: this.chain, contract: this.contract, event: this.event, fromBlock: this.fromBlock, toBlock: this.toBlock, }) // this.fromBlock = this.toBlock - await processEvents(this.web3, events, this.eventProcesser.saveEvent) + await processEvents(this.web3, events, this.chain, this.eventProcesser.saveEvent) // 处理完一种nft后, 清楚block的timestamp缓存 clearTimeCache() } diff --git a/src/utils/contract.util.ts b/src/utils/contract.util.ts index 0c08cc5..d786228 100644 --- a/src/utils/contract.util.ts +++ b/src/utils/contract.util.ts @@ -170,12 +170,14 @@ export async function getPastEvents({ } export function* getPastEventsIter({ + chain, contract, event, fromBlock, toBlock, options, }: { + chain: number contract: any event: string fromBlock: number @@ -183,7 +185,7 @@ export function* getPastEventsIter({ options?: any }) { const address = contract.options.address - const redisKey = `${address.toLowerCase()}_${event}` + const redisKey = `${chain}_${address.toLowerCase()}_${event}` logger.debug(`*getPastEventsIter: ${event} from: ${fromBlock} to: ${toBlock}`) let from = toBN(fromBlock) let to = toBN(fromBlock).add(queryRange) @@ -198,7 +200,7 @@ export function* getPastEventsIter({ yield new RedisClient().set(redisKey, toBlockBN.add(ONE) + '') } -export async function processEvents(web3, iterator, processedEvent) { +export async function processEvents(web3, iterator, chain: number, processedEvent) { for (const getPastEventPromise of iterator) { const events = await getPastEventPromise for (const event of events) { @@ -211,6 +213,7 @@ export async function processEvents(web3, iterator, processedEvent) { blockTimeMap.set(event.blockNumber, blockData.timestamp) } } + event.chain = chain await processedEvent(event) } }