From 6fff88a4be3bc9f55cca70b54f265435ef08a1cb Mon Sep 17 00:00:00 2001 From: nicholaspai <9457025+nicholaspai@users.noreply.github.com> Date: Mon, 9 May 2022 18:04:53 -0400 Subject: [PATCH] fix: Paginate InsuredBridgeL1Client event search for select events (#3902) * WIP * fix test * Update RelayerConfig.ts * Fix across monitor * add await * fix * Update InsuredBridgeL1Client.ts * Update InsuredBridgeL1Client.ts --- package.json | 3 +- packages/across-monitor/src/AcrossMonitor.ts | 11 +- .../across-monitor/src/AcrossMonitorConfig.ts | 21 +++ .../across-monitor/src/RelayEventProcessor.ts | 79 +++-------- packages/across-monitor/src/index.ts | 12 +- .../src/clients/InsuredBridgeL1Client.ts | 130 +++++++++++++----- .../src/RelayerConfig.ts | 21 +++ packages/insured-bridge-relayer/src/index.ts | 10 +- packages/insured-bridge-relayer/test/index.ts | 4 + yarn.lock | 6 +- 10 files changed, 186 insertions(+), 111 deletions(-) diff --git a/package.json b/package.json index 16e8994cb4..7de27330dd 100644 --- a/package.json +++ b/package.json @@ -74,5 +74,6 @@ "packages": [ "packages/*" ] - } + }, + "dependencies": {} } diff --git a/packages/across-monitor/src/AcrossMonitor.ts b/packages/across-monitor/src/AcrossMonitor.ts index 5c9767873b..8d6016f1ad 100644 --- a/packages/across-monitor/src/AcrossMonitor.ts +++ b/packages/across-monitor/src/AcrossMonitor.ts @@ -33,7 +33,7 @@ export class AcrossMonitor { readonly monitorConfig: AcrossMonitorConfig, readonly l1Client: InsuredBridgeL1Client ) { - this.relayEventProcessor = new RelayEventProcessor(); + this.relayEventProcessor = new RelayEventProcessor(l1Client); } async update(): Promise { @@ -60,7 +60,7 @@ export class AcrossMonitor { // misconfiguration). this.startingBlock = Math.min(this.startingBlock, this.endingBlock); - await this.relayEventProcessor.update(this.endingBlock); + this.relayEventProcessor.update(this.endingBlock); } async checkUtilization(): Promise { @@ -110,13 +110,10 @@ export class AcrossMonitor { return; } - async checkUnknownRelayers(): Promise { + checkUnknownRelayers(): void { this.logger.debug({ at: "AcrossMonitor#UnknownRelayers", message: "Checking for unknown relayers" }); - const relayEvents: EventInfo[] = await this.relayEventProcessor.getRelayEventInfo( - this.startingBlock, - this.endingBlock - ); + const relayEvents: EventInfo[] = this.relayEventProcessor.getRelayEventInfo(this.startingBlock, this.endingBlock); for (const event of relayEvents) { // Skip notifications for known relay caller addresses. if (this.monitorConfig.whitelistedAddresses.includes(toChecksumAddress(event.caller))) { diff --git a/packages/across-monitor/src/AcrossMonitorConfig.ts b/packages/across-monitor/src/AcrossMonitorConfig.ts index 01e81f829e..0a48e4afc1 100644 --- a/packages/across-monitor/src/AcrossMonitorConfig.ts +++ b/packages/across-monitor/src/AcrossMonitorConfig.ts @@ -11,6 +11,16 @@ export interface BotModes { unknownRelayersEnabled: boolean; // Monitors relay related events triggered by non-whitelisted addresses } +// Following settings can be overridden to optimize L1 event search for select events. For example, +// the "DepositRelayed" event search request could return > 10,000 return values so we need to shorten the block +// search using these parameters because some node providers like Infura limit event search return values to 10,000. + +// This is set to the oldest SpokePool's deploy block height because we can assume that there will not be any +// BridgePool events on any BridgePool at blocks lower than this height. This is specifically the WETH +// BridgePool's deploy block. +export const bridgePoolEarliestBlockToSearch = 13545377; +export const bridgePoolMaxBlocksToSeach = 1_000_000; + export class AcrossMonitorConfig { readonly bridgeAdminChainId: number; @@ -20,6 +30,8 @@ export class AcrossMonitorConfig { readonly startingBlock: number | undefined; readonly endingBlock: number | undefined; + readonly bridgePoolEarliestBlockToSearch: number; + readonly bridgePoolMaxBlocksToSeach: number; readonly utilizationThreshold: number; readonly whitelistedAddresses: string[]; @@ -37,6 +49,8 @@ export class AcrossMonitorConfig { WHITELISTED_ADDRESSES, UTILIZATION_ENABLED, UNKNOWN_RELAYERS_ENABLED, + BRIDGE_POOL_EVENT_SEARCH_FROM_BLOCK, + BRIDGE_POOL_MAX_BLOCKS_TO_SEARCH, } = env; this.botModes = { @@ -65,5 +79,12 @@ export class AcrossMonitorConfig { // In serverless mode use block range from environment to fetch for latest events. this.startingBlock = STARTING_BLOCK_NUMBER ? Number(STARTING_BLOCK_NUMBER) : undefined; this.endingBlock = ENDING_BLOCK_NUMBER ? Number(ENDING_BLOCK_NUMBER) : undefined; + + this.bridgePoolEarliestBlockToSearch = BRIDGE_POOL_EVENT_SEARCH_FROM_BLOCK + ? Number(BRIDGE_POOL_EVENT_SEARCH_FROM_BLOCK) + : bridgePoolEarliestBlockToSearch; + this.bridgePoolMaxBlocksToSeach = BRIDGE_POOL_MAX_BLOCKS_TO_SEARCH + ? Number(BRIDGE_POOL_MAX_BLOCKS_TO_SEARCH) + : bridgePoolMaxBlocksToSeach; } } diff --git a/packages/across-monitor/src/RelayEventProcessor.ts b/packages/across-monitor/src/RelayEventProcessor.ts index 12e46c89c0..8d77588af5 100644 --- a/packages/across-monitor/src/RelayEventProcessor.ts +++ b/packages/across-monitor/src/RelayEventProcessor.ts @@ -1,23 +1,11 @@ -import type { BridgePoolData } from "@uma/financial-templates-lib"; - -// Note that Relay parameters are narrower in this module than in @uma/financial-templates-lib. -interface Relay { - chainId: number; - depositId: number; - l2Sender: string; - l1Recipient: string; - amount: string; - slowRelayFeePct: string; - instantRelayFeePct: string; - realizedLpFeePct: string; - depositHash: string; -} +import type { BridgePoolData, InsuredBridgeL1Client, RelayedDeposit } from "@uma/financial-templates-lib"; +import { EventData } from "web3-eth-contract"; export interface EventInfo { l1Token: string; poolCollateralDecimals: number; poolCollateralSymbol: string; - relay: Relay; + relay: RelayedDeposit; caller: string; action: string; transactionHash: string; @@ -30,7 +18,7 @@ export class RelayEventProcessor { private lastRelayUpdate = -1; // DepositRelayed events are fetched from lastRelayUpdate + 1 block. - private deposits: { [key: string]: { [key: string]: Relay } } = {}; // L1TokenAddress=>depositHash=>Relay. + private deposits: { [key: string]: { [key: string]: RelayedDeposit } } = {}; // L1TokenAddress=>depositHash=>Relay. private eventActions: { [key: string]: string } = { DepositRelayed: "slow relayed", RelaySpedUp: "sped up", @@ -39,14 +27,14 @@ export class RelayEventProcessor { RelayCanceled: "canceled", }; - constructor() { + constructor(readonly l1Client: InsuredBridgeL1Client) { // do nothing. } - // update() should be called only after having populated bridgePools. + // update() should be called only after having updated L1 client // This fetches all DepositRelayed events since lastRelayUpdate block in order to store deposit and relay hash // mappings that could be referenced by other events. - async update(endingBlock: number): Promise { + update(endingBlock: number): void { // Only update if endingBlock is more recent than the lastRelayUpdate block from last update() call. const startingBlock = this.lastRelayUpdate + 1; if (startingBlock > endingBlock) { @@ -58,58 +46,25 @@ export class RelayEventProcessor { this.deposits[l1TokenAddress] = this.deposits[l1TokenAddress] ? this.deposits[l1TokenAddress] : {}; } - await Promise.all( - Object.keys(this.bridgePools).map(async (l1TokenAddress) => { - const depositRelayedEvents = await this.bridgePools[l1TokenAddress].contract.getPastEvents("DepositRelayed", { - fromBlock: startingBlock, - toBlock: endingBlock, - }); - for (const depositRelayedEvent of depositRelayedEvents) { - const relayData: Relay = { - chainId: Number(depositRelayedEvent.returnValues.depositData.chainId), - depositId: Number(depositRelayedEvent.returnValues.depositData.depositId), - l2Sender: depositRelayedEvent.returnValues.depositData.l2Sender, - l1Recipient: depositRelayedEvent.returnValues.depositData.l1Recipient, - amount: depositRelayedEvent.returnValues.depositData.amount, - slowRelayFeePct: depositRelayedEvent.returnValues.depositData.slowRelayFeePct, - instantRelayFeePct: depositRelayedEvent.returnValues.depositData.instantRelayFeePct, - realizedLpFeePct: depositRelayedEvent.returnValues.relay.realizedLpFeePct, - depositHash: depositRelayedEvent.returnValues.depositHash, - }; - this.deposits[l1TokenAddress][depositRelayedEvent.returnValues.depositHash] = relayData; - } - }) - ); + // This will return all relayed deposit data including disputed ones. + for (const relayData of this.l1Client.getAllRelayedDepositsSimple()) { + this.deposits[relayData.l1Token][relayData.depositHash] = relayData; + } this.lastRelayUpdate = endingBlock; } - async getRelayEventInfo(startingBlock: number | undefined, endingBlock: number | undefined): Promise { - const blockSearchConfig = { fromBlock: startingBlock, toBlock: endingBlock }; + getRelayEventInfo(startingBlock: number | undefined, endingBlock: number | undefined): EventInfo[] { const relayEvents: EventInfo[] = []; // Fetch all relay related events. for (const [l1TokenAddress, bridgePool] of Object.entries(this.bridgePools)) { - const [ - depositRelayedEvents, - relaySpedUpEvents, - relaySettledEvents, - relayDisputedEvents, - relayCanceledEvents, - ] = await Promise.all([ - bridgePool.contract.getPastEvents("DepositRelayed", blockSearchConfig), - bridgePool.contract.getPastEvents("RelaySpedUp", blockSearchConfig), - bridgePool.contract.getPastEvents("RelaySettled", blockSearchConfig), - bridgePool.contract.getPastEvents("RelayDisputed", blockSearchConfig), - bridgePool.contract.getPastEvents("RelayCanceled", blockSearchConfig), - ]); - // Process all relay related events, get caller, type and match with additional properties by depositHash that // were cached on update(). - const allEvents = depositRelayedEvents - .concat(relaySpedUpEvents) - .concat(relaySettledEvents) - .concat(relayDisputedEvents) - .concat(relayCanceledEvents); + const allEvents = this.l1Client.allRelayEventData[bridgePool.contract.options.address].filter( + (e: EventData) => + (startingBlock === undefined || e.blockNumber >= startingBlock) && + (endingBlock === undefined || e.blockNumber <= endingBlock) + ); for (const event of allEvents) { const depositHash = event.returnValues.depositHash; if (!this.deposits[l1TokenAddress][depositHash]) { diff --git a/packages/across-monitor/src/index.ts b/packages/across-monitor/src/index.ts index 122be89dbd..a6995cd8da 100644 --- a/packages/across-monitor/src/index.ts +++ b/packages/across-monitor/src/index.ts @@ -25,7 +25,15 @@ export async function run(logger: winston.Logger, l1Web3: Web3): Promise { // l1Client uses bridgeAdmin contract for bridge pool discovery. const bridgeAdminAddress = await getAddress("BridgeAdmin", config.bridgeAdminChainId); - const l1Client = new InsuredBridgeL1Client(logger, l1Web3, bridgeAdminAddress, null); + const l1Client = new InsuredBridgeL1Client( + logger, + l1Web3, + bridgeAdminAddress, + null, + config.bridgePoolEarliestBlockToSearch, + null, // Use latest block as end block + config.bridgePoolMaxBlocksToSeach + ); const acrossMonitor = new AcrossMonitor(logger, config, l1Client); @@ -39,7 +47,7 @@ export async function run(logger: winston.Logger, l1Web3: Web3): Promise { if (config.botModes.utilizationEnabled) await acrossMonitor.checkUtilization(); else logger.debug({ at: "AcrossMonitor#Utilization", message: "Utilization monitor disabled" }); - if (config.botModes.unknownRelayersEnabled) await acrossMonitor.checkUnknownRelayers(); + if (config.botModes.unknownRelayersEnabled) acrossMonitor.checkUnknownRelayers(); else logger.debug({ at: "AcrossMonitor#UnknownRelayers", message: "UnknownRelayers monitor disabled" }); }, { diff --git a/packages/financial-templates-lib/src/clients/InsuredBridgeL1Client.ts b/packages/financial-templates-lib/src/clients/InsuredBridgeL1Client.ts index bee4178458..6d0f26bd5d 100644 --- a/packages/financial-templates-lib/src/clients/InsuredBridgeL1Client.ts +++ b/packages/financial-templates-lib/src/clients/InsuredBridgeL1Client.ts @@ -5,11 +5,13 @@ import { BlockFinder } from "../price-feed/utils"; import { getAbi } from "@uma/contracts-node"; import { Deposit } from "./InsuredBridgeL2Client"; import { across } from "@uma/sdk"; +import { getEventsWithPaginatedBlockSearch, Web3Contract } from "@uma/common"; import type { BridgeAdminInterfaceWeb3, BridgePoolWeb3, RateModelStoreWeb3 } from "@uma/contracts-node"; import type { Logger } from "winston"; import type { BN } from "@uma/common"; import type { BlockTransactionBase } from "web3-eth"; +import { EventData } from "web3-eth-contract"; export enum ClientRelayState { Uninitialized, // Deposit on L2, nothing yet on L1. Can be slow relayed and can be sped up to instantly relay. @@ -23,21 +25,11 @@ export enum SettleableRelay { AnyoneCanSettle, } -export interface Relay { +export interface Relay extends RelayedDeposit { relayId: number; - chainId: number; - depositId: number; - l2Sender: string; slowRelayer: string; - l1Recipient: string; - l1Token: string; - amount: string; - slowRelayFeePct: string; - instantRelayFeePct: string; quoteTimestamp: number; - realizedLpFeePct: string; priceRequestTime: number; - depositHash: string; relayState: ClientRelayState; relayAncillaryDataHash: string; proposerBond: string; @@ -46,6 +38,19 @@ export interface Relay { blockNumber: number; } +export interface RelayedDeposit { + chainId: number; + depositId: number; + l1Token: string; + l2Sender: string; + l1Recipient: string; + amount: string; + slowRelayFeePct: string; + instantRelayFeePct: string; + realizedLpFeePct: string; + depositHash: string; +} + export interface InstantRelay { instantRelayer: string; } @@ -79,9 +84,16 @@ export class InsuredBridgeL1Client { public optimisticOracleLiveness = 0; public firstBlockToSearch: number; + // The main difference between `relays` and `deposits` is that `relayedDeposits` are deleted if they are disputed. + // Also, `relays` contain more props that track the Relay lifecycle. private relays: { [key: string]: { [key: string]: Relay } } = {}; // L1TokenAddress=>depositHash=>Relay. + private relayedDeposits: { [key: string]: { [key: string]: RelayedDeposit } } = {}; + private instantRelays: { [key: string]: { [key: string]: InstantRelay } } = {}; // L1TokenAddress=>{depositHash, realizedLpFeePct}=>InstantRelay. + // Stored event raw data used by Across Mainnet monitor + public readonly allRelayEventData: { [bridgePoolAddress: string]: EventData[] } = {}; + private readonly blockFinder: BlockFinder; constructor( @@ -90,7 +102,8 @@ export class InsuredBridgeL1Client { readonly bridgeAdminAddress: string, readonly rateModelStoreAddress: string | null, readonly startingBlockNumber = 0, - readonly endingBlockNumber: number | null = null + readonly endingBlockNumber: number | null = null, + readonly blocksPerEventSearch: number | null = null ) { // Cast the following contracts to web3-specific type this.bridgeAdmin = (new l1Web3.eth.Contract( @@ -124,6 +137,17 @@ export class InsuredBridgeL1Client { .flat(); } + getAllRelayedDepositsSimple(): RelayedDeposit[] { + this._throwIfNotInitialized(); + return Object.keys(this.relayedDeposits) + .map((l1Token: string) => + Object.keys(this.relayedDeposits[l1Token]).map( + (depositHash: string) => this.relayedDeposits[l1Token][depositHash] + ) + ) + .flat(); + } + getRelayedDepositsForL1Token(l1Token: string): Relay[] { this._throwIfNotInitialized(); return Object.values(this.relays[l1Token]); @@ -358,6 +382,7 @@ export class InsuredBridgeL1Client { ...l2Tokens, [whitelistedTokenEvent.returnValues.chainId]: toChecksumAddress(whitelistedTokenEvent.returnValues.l2Token), }; + this.relayedDeposits[l1Token] = {}; this.relays[l1Token] = {}; this.instantRelays[l1Token] = {}; } @@ -380,18 +405,10 @@ export class InsuredBridgeL1Client { for (const [l1Token, bridgePool] of Object.entries(this.bridgePools)) { const l1TokenInstance = new this.l1Web3.eth.Contract(getAbi("ERC20"), l1Token); - // This is a hacked solution to fix the problem where there are too many instances of the following events - // returned by a Infura, which limits return values to 10,000. So, if there are more than 10,000 - // "DepositRelayed" events returned by the event search, then we need to split up the search at this block. This - // will not be a solution once we hit 20,000 events so this is just a temporary fix. - const paginateBlockNumber = process.env.L1_SPLIT_BLOCK_NUMBER || "0"; const [ - depositRelayedEvents1, - depositRelayedEvents2, - relaySpedUpEvents1, - relaySpedUpEvents2, - relaySettledEvents1, - relaySettledEvents2, + depositRelayedEvents, + relaySpedUpEvents, + relaySettledEvents, relayDisputedEvents, relayCanceledEvents, contractTime, @@ -399,12 +416,27 @@ export class InsuredBridgeL1Client { poolCollateralDecimals, poolCollateralSymbol, ] = await Promise.all([ - bridgePool.contract.getPastEvents("DepositRelayed", { ...blockSearchConfig, toBlock: paginateBlockNumber }), - bridgePool.contract.getPastEvents("DepositRelayed", { ...blockSearchConfig, fromBlock: paginateBlockNumber }), - bridgePool.contract.getPastEvents("RelaySpedUp", { ...blockSearchConfig, toBlock: paginateBlockNumber }), - bridgePool.contract.getPastEvents("RelaySpedUp", { ...blockSearchConfig, fromBlock: paginateBlockNumber }), - bridgePool.contract.getPastEvents("RelaySettled", { ...blockSearchConfig, toBlock: paginateBlockNumber }), - bridgePool.contract.getPastEvents("RelaySettled", { ...blockSearchConfig, fromBlock: paginateBlockNumber }), + getEventsWithPaginatedBlockSearch( + (bridgePool.contract as unknown) as Web3Contract, + "DepositRelayed", + blockSearchConfig.fromBlock, + blockSearchConfig.toBlock, + this.blocksPerEventSearch + ), + getEventsWithPaginatedBlockSearch( + (bridgePool.contract as unknown) as Web3Contract, + "RelaySpedUp", + blockSearchConfig.fromBlock, + blockSearchConfig.toBlock, + this.blocksPerEventSearch + ), + getEventsWithPaginatedBlockSearch( + (bridgePool.contract as unknown) as Web3Contract, + "RelaySettled", + blockSearchConfig.fromBlock, + blockSearchConfig.toBlock, + this.blocksPerEventSearch + ), bridgePool.contract.getPastEvents("RelayDisputed", blockSearchConfig), bridgePool.contract.getPastEvents("RelayCanceled", blockSearchConfig), bridgePool.contract.methods.getCurrentTime().call(), @@ -413,9 +445,25 @@ export class InsuredBridgeL1Client { l1TokenInstance.methods.symbol().call(), ]); - const depositRelayedEvents = [...depositRelayedEvents1, ...depositRelayedEvents2]; - const relaySpedUpEvents = [...relaySpedUpEvents1, ...relaySpedUpEvents2]; - const relaySettledEvents = [...relaySettledEvents1, ...relaySettledEvents2]; + this.allRelayEventData[bridgePool.contract.options.address] = [ + ...depositRelayedEvents.eventData + .concat(relaySpedUpEvents.eventData) + .concat(relaySettledEvents.eventData) + .concat(relayDisputedEvents) + .concat(relayCanceledEvents), + ]; + + this.logger.debug({ + at: "InsuredBridgeL1Client", + message: "Paginated event search results", + bridgePool: bridgePool.contract.options.address, + l1Token: poolCollateralSymbol, + depositRelayedEventRequestCount: depositRelayedEvents.web3RequestCount, + relaySpedUpEventRequestCount: relaySpedUpEvents.web3RequestCount, + relaySettledEventRequestCount: relaySettledEvents.web3RequestCount, + blockSearchConfig, + blocksPerEventSearch: this.blocksPerEventSearch, + }); // Store current contract time and relay nonce that user can use to send instant relays (where there is no pending // relay) for a deposit. Store the l1Token decimals and symbol to enhance logging. @@ -425,7 +473,7 @@ export class InsuredBridgeL1Client { bridgePool.poolCollateralSymbol = poolCollateralSymbol; // Process events an set in state. - for (const depositRelayedEvent of depositRelayedEvents) { + for (const depositRelayedEvent of depositRelayedEvents.eventData) { const relayData: Relay = { relayId: Number(depositRelayedEvent.returnValues.relay.relayId), chainId: Number(depositRelayedEvent.returnValues.depositData.chainId), @@ -449,10 +497,22 @@ export class InsuredBridgeL1Client { blockNumber: depositRelayedEvent.blockNumber, }; this.relays[l1Token][relayData.depositHash] = relayData; + this.relayedDeposits[l1Token][relayData.depositHash] = { + chainId: relayData.chainId, + depositId: relayData.depositId, + l2Sender: relayData.l2Sender, + l1Recipient: relayData.l1Recipient, + l1Token: relayData.l1Token, + amount: relayData.amount, + slowRelayFeePct: relayData.slowRelayFeePct, + instantRelayFeePct: relayData.instantRelayFeePct, + realizedLpFeePct: relayData.realizedLpFeePct, + depositHash: relayData.depositHash, + }; } // For all RelaySpedUp, set the instant relayer. - for (const relaySpedUpEvent of relaySpedUpEvents) { + for (const relaySpedUpEvent of relaySpedUpEvents.eventData) { const instantRelayDataHash = this._getInstantRelayHash( relaySpedUpEvent.returnValues.depositHash, relaySpedUpEvent.returnValues.relay.realizedLpFeePct @@ -475,7 +535,7 @@ export class InsuredBridgeL1Client { delete this.relays[l1Token][relayDisputedEvent.returnValues.depositHash]; } - for (const relaySettledEvent of relaySettledEvents) { + for (const relaySettledEvent of relaySettledEvents.eventData) { this.relays[l1Token][relaySettledEvent.returnValues.depositHash].relayState = ClientRelayState.Finalized; this.relays[l1Token][relaySettledEvent.returnValues.depositHash].settleable = SettleableRelay.CannotSettle; } diff --git a/packages/insured-bridge-relayer/src/RelayerConfig.ts b/packages/insured-bridge-relayer/src/RelayerConfig.ts index f72f945fc4..2113f4cca4 100644 --- a/packages/insured-bridge-relayer/src/RelayerConfig.ts +++ b/packages/insured-bridge-relayer/src/RelayerConfig.ts @@ -13,6 +13,16 @@ export const bridgeDepositBoxDeployData = { 288: { blockNumber: 223808 }, }; +// Following settings can be overridden to optimize L1 client event search for select events. For example, +// the "DepositRelayed" event search request could return > 10,000 return values so we need to shorten the block +// search using these parameters because some node providers like Infura limit event search return values to 10,000. + +// This is set to the oldest SpokePool's deploy block height because we can assume that there will not be any +// BridgePool events on any BridgePool at blocks lower than this height. This is specifically the WETH +// BridgePool's deploy block. +export const bridgePoolEarliestBlockToSearch = 13545377; +export const bridgePoolMaxBlocksToSeach = 1_000_000; + export interface ProcessEnv { [key: string]: string | undefined; } @@ -42,6 +52,8 @@ export class RelayerConfig { readonly botModes: BotModes; readonly l2DeployData: { [key: string]: { blockNumber: number } }; + readonly bridgePoolEarliestBlockToSearch: number; + readonly bridgePoolMaxBlocksToSeach: number; constructor(env: ProcessEnv) { const { @@ -61,6 +73,8 @@ export class RelayerConfig { L2_FINALIZER_ENABLED, WHITELISTED_CHAIN_IDS, L2_DEPLOY_DATA, + BRIDGE_POOL_EVENT_SEARCH_FROM_BLOCK, + BRIDGE_POOL_MAX_BLOCKS_TO_SEARCH, } = env; if (!BRIDGE_ADMIN_ADDRESS) throw new Error("BRIDGE_ADMIN_ADDRESS required"); @@ -106,6 +120,13 @@ export class RelayerConfig { this.l2DeployData = L2_DEPLOY_DATA ? JSON.parse(L2_DEPLOY_DATA) : bridgeDepositBoxDeployData; + this.bridgePoolEarliestBlockToSearch = BRIDGE_POOL_EVENT_SEARCH_FROM_BLOCK + ? Number(BRIDGE_POOL_EVENT_SEARCH_FROM_BLOCK) + : bridgePoolEarliestBlockToSearch; + this.bridgePoolMaxBlocksToSeach = BRIDGE_POOL_MAX_BLOCKS_TO_SEARCH + ? Number(BRIDGE_POOL_MAX_BLOCKS_TO_SEARCH) + : bridgePoolMaxBlocksToSeach; + // CHAIN_IDS sets the active chain ID's for this bot. Note how this is distinct from WHITELISTED_CHAIN_IDS which // sets all valid chain ID's. Any relays for chain ID's outside of this whitelist will be disputed. this.activatedChainIds = JSON.parse(CHAIN_IDS || "[]"); diff --git a/packages/insured-bridge-relayer/src/index.ts b/packages/insured-bridge-relayer/src/index.ts index f54d3a1058..aba9c5a236 100644 --- a/packages/insured-bridge-relayer/src/index.ts +++ b/packages/insured-bridge-relayer/src/index.ts @@ -47,7 +47,15 @@ export async function run(logger: winston.Logger, l1Web3: Web3): Promise { // Create L1/L2 clients to pull data to inform the relayer. // todo: add in start and ending block numbers (if need be). // todo: grab bridge admin from `getAddress`. - const l1Client = new InsuredBridgeL1Client(logger, l1Web3, config.bridgeAdmin, config.rateModelStore); + const l1Client = new InsuredBridgeL1Client( + logger, + l1Web3, + config.bridgeAdmin, + config.rateModelStore, + config.bridgePoolEarliestBlockToSearch, + null, // Use latest block as end block + config.bridgePoolMaxBlocksToSeach + ); await l1Client.update(); // TODO: Add a method to fetch all registered chainIDs from bridge admin to let the bot default to all chains when diff --git a/packages/insured-bridge-relayer/test/index.ts b/packages/insured-bridge-relayer/test/index.ts index dd8c94f79b..563f44c7ca 100644 --- a/packages/insured-bridge-relayer/test/index.ts +++ b/packages/insured-bridge-relayer/test/index.ts @@ -243,6 +243,7 @@ describe("index.js", function () { process.env.RATE_MODEL_ADDRESS = rateModelStore.options.address; process.env.CHAIN_IDS = JSON.stringify([networks[0].chainId]); process.env[`NODE_URL_${networks[0].chainId}`] = "http://localhost:7777"; + process.env.BRIDGE_POOL_EVENT_SEARCH_FROM_BLOCK = "0"; // Must not throw. await run(spyLogger, web3); @@ -260,6 +261,7 @@ describe("index.js", function () { process.env.RATE_MODEL_ADDRESS = rateModelStore.options.address; process.env.CHAIN_IDS = JSON.stringify(networks.map(({ chainId }) => chainId)); networks.forEach(({ chainId, port }) => (process.env[`NODE_URL_${chainId}`] = `http://localhost:${port}`)); + process.env.BRIDGE_POOL_EVENT_SEARCH_FROM_BLOCK = "0"; // Must not throw. await run(spyLogger, web3); @@ -277,6 +279,7 @@ describe("index.js", function () { process.env.POLLING_DELAY = "0"; process.env.CHAIN_IDS = JSON.stringify([networks[0].chainId]); process.env[`NODE_URL_${networks[0].chainId}`] = "http://localhost:7777"; + process.env.BRIDGE_POOL_EVENT_SEARCH_FROM_BLOCK = "0"; // Add another L1 token to rate model that is not whitelisted. const unWhitelistedL1Token = toChecksumAddress(randomHex(20)); @@ -311,6 +314,7 @@ describe("index.js", function () { process.env.POLLING_DELAY = "0"; process.env.CHAIN_IDS = JSON.stringify([networks[0].chainId]); process.env[`NODE_URL_${networks[0].chainId}`] = "http://localhost:7777"; + process.env.BRIDGE_POOL_EVENT_SEARCH_FROM_BLOCK = "0"; // whitelist new token const newWhitelistedL1Token = await ERC20.new("TESTERC20", "TESTERC20", 18).send({ from: owner }); diff --git a/yarn.lock b/yarn.lock index 4d4e709f50..fc71daf82a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8693,9 +8693,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30001219: - version "1.0.30001248" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001248.tgz#26ab45e340f155ea5da2920dadb76a533cb8ebce" - integrity sha512-NwlQbJkxUFJ8nMErnGtT0QTM2TJ33xgz4KXJSMIrjXIbDVdaYueGyjOrLKRtJC+rTiWfi6j5cnZN1NBiSBJGNw== + version "1.0.30001338" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001338.tgz" + integrity sha512-1gLHWyfVoRDsHieO+CaeYe7jSo/MT7D7lhaXUiwwbuR5BwQxORs0f1tAwUSQr3YbxRXJvxHM/PA5FfPQRnsPeQ== capture-exit@^2.0.0: version "2.0.0"