import { Annotated } from '.'; import { OpticsContext } from '..'; import { Domain } from '../../domains'; import { Result } from '@ethersproject/abi'; import { TypedEvent, TypedEventFilter, } from 'optics-ts-interface/dist/optics-core/commons'; // specifies an interface shared by the TS generated contracts export interface TSContract { queryFilter( event: TypedEventFilter, fromBlockOrBlockhash?: string | number | undefined, toBlock?: string | number | undefined, ): Promise>>; } export async function queryAnnotatedEvents( context: OpticsContext, nameOrDomain: string | number, contract: TSContract, filter: TypedEventFilter, startBlock?: number, endBlock?: number, ): Promise>>> { const events = await getEvents( context, nameOrDomain, contract, filter, startBlock, endBlock, ); return Annotated.fromEvents(context.resolveDomain(nameOrDomain), events); } export async function findAnnotatedSingleEvent( context: OpticsContext, nameOrDomain: string | number, contract: TSContract, filter: TypedEventFilter, startBlock?: number, ): Promise>>> { const events = await findEvent( context, nameOrDomain, contract, filter, startBlock, ); return Annotated.fromEvents(context.resolveDomain(nameOrDomain), events); } export async function getEvents( context: OpticsContext, nameOrDomain: string | number, contract: TSContract, filter: TypedEventFilter, startBlock?: number, endBlock?: number, ): Promise>> { const domain = context.mustGetDomain(nameOrDomain); if (domain.paginate) { return getPaginatedEvents( context, domain, contract, filter, startBlock, endBlock, ); } return contract.queryFilter(filter, startBlock, endBlock); } export async function findEvent( context: OpticsContext, nameOrDomain: string | number, contract: TSContract, filter: TypedEventFilter, startBlock?: number, ): Promise>> { const domain = context.mustGetDomain(nameOrDomain); if (domain.paginate) { return findFromPaginatedEvents( context, domain, contract, filter, startBlock, ); } return contract.queryFilter(filter, startBlock); } async function getPaginatedEvents( context: OpticsContext, domain: Domain, contract: TSContract, filter: TypedEventFilter, startBlock?: number, endBlock?: number, ): Promise>> { if (!domain.paginate) { throw new Error('Domain need not be paginated'); } // get the first block by params // or domain deployment block const firstBlock = startBlock ? Math.max(startBlock, domain.paginate.from) : domain.paginate.from; // get the last block by params // or current block number let lastBlock; if (!endBlock) { const provider = context.mustGetProvider(domain.id); lastBlock = await provider.getBlockNumber(); } else { lastBlock = endBlock; } // query domain pagination limit at a time, concurrently const eventArrayPromises = []; for ( let from = firstBlock; from <= lastBlock; from += domain.paginate.blocks ) { const nextFrom = from + domain.paginate.blocks; const to = Math.min(nextFrom, lastBlock); const eventArrayPromise = contract.queryFilter(filter, from, to); eventArrayPromises.push(eventArrayPromise); } // await promises & concatenate results const eventArrays = await Promise.all(eventArrayPromises); let events: Array> = []; for (const eventArray of eventArrays) { events = events.concat(eventArray); } return events; } async function findFromPaginatedEvents( context: OpticsContext, domain: Domain, contract: TSContract, filter: TypedEventFilter, startBlock?: number, endBlock?: number, ): Promise>> { if (!domain.paginate) { throw new Error('Domain need not be paginated'); } // get the first block by params // or domain deployment block const firstBlock = startBlock ? Math.max(startBlock, domain.paginate.from) : domain.paginate.from; // get the last block by params // or current block number let lastBlock; if (!endBlock) { const provider = context.mustGetProvider(domain.id); lastBlock = await provider.getBlockNumber(); } else { lastBlock = endBlock; } // query domain pagination limit at a time, concurrently // eslint-disable-next-line for-direction for ( let end = lastBlock; end > firstBlock; end -= domain.paginate.blocks ) { const nextEnd = end - domain.paginate.blocks; const from = Math.max(nextEnd, firstBlock); const queriedEvents = await contract.queryFilter(filter, from, end); if (queriedEvents.length > 0) { return queriedEvents; } } return []; }