UNPKG

ethers-opt

Version:

Collection of heavily optimized functions for ethers.js V6

85 lines (68 loc) 2.67 kB
import type { Provider } from 'ethers'; import { Multicall, Multicall__factory } from './typechain/index.js'; import { MULTICALL_ADDRESS } from './multicall.js'; import { range } from './utils.js'; /** * Compare last 80 blocks to find reorgs */ export interface BlockHash { number: number; hash?: string; } /** * Fetches recent block hashes, using multicall when possible for efficiency. * @param provider The provider (optionally with multicall). * @param knownBlock Optional: block to start from (defaults to latest). * @param depth Optional: how many blocks to look back (default 80). * @returns Array of BlockHash {number, hash}. */ export async function fetchBlockHashes( provider: Provider & { multicall?: Multicall }, knownBlock?: number, // Think that 80 is better to detect reorgs // https://www.reddit.com/r/0xPolygon/comments/10bvruq/polygons_block_reorg_problem_daily_10_depth_reorgs depth = 80, ): Promise<BlockHash[]> { const multicall = provider.multicall || Multicall__factory.connect(MULTICALL_ADDRESS, provider); const head = await provider.getBlockNumber(); if (!knownBlock) { knownBlock = head; } const blocks = await Promise.all( range(knownBlock + 1 - depth, knownBlock).map(async (number) => { // If it is unable to fetch using multicall const outsideState = number + 100 <= head; if (!outsideState) { try { const hash = await multicall.getBlockHash(number); return { number, hash }; // eslint-disable-next-line no-empty } catch {} } const { hash } = (await provider.getBlock(number)) || {}; if (!hash) { throw new Error(`Block hash ${number} not available`); } return { number, hash }; }), ); return blocks; } /** * Returns the first block number where the hashes from two sources disagree (detects reorgs). * @param fromLocal Locally cached block hashes. * @param fromNode Current chain block hashes. * @returns The reorged block number, or undefined if chains match. */ export function compareBlockHashes(fromLocal: BlockHash[], fromNode: BlockHash[]): number | undefined { fromLocal = fromLocal.sort((a, b) => a.number - b.number); for (const localBlock of fromLocal) { const nodeBlock = fromNode.find((a) => a.number === localBlock.number); if (!nodeBlock?.hash) { continue; } if (nodeBlock.hash !== localBlock.hash) { return localBlock.number; } } }