UNPKG

shove-js

Version:

SDK for shove.bet

123 lines (107 loc) 3.35 kB
import { TopicFilter } from "ethers"; import { JsonRpcProvider } from "ethers"; import { Interface } from "ethers"; import { Contract, ContractRunner, InterfaceAbi, Overrides } from "ethers"; export class BaseContract { protected readonly contract: Contract; public address: string; private blockTimestampCache = new Map<number, number>(); constructor(address: string, abi: InterfaceAbi, runner: ContractRunner) { this.address = address; this.contract = new Contract(address, abi, runner); } public getInterface(): Interface { return this.contract.interface; } private async call<T = any>( method: string, args: any, overrides?: Overrides, ): Promise<T> { const fn = (this.contract as any)[method]; if (typeof fn !== "function") { throw new Error(`Method "${method}" not found on contract`); } const result = await fn(...args, { ...overrides }); return result as T; } protected async read<T = any>( method: string, args: unknown[] = [], overrides?: Overrides, ): Promise<T> { return this.call<T>(method, args, overrides); } protected async write<T = any>( method: string, args: unknown[] = [], overrides?: Overrides, ): Promise<T> { return this.call<T>(method, args, overrides); } async getEvents<T = unknown>( filterArgs: TopicFilter = [], fromBlock?: number | string, toBlock?: number | string, parser?: (entry: { name?: string; args?: any; blockNumber: number; transactionHash: string; log: any; timestamp: number | null; }) => T, ): Promise<T[]> { const provider = this.contract.runner?.provider! as JsonRpcProvider; if (!provider || typeof provider.getLogs !== "function") { throw new Error("Provider not available to fetch logs from the contract"); } const parseRaw = (log: any) => { try { const parsed = this.contract.interface.parseLog(log); return { name: parsed!.name, args: parsed!.args, blockNumber: log.blockNumber, transactionHash: log.transactionHash, log, }; } catch (err) { return { name: undefined, args: undefined, blockNumber: log.blockNumber, transactionHash: log.transactionHash, log, }; } }; let logs: any[]; logs = await provider.getLogs({ address: this.address, topics: filterArgs, fromBlock, toBlock, }); const parsedEntries = logs.map(parseRaw); const uniqueBlocks = Array.from( new Set(parsedEntries.map((e) => e.blockNumber).filter((bn) => !!bn)), ) as number[]; const missingBlocks = uniqueBlocks.filter( (bn) => !this.blockTimestampCache.has(bn), ); if (missingBlocks.length) { const blockPromises = missingBlocks.map((bn) => provider.getBlock(bn)); const blocks = await Promise.all(blockPromises); for (const b of blocks) { if (b) this.blockTimestampCache.set(b.number, b.timestamp); } } const entriesWithTs = parsedEntries.map((e) => ({ ...e, timestamp: this.blockTimestampCache.get(e.blockNumber) ?? null, })); if (parser) return entriesWithTs.map(parser); return entriesWithTs as unknown as T[]; } }