From 0d0f3d8701e2a300c0533bb1c07e932745bec90a Mon Sep 17 00:00:00 2001 From: Nikolas Haimerl Date: Fri, 19 Dec 2025 15:25:29 +0100 Subject: [PATCH] add cctp finalizer mode --- .../service/CctpFinalizerService.ts | 101 ++++++++++-------- packages/indexer/src/parseEnv.ts | 28 +++++ 2 files changed, 85 insertions(+), 44 deletions(-) diff --git a/packages/indexer/src/data-indexing/service/CctpFinalizerService.ts b/packages/indexer/src/data-indexing/service/CctpFinalizerService.ts index b215e59d..5b4c37cc 100644 --- a/packages/indexer/src/data-indexing/service/CctpFinalizerService.ts +++ b/packages/indexer/src/data-indexing/service/CctpFinalizerService.ts @@ -5,7 +5,7 @@ import { RepeatableTask } from "../../generics"; import { DataSource, entities } from "@repo/indexer-database"; import { CHAIN_IDs } from "@across-protocol/constants"; import { PubSubService } from "../../pubsub/service"; -import { Config } from "../../parseEnv"; +import { Config, CctpFinalizerMode } from "../../parseEnv"; import { fetchAttestationsForTxn, getCctpDestinationChainFromDomain, @@ -33,9 +33,10 @@ export class CctpFinalizerServiceManager { this.logger, this.postgres, this.pubSubService, + this.config, ); await this.lighterFinalizerService.start(CCTP_FINALIZER_DELAY_SECONDS); - if (!this.config.enableCctpFinalizer) { + if (this.config.cctpFinalizerMode === CctpFinalizerMode.Off) { this.logger.warn({ at: "Indexer#CctpFinalizerServiceManager#start", message: "CCTP finalizer is disabled", @@ -48,7 +49,9 @@ export class CctpFinalizerServiceManager { this.logger, this.postgres, this.pubSubService, + this.config, ); + // Start the service if we are not in 'off' mode (implied by the early return above) await this.service.start(CCTP_FINALIZER_DELAY_SECONDS); } catch (error) { this.logger.error({ @@ -74,6 +77,7 @@ class LighterCctpFinalizerService extends RepeatableTask { logger: winston.Logger, private readonly postgres: DataSource, private readonly pubSubService: PubSubService, + private readonly config: Config, ) { super(logger, "lighter-cctp-finalizer-service"); } @@ -214,27 +218,32 @@ class LighterCctpFinalizerService extends RepeatableTask { { chainId, blockNumber: burnEvent.blockNumber, transactionHash }, ) .execute(); - this.logger.debug({ - at: "LighterCctpFinalizerService#publishBurnEvent", - message: "Publishing burn event to pubsub", - chainId, - transactionHash, - minFinalityThreshold, - blockTimestamp, - attestationTimeSeconds, - elapsedSeconds, - }); - const destinationChainId = getCctpDestinationChainFromDomain( - burnEvent.destinationDomain, - ); - await this.pubSubService.publishCctpFinalizerMessage( - transactionHash, - Number(chainId), - message, - attestation, - destinationChainId, - signature, - ); + + if (this.config.cctpFinalizerMode === CctpFinalizerMode.Full) { + this.logger.debug({ + at: "LighterCctpFinalizerService#publishBurnEvent", + message: "Publishing burn event to pubsub", + chainId, + transactionHash, + minFinalityThreshold, + blockTimestamp, + attestationTimeSeconds, + elapsedSeconds, + }); + + const destinationChainId = getCctpDestinationChainFromDomain( + burnEvent.destinationDomain, + ); + + await this.pubSubService.publishCctpFinalizerMessage( + transactionHash, + Number(chainId), + message, + attestation, + destinationChainId, + signature, + ); + } const jobValues: { attestation: string; @@ -278,6 +287,7 @@ class CctpFinalizerService extends RepeatableTask { logger: winston.Logger, private readonly postgres: DataSource, private readonly pubSubService: PubSubService, + private readonly config: Config, ) { super(logger, "cctp-finalizer-service"); } @@ -426,27 +436,30 @@ class CctpFinalizerService extends RepeatableTask { { chainId, blockNumber: burnEvent.blockNumber, transactionHash }, ) .execute(); - this.logger.debug({ - at: "CctpFinalizerService#publishBurnEvent", - message: "Publishing burn event to pubsub", - chainId, - transactionHash, - minFinalityThreshold, - blockTimestamp, - attestationTimeSeconds, - elapsedSeconds, - }); - const destinationChainId = getCctpDestinationChainFromDomain( - burnEvent.destinationDomain, - ); - await this.pubSubService.publishCctpFinalizerMessage( - transactionHash, - Number(chainId), - message, - attestation, - destinationChainId, - signature, - ); + + if (this.config.cctpFinalizerMode === CctpFinalizerMode.Full) { + this.logger.debug({ + at: "CctpFinalizerService#publishBurnEvent", + message: "Publishing burn event to pubsub", + chainId, + transactionHash, + minFinalityThreshold, + blockTimestamp, + attestationTimeSeconds, + elapsedSeconds, + }); + const destinationChainId = getCctpDestinationChainFromDomain( + burnEvent.destinationDomain, + ); + await this.pubSubService.publishCctpFinalizerMessage( + transactionHash, + Number(chainId), + message, + attestation, + destinationChainId, + signature, + ); + } const jobValues: { attestation: string; diff --git a/packages/indexer/src/parseEnv.ts b/packages/indexer/src/parseEnv.ts index 3ce8bfd6..e009f0c5 100644 --- a/packages/indexer/src/parseEnv.ts +++ b/packages/indexer/src/parseEnv.ts @@ -21,6 +21,7 @@ export type Config = { enableBundleBuilder: boolean; cctpIndexerChainIds: number[]; enableCctpFinalizer: boolean; + cctpFinalizerMode: CctpFinalizerMode; pubSubCctpFinalizerTopic: string; pubSubGcpProjectId: string; enableOftIndexer: boolean; @@ -69,6 +70,12 @@ export type RetryProviderConfig = { export type Env = Record; +export enum CctpFinalizerMode { + Off = "off", + Full = "full", + FetchAttestationOnly = "fetch-attestation-only", +} + export function parseRedisConfig(env: Env): RedisConfig { const { REDIS_HOST, REDIS_PORT } = env; assert(REDIS_HOST, "requires REDIS_HOST"); @@ -232,6 +239,26 @@ export function envToConfig(env: Env): Config { const enableCctpFinalizer = env.ENABLE_CCTP_FINALIZER ? env.ENABLE_CCTP_FINALIZER === "true" : false; + let cctpFinalizerMode: CctpFinalizerMode = CctpFinalizerMode.Off; + + if (env.CCTP_FINALIZER_MODE) { + if ( + env.CCTP_FINALIZER_MODE === "full" || + env.CCTP_FINALIZER_MODE === "fetch-attestation-only" || + env.CCTP_FINALIZER_MODE === "off" + ) { + cctpFinalizerMode = env.CCTP_FINALIZER_MODE as CctpFinalizerMode; + } else { + throw new Error( + `Invalid CCTP_FINALIZER_MODE: ${env.CCTP_FINALIZER_MODE}. Must be one of 'off', 'full', 'fetch-attestation-only'`, + ); + } + } else if (env.ENABLE_CCTP_FINALIZER) { + cctpFinalizerMode = + env.ENABLE_CCTP_FINALIZER === "true" + ? CctpFinalizerMode.Full + : CctpFinalizerMode.Off; + } const pubSubCctpFinalizerTopic = env.PUBSUB_CCTP_FINALIZER_TOPIC ?? ""; const pubSubGcpProjectId = env.PUBSUB_GCP_PROJECT_ID ?? ""; const enableBundleIncludedEventsService = @@ -293,6 +320,7 @@ export function envToConfig(env: Env): Config { cctpIndexerChainIds, enableOftIndexer, enableCctpFinalizer, + cctpFinalizerMode, pubSubCctpFinalizerTopic, pubSubGcpProjectId, webhookConfig,