UNPKG

@atomiqlabs/chain-evm

Version:

EVM specific base implementation

140 lines (125 loc) 5.8 kB
import {EVMModule} from "../EVMModule"; import {Log} from "ethers"; export class EVMEvents extends EVMModule<any> { /** * Returns the all the events occuring in a block range as identified by the contract and keys * * @param contract * @param topics * @param startBlock * @param endBlock * @param abortSignal */ public async getBlockEvents( contract: string, topics: (string[] | string | null)[], startBlock?: number, endBlock: number = startBlock, abortSignal?: AbortSignal ): Promise<Log[]> { let events: Log[] = []; if(startBlock===endBlock) { events = await this.root.provider.getLogs({ address: contract, fromBlock: startBlock==null ? this.root.config.safeBlockTag : startBlock, toBlock: endBlock==null ? this.root.config.safeBlockTag : endBlock, topics }); } else if(endBlock==null) { const safeBlock = await this.root.provider.getBlock(this.root.config.safeBlockTag); if(safeBlock.number - startBlock > this.root.config.maxLogsBlockRange) { for(let i = startBlock + this.root.config.maxLogsBlockRange; i < safeBlock.number; i += this.root.config.maxLogsBlockRange) { events.push(...await this.root.provider.getLogs({ address: contract, fromBlock: i - this.root.config.maxLogsBlockRange, toBlock: i, topics })); startBlock = i; } } events.push(...await this.root.provider.getLogs({ address: contract, fromBlock: startBlock==null ? this.root.config.safeBlockTag : startBlock, toBlock: endBlock==null ? this.root.config.safeBlockTag : endBlock, topics })); } else { //Both numeric if(endBlock - startBlock > this.root.config.maxLogsBlockRange) { for(let i = startBlock + this.root.config.maxLogsBlockRange; i < endBlock; i += this.root.config.maxLogsBlockRange) { events.push(...await this.root.provider.getLogs({ address: contract, fromBlock: i - this.root.config.maxLogsBlockRange, toBlock: i, topics })); startBlock = i; } } events.push(...await this.root.provider.getLogs({ address: contract, fromBlock: startBlock, toBlock: endBlock, topics })); } return events.filter(val => !val.removed); } /** * Runs a search backwards in time, processing events from a specific contract and keys * * @param contract * @param topics * @param processor called for every batch of returned signatures, should return a value if the correct signature * was found, or null if the search should continue * @param abortSignal * @param genesisHeight Height when the contract was deployed */ public async findInEvents<T>( contract: string, topics: (string[] | string | null)[], processor: (signatures: Log[]) => Promise<T>, abortSignal?: AbortSignal, genesisHeight?: number ): Promise<T> { const {number: latestBlockNumber} = await this.provider.getBlock(this.root.config.safeBlockTag); for(let blockNumber = latestBlockNumber; blockNumber >= (genesisHeight ?? 0); blockNumber-=this.root.config.maxLogsBlockRange) { const eventsResult = await this.provider.getLogs({ address: contract, topics, fromBlock: Math.max(blockNumber-this.root.config.maxLogsBlockRange, 0), toBlock: blockNumber===latestBlockNumber ? this.root.config.safeBlockTag : blockNumber }); if(abortSignal!=null) abortSignal.throwIfAborted(); const result: T = await processor(eventsResult.reverse()); //Newest events first if(result!=null) return result; } return null; } /** * Runs a search forwards in time, processing events from a specific contract and keys * * @param contract * @param topics * @param processor called for every batch of returned signatures, should return a value if the correct signature * was found, or null if the search should continue * @param abortSignal * @param startHeight Blockheight at which to start */ public async findInEventsForward<T>( contract: string, topics: (string[] | string | null)[], processor: (signatures: Log[]) => Promise<T>, abortSignal?: AbortSignal, startHeight?: number ): Promise<T> { const {number: latestBlockNumber} = await this.provider.getBlock(this.root.config.safeBlockTag); for(let blockNumber = startHeight ?? 0; blockNumber < latestBlockNumber; blockNumber += this.root.config.maxLogsBlockRange) { const eventsResult = await this.provider.getLogs({ address: contract, topics, fromBlock: blockNumber, toBlock: (blockNumber + this.root.config.maxLogsBlockRange) > latestBlockNumber ? this.root.config.safeBlockTag : blockNumber + this.root.config.maxLogsBlockRange }); if(abortSignal!=null) abortSignal.throwIfAborted(); const result: T = await processor(eventsResult); //Oldest events first if(result!=null) return result; } return null; } }