-
Notifications
You must be signed in to change notification settings - Fork 52
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(relayer): Factor out common listener utils (#1841)
This is a pre-emptive change made to make it easier to reuse common components in alternative listener implementations. Examples for a viem-based listener, as well as an eventual Solana listener. There are subsequent changes in the pipeline to factor out evm-specific parts.
- Loading branch information
Showing
5 changed files
with
144 additions
and
117 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
export { Log } from "../interfaces"; | ||
export { SpokePoolClientMessage } from "../clients"; | ||
|
||
export type ScraperOpts = { | ||
lookback?: number; // Event lookback (in seconds). | ||
deploymentBlock: number; // SpokePool deployment block | ||
maxBlockRange?: number; // Maximum block range for paginated getLogs queries. | ||
filterArgs?: { [event: string]: string[] }; // Event-specific filter criteria to apply. | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from "./util"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import assert from "assert"; | ||
import { Contract, EventFilter } from "ethers"; | ||
import { getNetworkName, isDefined, paginatedEventQuery, winston } from "../../../utils"; | ||
import { Log, ScraperOpts } from "../../types"; | ||
|
||
/** | ||
* Given an event name and contract, return the corresponding Ethers EventFilter object. | ||
* @param contract Ethers Constract instance. | ||
* @param eventName The name of the event to be filtered. | ||
* @param filterArgs Optional filter arguments to be applied. | ||
* @returns An Ethers EventFilter instance. | ||
*/ | ||
export function getEventFilter(contract: Contract, eventName: string, filterArgs?: string[]): EventFilter { | ||
const filter = contract.filters[eventName]; | ||
if (!isDefined(filter)) { | ||
throw new Error(`Event ${eventName} not defined for contract`); | ||
} | ||
|
||
return isDefined(filterArgs) ? filter(...filterArgs) : filter(); | ||
} | ||
|
||
/** | ||
* Get a general event filter mapping to be used for filtering SpokePool contract events. | ||
* This is currently only useful for filtering the relayer address on FilledV3Relay events. | ||
* @param relayer Optional relayer address to filter on. | ||
* @returns An argument array for input to an Ethers EventFilter. | ||
*/ | ||
export function getEventFilterArgs(relayer?: string): { [event: string]: (null | string)[] } { | ||
const FilledV3Relay = !isDefined(relayer) | ||
? undefined | ||
: [null, null, null, null, null, null, null, null, null, null, relayer]; | ||
|
||
return { FilledV3Relay }; | ||
} | ||
|
||
/** | ||
* Given a SpokePool contract instance and an event name, scrape all corresponding events and submit them to the | ||
* parent process (if defined). | ||
* @param spokePool Ethers Constract instance. | ||
* @param eventName The name of the event to be filtered. | ||
* @param opts Options to configure event scraping behaviour. | ||
* @returns void | ||
*/ | ||
export async function scrapeEvents( | ||
spokePool: Contract, | ||
eventName: string, | ||
opts: ScraperOpts & { toBlock: number }, | ||
logger: winston.Logger | ||
): Promise<Log[]> { | ||
const { lookback, deploymentBlock, filterArgs, maxBlockRange, toBlock } = opts; | ||
const { chainId } = await spokePool.provider.getNetwork(); | ||
const chain = getNetworkName(chainId); | ||
|
||
const fromBlock = Math.max(toBlock - (lookback ?? deploymentBlock), deploymentBlock); | ||
assert(toBlock > fromBlock, `${toBlock} > ${fromBlock}`); | ||
const searchConfig = { fromBlock, toBlock, maxBlockLookBack: maxBlockRange }; | ||
|
||
const tStart = performance.now(); | ||
const filter = getEventFilter(spokePool, eventName, filterArgs[eventName]); | ||
const events = await paginatedEventQuery(spokePool, filter, searchConfig); | ||
const tStop = performance.now(); | ||
logger.debug({ | ||
at: "scrapeEvents", | ||
message: `Scraped ${events.length} ${chain} ${eventName} events in ${Math.round((tStop - tStart) / 1000)} seconds`, | ||
searchConfig, | ||
}); | ||
|
||
return events; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { utils as sdkUtils } from "@across-protocol/sdk"; | ||
import { isDefined, sortEventsAscending } from "../../utils"; | ||
import { Log, SpokePoolClientMessage } from "./../types"; | ||
|
||
/** | ||
* Given the inputs for a SpokePoolClient update, consolidate the inputs into a message and submit it to the parent | ||
* process (if defined). | ||
* @param blockNumber Block number up to which the update applies. | ||
* @param currentTime The SpokePool timestamp at blockNumber. | ||
* @param events An array of Log objects to be submitted. | ||
* @returns void | ||
*/ | ||
export function postEvents(blockNumber: number, oldestTime: number, currentTime: number, events: Log[]): void { | ||
if (!isDefined(process.send)) { | ||
return; | ||
} | ||
|
||
events = sortEventsAscending(events); | ||
const message: SpokePoolClientMessage = { | ||
blockNumber, | ||
currentTime, | ||
oldestTime, | ||
nEvents: events.length, | ||
data: JSON.stringify(events, sdkUtils.jsonReplacerWithBigNumbers), | ||
}; | ||
process.send(JSON.stringify(message)); | ||
} | ||
|
||
/** | ||
* Given an event removal notification, post the message to the parent process. | ||
* @param event Log instance. | ||
* @returns void | ||
*/ | ||
export function removeEvent(event: Log): void { | ||
if (!isDefined(process.send)) { | ||
return; | ||
} | ||
|
||
const message: SpokePoolClientMessage = { | ||
event: JSON.stringify(event, sdkUtils.jsonReplacerWithBigNumbers), | ||
}; | ||
process.send(JSON.stringify(message)); | ||
} |