From 87a0efd99eab81569cbb9cbcc0a9b31f74e40483 Mon Sep 17 00:00:00 2001 From: Gerhard Steenkamp Date: Thu, 20 Nov 2025 20:50:06 +0200 Subject: [PATCH] use paginated filter Signed-off-by: Gerhard Steenkamp --- src/utils/providers.ts | 21 +++++ src/utils/sdk.ts | 1 + .../useDepositTracking/strategies/evm.ts | 91 ++++++++++++------- 3 files changed, 79 insertions(+), 34 deletions(-) diff --git a/src/utils/providers.ts b/src/utils/providers.ts index 0d87002c7..916aacb7f 100644 --- a/src/utils/providers.ts +++ b/src/utils/providers.ts @@ -7,6 +7,7 @@ import { } from "./constants"; import { createSolanaRpc, MainnetUrl } from "@solana/kit"; import { SVMProvider } from "@across-protocol/sdk/dist/esm/arch/svm"; +import { CHAIN_IDs } from "@across-protocol/constants"; export function getProviderUrl(chainId: number): string { const resolvedRpcUrl = @@ -55,3 +56,23 @@ export function getSVMRpc( const transport = getProviderUrl(chainId) as MainnetUrl; return createSolanaRpc(transport, config) as SVMProvider; } + +const resolveRpcConfig = () => { + const defaultRange = 10_000; + const ranges = { + [CHAIN_IDs.ALEPH_ZERO]: 0, + [CHAIN_IDs.BOBA]: 0, + [CHAIN_IDs.HYPEREVM]: 1_000, // QuickNode constraint. + [CHAIN_IDs.MONAD]: 50, // public RPC constraint + [CHAIN_IDs.SOLANA]: 1_000, + [CHAIN_IDs.SOLANA_DEVNET]: 1000, + }; + return Object.fromEntries( + Object.values(CHAIN_IDs).map((chainId) => [ + chainId, + ranges[chainId] ?? defaultRange, + ]) + ); +}; + +export const CHAIN_MAX_BLOCK_LOOKBACK = resolveRpcConfig(); diff --git a/src/utils/sdk.ts b/src/utils/sdk.ts index 9a8f61a6e..4e4f4d010 100644 --- a/src/utils/sdk.ts +++ b/src/utils/sdk.ts @@ -31,6 +31,7 @@ export { getMessageHash } from "@across-protocol/sdk/dist/esm/utils/SpokeUtils"; export { SvmCpiEventsClient } from "@across-protocol/sdk/dist/esm/arch/svm/eventsClient"; export { findFillEvent } from "@across-protocol/sdk/dist/esm/arch/svm/SpokeUtils"; export { bigToU8a32 } from "@across-protocol/sdk/dist/esm/arch/svm/utils"; +export { paginatedEventQuery } from "@across-protocol/sdk/dist/esm/utils/EventUtils"; export function getUpdateV3DepositTypedData( depositId: string, diff --git a/src/views/DepositStatus/hooks/useDepositTracking/strategies/evm.ts b/src/views/DepositStatus/hooks/useDepositTracking/strategies/evm.ts index 673a5b2bc..9395028f1 100644 --- a/src/views/DepositStatus/hooks/useDepositTracking/strategies/evm.ts +++ b/src/views/DepositStatus/hooks/useDepositTracking/strategies/evm.ts @@ -1,7 +1,12 @@ -import { getProvider } from "utils/providers"; +import { CHAIN_MAX_BLOCK_LOOKBACK, getProvider } from "utils/providers"; import { getDepositByTxHash, parseFilledRelayLog } from "utils/deposits"; import { getConfig } from "utils/config"; -import { getBlockForTimestamp, getMessageHash, toAddressType } from "utils/sdk"; +import { + getBlockForTimestamp, + getMessageHash, + paginatedEventQuery, + toAddressType, +} from "utils/sdk"; import { NoFilledRelayLogError } from "utils/deposits"; import { indexerApiBaseUrl } from "utils/constants"; import axios from "axios"; @@ -16,6 +21,8 @@ import { import { Deposit } from "hooks/useDeposits"; import { FromBridgePagePayload } from "views/Bridge/hooks/useBridgeAction"; import { ethers } from "ethers"; +import { FilledV3RelayEvent } from "utils/typechain"; +import { FilledRelayEvent } from "@across-protocol/contracts/dist/typechain/contracts/SpokePool"; /** * Strategy for handling EVM chain operations @@ -160,44 +167,58 @@ export class EVMStrategy implements IChainStrategy { // If API approach didn't work, find the fill on-chain try { const provider = getProvider(this.chainId); - const blockForTimestamp = await getBlockForTimestamp( + const blockNumberAtDepositTime = await getBlockForTimestamp( provider, depositInfo.depositTimestamp ); const config = getConfig(); const destinationSpokePool = config.getSpokePool(this.chainId); + const latestBlockNumber = await provider.getBlockNumber(); + const v3FilledRelayFilter = destinationSpokePool.filters.FilledV3Relay( + undefined, + undefined, + undefined, + undefined, + undefined, + originChainId, + depositId.toNumber() + ); + + const filledRelayFilter = destinationSpokePool.filters.FilledRelay( + undefined, + undefined, + undefined, + undefined, + undefined, + originChainId, + depositId.toNumber() + ); + + const eventSearchConfig: Parameters[2] = { + from: blockNumberAtDepositTime, + to: latestBlockNumber, + maxLookBack: CHAIN_MAX_BLOCK_LOOKBACK?.[this.chainId], + }; + + const v3FilledRelayQuery = paginatedEventQuery( + destinationSpokePool, + v3FilledRelayFilter, + eventSearchConfig + ); + const filledRelayQuery = paginatedEventQuery( + destinationSpokePool, + filledRelayFilter, + eventSearchConfig + ); + const [legacyFilledRelayEvents, newFilledRelayEvents] = await Promise.all( - [ - destinationSpokePool.queryFilter( - destinationSpokePool.filters.FilledV3Relay( - undefined, - undefined, - undefined, - undefined, - undefined, - originChainId, - depositId.toNumber() - ), - blockForTimestamp - ), - destinationSpokePool.queryFilter( - destinationSpokePool.filters.FilledRelay( - undefined, - undefined, - undefined, - undefined, - undefined, - originChainId, - depositId.toNumber() - ), - blockForTimestamp - ), - ] + [v3FilledRelayQuery, filledRelayQuery] ); + const filledRelayEvents = [ - ...legacyFilledRelayEvents, - ...newFilledRelayEvents, + ...(legacyFilledRelayEvents as FilledV3RelayEvent[]), + ...(newFilledRelayEvents as FilledRelayEvent[]), ]; // If we make it to this point, we can be sure that there is exactly one filled relay event // that corresponds to the deposit we are looking for. @@ -217,11 +238,13 @@ export class EVMStrategy implements IChainStrategy { ? filledRelayEvent.args.relayExecutionInfo.updatedMessageHash : messageHash; - const fillTxBlock = await filledRelayEvent.getBlock(); + const { timestamp: fillTxTimestamp } = await provider.getBlock( + filledRelayEvent.blockNumber + ); return { fillTxHash: filledRelayEvent.transactionHash, - fillTxTimestamp: fillTxBlock.timestamp, + fillTxTimestamp, depositInfo, fillLog: { ...filledRelayEvent, @@ -252,7 +275,7 @@ export class EVMStrategy implements IChainStrategy { ), messageHash, destinationChainId: this.chainId, - fillTimestamp: fillTxBlock.timestamp, + fillTimestamp: fillTxTimestamp, blockNumber: filledRelayEvent.blockNumber, txnRef: filledRelayEvent.transactionHash, txnIndex: filledRelayEvent.transactionIndex,