diff --git a/src/clients/SpokePoolClient.ts b/src/clients/SpokePoolClient.ts index dc2518cb6..cb6b51e52 100644 --- a/src/clients/SpokePoolClient.ts +++ b/src/clients/SpokePoolClient.ts @@ -78,14 +78,15 @@ export class IndexedSpokePoolClient extends clients.SpokePoolClient { */ protected startWorker(): void { const { - eventSearchConfig: { fromBlock, maxBlockLookBack: blockRange }, + eventSearchConfig: { fromBlock, maxBlockLookBack: blockrange }, + spokePool: { address: spokepool }, } = this; - const opts = { blockRange, lookback: `@${fromBlock}` }; + const opts = { spokepool, blockrange, lookback: `@${fromBlock}` }; const args = Object.entries(opts) .map(([k, v]) => [`--${k}`, `${v}`]) .flat(); - this.worker = spawn("node", [this.indexerPath, "--chainId", this.chainId.toString(), ...args], { + this.worker = spawn("node", [this.indexerPath, "--chainid", this.chainId.toString(), ...args], { stdio: ["ignore", "inherit", "inherit", "ipc"], }); diff --git a/src/common/Constants.ts b/src/common/Constants.ts index 73e67b531..59fe6b34e 100644 --- a/src/common/Constants.ts +++ b/src/common/Constants.ts @@ -127,7 +127,7 @@ export const CHAIN_MAX_BLOCK_LOOKBACK = { [CHAIN_IDs.BOBA]: 4990, [CHAIN_IDs.LINEA]: 5000, [CHAIN_IDs.LISK]: 10000, - [CHAIN_IDs.MAINNET]: 10000, + [CHAIN_IDs.MAINNET]: 5000, [CHAIN_IDs.MODE]: 10000, [CHAIN_IDs.OPTIMISM]: 10000, // Quick [CHAIN_IDs.POLYGON]: 10000, diff --git a/src/libexec/RelayerSpokePoolIndexer.ts b/src/libexec/RelayerSpokePoolIndexer.ts index e6b211734..cca604523 100644 --- a/src/libexec/RelayerSpokePoolIndexer.ts +++ b/src/libexec/RelayerSpokePoolIndexer.ts @@ -15,6 +15,7 @@ import { getOriginFromURL, getProvider, getRedisCache, + getSpokePool, getWSProviders, Logger, winston, @@ -117,11 +118,11 @@ async function listen( */ async function run(argv: string[]): Promise { const minimistOpts = { - string: ["lookback", "relayer"], + string: ["lookback", "relayer", "spokepool"], }; const args = minimist(argv, minimistOpts); - const { chainId, lookback, relayer = null, maxBlockRange = 10_000 } = args; + const { chainId: chainId, lookback, relayer = null, blockrange: maxBlockRange = 10_000 } = args; assert(Number.isInteger(chainId), "chainId must be numeric "); assert(Number.isInteger(maxBlockRange), "maxBlockRange must be numeric"); assert(!isDefined(relayer) || ethersUtils.isAddress(relayer), `relayer address is invalid (${relayer})`); @@ -129,6 +130,12 @@ async function run(argv: string[]): Promise { const { quorum = getChainQuorum(chainId) } = args; assert(Number.isInteger(quorum), "quorum must be numeric "); + let { spokepool: spokePoolAddr } = args; + assert( + !isDefined(spokePoolAddr) || ethersUtils.isAddress(spokePoolAddr), + `Invalid SpokePool address (${spokePoolAddr})` + ); + chain = getNetworkName(chainId); const quorumProvider = await getProvider(chainId); @@ -152,16 +159,21 @@ async function run(argv: string[]): Promise { logger.debug({ at: "RelayerSpokePoolIndexer::run", message: `Skipping lookback on ${chain}.` }); } + const spokePool = getSpokePool(chainId, spokePoolAddr); + if (!isDefined(spokePoolAddr)) { + ({ address: spokePoolAddr } = spokePool); + } + const opts = { - quorum, + spokePool: spokePoolAddr, deploymentBlock, lookback: latestBlock.number - startBlock, maxBlockRange, filterArgs: getEventFilterArgs(relayer), + quorum, }; logger.debug({ at: "RelayerSpokePoolIndexer::run", message: `Starting ${chain} SpokePool Indexer.`, opts }); - const spokePool = await utils.getSpokePoolContract(chainId); process.on("SIGHUP", () => { logger.debug({ at: "Relayer#run", message: `Received SIGHUP in ${chain} listener, stopping...` }); diff --git a/src/libexec/SpokePoolListenerExperimental.ts b/src/libexec/SpokePoolListenerExperimental.ts index 5236575c7..0a14c9d4f 100644 --- a/src/libexec/SpokePoolListenerExperimental.ts +++ b/src/libexec/SpokePoolListenerExperimental.ts @@ -18,6 +18,7 @@ import { getNodeUrlList, getOriginFromURL, getProvider, + getSpokePool, getRedisCache, Logger, winston, @@ -161,12 +162,12 @@ async function listen(eventMgr: EventManager, spokePool: Contract, eventNames: s */ async function run(argv: string[]): Promise { const minimistOpts = { - string: ["lookback", "relayer"], + string: ["lookback", "relayer", "spokepool"], }; const args = minimist(argv, minimistOpts); - ({ chainId } = args); - const { lookback, relayer = null, maxBlockRange = 10_000 } = args; + ({ chainid: chainId } = args); + const { lookback, relayer = null, blockrange: maxBlockRange = 10_000 } = args; assert(Number.isInteger(chainId), "chainId must be numeric "); assert(Number.isInteger(maxBlockRange), "maxBlockRange must be numeric"); assert(!isDefined(relayer) || ethersUtils.isAddress(relayer), `relayer address is invalid (${relayer})`); @@ -174,6 +175,12 @@ async function run(argv: string[]): Promise { const { quorum = getChainQuorum(chainId) } = args; assert(Number.isInteger(quorum), "quorum must be numeric "); + let { spokepool: spokePoolAddr } = args; + assert( + !isDefined(spokePoolAddr) || ethersUtils.isAddress(spokePoolAddr), + `Invalid SpokePool address (${spokePoolAddr})` + ); + chain = getNetworkName(chainId); const quorumProvider = await getProvider(chainId); @@ -197,16 +204,21 @@ async function run(argv: string[]): Promise { logger.debug({ at: "RelayerSpokePoolListener::run", message: `Skipping lookback on ${chain}.` }); } + const spokePool = getSpokePool(chainId, spokePoolAddr); + if (!isDefined(spokePoolAddr)) { + ({ address: spokePoolAddr } = spokePool); + } + const opts = { - quorum, + spokePool: spokePoolAddr, deploymentBlock, lookback: latestBlock.number - startBlock, maxBlockRange, filterArgs: getEventFilterArgs(relayer), + quorum, }; logger.debug({ at: "RelayerSpokePoolListener::run", message: `Starting ${chain} SpokePool Indexer.`, opts }); - const spokePool = await utils.getSpokePoolContract(chainId); process.on("SIGHUP", () => { logger.debug({ at: "Relayer#run", message: `Received SIGHUP in ${chain} listener, stopping...` }); diff --git a/src/utils/ContractUtils.ts b/src/utils/ContractUtils.ts index 31bf09e60..d4e4206b0 100644 --- a/src/utils/ContractUtils.ts +++ b/src/utils/ContractUtils.ts @@ -1,32 +1,43 @@ -import { getNetworkName, Contract, Signer, getDeployedAddress, getDeployedBlockNumber } from "."; - import * as typechain from "@across-protocol/contracts"; // TODO: refactor once we've fixed export from contract repo +import { CHAIN_IDs, getNetworkName, Contract, Signer, getDeployedAddress, getDeployedBlockNumber } from "."; // Return an ethers contract instance for a deployed contract, imported from the Across-protocol contracts repo. export function getDeployedContract(contractName: string, networkId: number, signer?: Signer): Contract { try { const address = getDeployedAddress(contractName, networkId); // If the contractName is SpokePool then we need to modify it to find the correct contract factory artifact. - const factoryName = contractName === "SpokePool" ? castSpokePoolName(networkId) : contractName; - const artifact = typechain[`${[factoryName.replace("_", "")]}__factory`]; + const factoryName = `${contractName === "SpokePool" ? castSpokePoolName(networkId) : contractName}__factory`; + const artifact = typechain[factoryName]; return new Contract(address, artifact.abi, signer); } catch (error) { - throw new Error(`Could not find address for contract ${contractName} on ${networkId}`); + throw new Error(`Could not find address for contract ${contractName} on ${networkId} (${error})`); } } // If the name of the contract is SpokePool then we need to apply a transformation on the name to get the correct // contract factory name. For example, if the network is "mainnet" then the contract is called Ethereum_SpokePool. export function castSpokePoolName(networkId: number): string { - let networkName = getNetworkName(networkId); - if (networkName == "Mainnet" || networkName == "Rinkeby" || networkName == "Kovan" || networkName == "Goerli") { - return "Ethereum_SpokePool"; + let networkName: string; + switch (networkId) { + case CHAIN_IDs.MAINNET: + case CHAIN_IDs.SEPOLIA: + return "Ethereum_SpokePool"; + case CHAIN_IDs.ARBITRUM: + return "Arbitrum_SpokePool"; + case CHAIN_IDs.ZK_SYNC: + return "ZkSync_SpokePool"; + default: + networkName = getNetworkName(networkId); } - if (networkName.includes("-")) { - networkName = networkName.substring(0, networkName.indexOf("-")); - } - return `${networkName}_SpokePool`; + return `${networkName.replace(" ", "")}_SpokePool`; +} + +// For a chain ID and optional SpokePool address, return a Contract instance with the corresponding ABI. +export function getSpokePool(chainId: number, address?: string): Contract { + const factoryName = castSpokePoolName(chainId); + const artifact = typechain[`${factoryName}__factory`]; + return new Contract(address ?? getDeployedAddress("SpokePool", chainId), artifact.abi); } export function getParamType(contractName: string, functionName: string, paramName: string): string {