From 928402b78c423737cec407b4fd8558dc0d6c2bd3 Mon Sep 17 00:00:00 2001 From: xiaoch05 Date: Wed, 24 Jul 2024 22:30:08 +0800 Subject: [PATCH] use multi lvl0 indexers --- apollo/src/base/TransferServiceT2.ts | 10 +- apollo/src/lnv3/lnv3.service.ts | 199 +++++++++++---------- apollo/src/lnv3/source/ponder.service.ts | 76 ++++++++ apollo/src/lnv3/source/source.service.ts | 78 ++++++++ apollo/src/lnv3/source/thegraph.service.ts | 73 ++++++++ apollo/src/lnv3/transfer.service.ts | 154 ++++++++++++---- 6 files changed, 454 insertions(+), 136 deletions(-) create mode 100644 apollo/src/lnv3/source/ponder.service.ts create mode 100644 apollo/src/lnv3/source/source.service.ts create mode 100644 apollo/src/lnv3/source/thegraph.service.ts diff --git a/apollo/src/base/TransferServiceT2.ts b/apollo/src/base/TransferServiceT2.ts index d158fea..81c880b 100644 --- a/apollo/src/base/TransferServiceT2.ts +++ b/apollo/src/base/TransferServiceT2.ts @@ -19,7 +19,7 @@ export enum RecordStatus { failed, } -export enum Level0Indexer { +export enum Level0IndexerType { thegraph, ponder, } @@ -37,9 +37,13 @@ export interface BridgeBaseConfigure { takeEachTime: number; } +export interface Level0Indexer { + indexerType: Level0IndexerType; + url: string; +} + export interface PartnerT2 { - level0Indexer: number; - indexerUrl: string; + level0Indexers: Level0Indexer[]; chainConfig: HelixChainConf; } diff --git a/apollo/src/lnv3/lnv3.service.ts b/apollo/src/lnv3/lnv3.service.ts index bb2b225..a1f008e 100644 --- a/apollo/src/lnv3/lnv3.service.ts +++ b/apollo/src/lnv3/lnv3.service.ts @@ -1,12 +1,13 @@ import { Injectable, Logger, OnModuleInit } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; -import axios from 'axios'; import { last } from 'lodash'; import { AggregationService } from '../aggregation/aggregation.service'; -import { PartnerT2, RecordStatus, Level0Indexer } from '../base/TransferServiceT2'; +import { PartnerT2, RecordStatus, Level0IndexerType } from '../base/TransferServiceT2'; import { TasksService } from '../tasks/tasks.service'; import { TransferService } from './transfer.service'; import { ChainToken, ChainMessager, ChainCouple } from '@helixbridge/helixconf'; +import { Lnv3ThegraphService } from './source/thegraph.service'; +import { Lnv3PonderService } from './source/ponder.service'; export enum RelayUpdateType { PROVIDER_UPDATE, @@ -28,13 +29,17 @@ export class Lnv3Service implements OnModuleInit { private readonly takeEachTime = 2; private skip = new Array(this.transferService.transfers.length).fill(0); + private sourceServices = new Map(); constructor( public configService: ConfigService, private aggregationService: AggregationService, private taskService: TasksService, private transferService: TransferService - ) {} + ) { + this.sourceServices.set(Level0IndexerType.thegraph, new Lnv3ThegraphService()); + this.sourceServices.set(Level0IndexerType.ponder, new Lnv3PonderService()); + } async onModuleInit() { this.transferService.transfers.forEach((item, index) => { @@ -88,83 +93,91 @@ export class Lnv3Service implements OnModuleInit { } async queryRecordInfo(transfer: PartnerT2, latestNonce: number) { - if (transfer.level0Indexer === Level0Indexer.ponder) { - const url = this.transferService.ponderEndpoint; - const query = `query { lnv3TransferRecords(limit: 50, orderBy: "nonce", orderDirection: "asc", where: {localChainId: "${transfer.chainConfig.id}", nonce_gt: "${latestNonce}"}) { items { id, nonce, messageNonce, remoteChainId, provider, sourceToken, targetToken, sourceAmount, targetAmount, sender, receiver, timestamp, transactionHash, fee, transferId, hasWithdrawn } }}`; - return await axios - .post(url, { - query: query, - variables: null, - }) - .then((res) => res.data?.data?.lnv3TransferRecords.items); - } else { - const url = transfer.indexerUrl; - const query = `query { lnv3TransferRecords(first: 20, orderBy: nonce, orderDirection: asc, skip: ${latestNonce}) { id, nonce, messageNonce, remoteChainId, provider, sourceToken, targetToken, sourceAmount, targetAmount, sender, receiver, timestamp, transactionHash, fee, transferId, hasWithdrawn } }`; - return await axios - .post(url, { - query: query, - variables: null, - }) - .then((res) => res.data?.data?.lnv3TransferRecords); + let result = []; + for (const level0Indexer of transfer.level0Indexers) { + const url = level0Indexer.url; + const service = this.sourceServices.get(level0Indexer.indexerType); + try { + const response = await service.queryRecordInfo( + level0Indexer.url, + transfer.chainConfig.id, + latestNonce + ); + if (response && response.length >= result.length) { + result = response; + } + } catch (err) { + this.logger.warn( + `try to get records failed, id ${transfer.chainConfig.id}, type ${level0Indexer.indexerType}` + ); + } } + return result; } async queryProviderInfo(transfer: PartnerT2, latestNonce: number) { - if (transfer.level0Indexer === Level0Indexer.ponder) { - const url = this.transferService.ponderEndpoint; - const query = `query { lnv3RelayUpdateRecords(limit: 50, orderBy: "nonce", orderDirection: "asc", where: {localChainId: "${transfer.chainConfig.id}", nonce_gt: "${latestNonce}"}) { items { id, updateType, remoteChainId, provider, transactionHash, timestamp, sourceToken, targetToken, penalty, baseFee, liquidityFeeRate, transferLimit, paused } }}`; - - return await axios - .post(url, { - query: query, - variables: null, - }) - .then((res) => res.data?.data?.lnv3RelayUpdateRecords.items); - } else { - const query = `query { lnv3RelayUpdateRecords(first: 50, orderBy: nonce, orderDirection: asc, skip: ${latestNonce}) { id, updateType, remoteChainId, provider, transactionHash, timestamp, sourceToken, targetToken, penalty, baseFee, liquidityFeeRate, transferLimit, paused } }`; - return await axios - .post(transfer.indexerUrl, { - query: query, - variables: null, - }) - .then((res) => res.data?.data?.lnv3RelayUpdateRecords); + let result = []; + for (const level0Indexer of transfer.level0Indexers) { + const url = level0Indexer.url; + const service = this.sourceServices.get(level0Indexer.indexerType); + try { + const response = await service.queryProviderInfo( + level0Indexer.url, + transfer.chainConfig.id, + latestNonce + ); + if (response && response.length >= result.length) { + result = response; + } + } catch (err) { + this.logger.warn( + `try to get provider infos failed, id ${transfer.chainConfig.id}, type ${level0Indexer.indexerType}` + ); + } } + return result; } async queryRecordRelayStatus(toChain: PartnerT2, transferId: string) { - const url = - toChain.level0Indexer === Level0Indexer.ponder - ? this.transferService.ponderEndpoint - : toChain.indexerUrl; - const id = - toChain.level0Indexer === Level0Indexer.ponder - ? `${toChain.chainConfig.id}-${transferId}` - : transferId; - const query = `query { lnv3RelayRecord(id: "${id}") { id, relayer, timestamp, transactionHash, slashed, requestWithdrawTimestamp, fee }}`; - return await axios - .post(url, { - query: query, - variables: null, - }) - .then((res) => res.data?.data?.lnv3RelayRecord); + for (const level0Indexer of toChain.level0Indexers) { + const url = level0Indexer.url; + const service = this.sourceServices.get(level0Indexer.indexerType); + try { + const response = await service.queryRelayStatus( + level0Indexer.url, + toChain.chainConfig.id, + transferId + ); + if (response) { + return response; + } + } catch (err) { + this.logger.warn( + `try to get relay status failed, id ${toChain.chainConfig.id}, type ${level0Indexer.indexerType}` + ); + } + } } async queryRecordWithdrawStatus(transfer: PartnerT2, transferId: string) { - const url = - transfer.level0Indexer === Level0Indexer.ponder - ? this.transferService.ponderEndpoint - : transfer.indexerUrl; - const id = - transfer.level0Indexer === Level0Indexer.ponder - ? `${transfer.chainConfig.id}-${transferId}` - : transferId; - const query = `query { lnv3TransferRecord(id: "${id}") { id, hasWithdrawn }}`; - return await axios - .post(url, { - query: query, - variables: null, - }) - .then((res) => res.data?.data?.lnv3TransferRecord); + for (const level0Indexer of transfer.level0Indexers) { + const url = level0Indexer.url; + const service = this.sourceServices.get(level0Indexer.indexerType); + try { + const response = await service.queryWithdrawStatus( + level0Indexer.url, + transfer.chainConfig.id, + transferId + ); + if (response) { + return response; + } + } catch (err) { + this.logger.warn( + `try to get withdraw status failed, id ${transfer.chainConfig.id}, type ${level0Indexer.indexerType}` + ); + } + } } async fetchRecords(transfer: PartnerT2, index: number) { @@ -193,9 +206,6 @@ export class Lnv3Service implements OnModuleInit { this.fetchCache[index].latestNonce = latestNonce; continue; } - if (toChain.indexerUrl === null) { - continue; - } const fromToken = this.getTokenInfo(transfer, record.sourceToken); const toToken = this.getTokenInfo(toChain, record.targetToken); @@ -256,25 +266,26 @@ export class Lnv3Service implements OnModuleInit { // batch get status from target chain on sycing historical phase async queryFillInfos(transfer: PartnerT2, latestTimestamp: number) { - if (transfer.level0Indexer === Level0Indexer.ponder) { - const url = this.transferService.ponderEndpoint; - const query = `query { lnv3RelayRecords(limit: 50, orderBy: "timestamp", orderDirection: "asc", where: {localChainId: "${transfer.chainConfig.id}", slashed: false, timestamp_gt: "${latestTimestamp}"}) { items { id, timestamp, requestWithdrawTimestamp, relayer, transactionHash, slashed, fee } }}`; - return await axios - .post(url, { - query: query, - variables: null, - }) - .then((res) => res.data?.data?.lnv3RelayRecords.items); - } else { - const url = transfer.indexerUrl; - const query = `query { lnv3RelayRecords(first: 20, orderBy: timestamp, orderDirection: asc, where: {timestamp_gt: "${latestTimestamp}", slashed: false}) { id, timestamp, requestWithdrawTimestamp, relayer, transactionHash, slashed, fee } }`; - return await axios - .post(url, { - query: query, - variables: null, - }) - .then((res) => res.data?.data?.lnv3RelayRecords); + let result = []; + for (const level0Indexer of transfer.level0Indexers) { + const url = level0Indexer.url; + const service = this.sourceServices.get(level0Indexer.indexerType); + try { + const response = await service.batchQueryRelayStatus( + level0Indexer.url, + transfer.chainConfig.id, + latestTimestamp + ); + if (response && response.length >= result.length) { + result = response; + } + } catch (err) { + this.logger.warn( + `try to batch get fill infos failed, id ${transfer.chainConfig.id}, type ${level0Indexer.indexerType}` + ); + } } + return result; } async batchFetchStatus(transfer: PartnerT2, index: number) { @@ -427,9 +438,9 @@ export class Lnv3Service implements OnModuleInit { }); size += 1; - //this.logger.log( - //`lnv3 [${transfer.chain}->${toChain.chain}] new status id: ${record.id} relayed responseTxHash: ${relayRecord.transactionHash}` - //); + this.logger.log( + `lnv3 [${transfer.chainConfig.code}->${toChain.chainConfig.code}] new status id: ${record.id} relayed responseTxHash: ${relayRecord.transactionHash}` + ); } // query withdrawLiquidity result if (needWithdrawLiquidity && requestWithdrawTimestamp > 0) { @@ -514,7 +525,7 @@ export class Lnv3Service implements OnModuleInit { const records = await this.queryProviderInfo(transfer, latestNonce); // maybe this query is archived and can't access if (records === undefined) { - this.logger.warn(`query record failed, url: ${transfer.indexerUrl}`); + this.logger.warn(`query record failed, id: ${transfer.chainConfig.id}`); return; } diff --git a/apollo/src/lnv3/source/ponder.service.ts b/apollo/src/lnv3/source/ponder.service.ts new file mode 100644 index 0000000..cf8ec1f --- /dev/null +++ b/apollo/src/lnv3/source/ponder.service.ts @@ -0,0 +1,76 @@ +import axios from 'axios'; +import { + Lnv3Record, + Lnv3UpdateRecords, + Lnv3RelayRecord, + Lnv3WithdrawStatus, + SourceService, +} from './source.service'; + +export class Lnv3PonderService extends SourceService { + async queryRecordInfo(url: string, localId: number, latestNonce: number): Promise { + const query = `query { lnv3TransferRecords(limit: 20, orderBy: "nonce", orderDirection: "asc", where: {localChainId: "${localId}", nonce_gt: "${latestNonce}"}) { items { id, nonce, messageNonce, remoteChainId, provider, sourceToken, targetToken, sourceAmount, targetAmount, sender, receiver, timestamp, transactionHash, fee, transferId, hasWithdrawn } }}`; + return await axios + .post(url, { + query: query, + variables: null, + }) + .then((res) => res.data?.data?.lnv3TransferRecords.items); + } + + async queryProviderInfo( + url: string, + localId: number, + latestNonce: number + ): Promise { + const query = `query { lnv3RelayUpdateRecords(limit: 20, orderBy: "nonce", orderDirection: "asc", where: {localChainId: "${localId}", nonce_gt: "${latestNonce}"}) { items { id, updateType, remoteChainId, provider, transactionHash, timestamp, sourceToken, targetToken, penalty, baseFee, liquidityFeeRate, transferLimit, paused } }}`; + return await axios + .post(url, { + query: query, + variables: null, + }) + .then((res) => res.data?.data?.lnv3RelayUpdateRecords.items); + } + + async queryRelayStatus( + url: string, + localId: number, + transferId: string + ): Promise { + const id = `${localId}-${transferId}`; + const query = `query { lnv3RelayRecord(id: "${id}") { id, relayer, timestamp, transactionHash, slashed, requestWithdrawTimestamp, fee }}`; + return await axios + .post(url, { + query: query, + variables: null, + }) + .then((res) => res.data?.data?.lnv3RelayRecord); + } + async batchQueryRelayStatus( + url: string, + localId: number, + latestTimestamp: number + ): Promise { + const query = `query { lnv3RelayRecords(limit: 20, orderBy: "timestamp", orderDirection: "asc", where: {localChainId: "${localId}", slashed: false, timestamp_gt: "${latestTimestamp}"}) { items { id, timestamp, requestWithdrawTimestamp, relayer, transactionHash, slashed, fee } }}`; + return await axios + .post(url, { + query: query, + variables: null, + }) + .then((res) => res.data?.data?.lnv3RelayRecords.items); + } + async queryWithdrawStatus( + url: string, + localId: number, + transferId: string + ): Promise { + const id = `${localId}-${transferId}`; + const query = `query { lnv3TransferRecord(id: "${id}") { id, hasWithdrawn }}`; + return await axios + .post(url, { + query: query, + variables: null, + }) + .then((res) => res.data?.data?.lnv3TransferRecord); + } +} diff --git a/apollo/src/lnv3/source/source.service.ts b/apollo/src/lnv3/source/source.service.ts new file mode 100644 index 0000000..e16b1e0 --- /dev/null +++ b/apollo/src/lnv3/source/source.service.ts @@ -0,0 +1,78 @@ +export interface Lnv3Record { + id: string; + nonce: string; + messageNonce: string; + remoteChainId: number; + provider: string; + sourceToken: string; + sourceAmount: string; + targetToken: string; + targetAmount: string; + sender: string; + receiver: string; + timestamp: string; + transactionHash: string; + fee: string; + transferId: string; + hasWithdrawn: boolean; +} + +export interface Lnv3UpdateRecords { + id: string; + updateType: number; + remoteChainId: number; + provider: string; + transactionHash: string; + timestamp: string; + sourceToken: string; + targetToken: string; + penalty: string; + baseFee: string; + liquidityFeeRate: number; + transferLimit: string; + paused: boolean; +} + +export interface Lnv3RelayRecord { + id: string; + relayer: string; + timestamp: string; + transactionHash: string; + slashed: boolean; + requestWithdrawTimestamp: string; + fee: string; +} + +export interface Lnv3WithdrawStatus { + id: string; + hasWithdrawn: boolean; + responseTxHash: string; +} + +export abstract class SourceService { + abstract queryRecordInfo( + url: string, + chainId: number, + latestNonce: number + ): Promise; + abstract queryProviderInfo( + url: string, + chainId: number, + latestNonce: number + ): Promise; + abstract queryRelayStatus( + url: string, + chainId: number, + transferId: string + ): Promise; + abstract batchQueryRelayStatus( + url: string, + chainId: number, + latestTimestamp: number + ): Promise; + abstract queryWithdrawStatus( + url: string, + chainId: number, + transferId: string + ): Promise; +} diff --git a/apollo/src/lnv3/source/thegraph.service.ts b/apollo/src/lnv3/source/thegraph.service.ts new file mode 100644 index 0000000..ac90003 --- /dev/null +++ b/apollo/src/lnv3/source/thegraph.service.ts @@ -0,0 +1,73 @@ +import axios from 'axios'; +import { + Lnv3Record, + Lnv3UpdateRecords, + Lnv3RelayRecord, + Lnv3WithdrawStatus, + SourceService, +} from './source.service'; + +export class Lnv3ThegraphService extends SourceService { + async queryRecordInfo(url: string, chainId: number, latestNonce: number): Promise { + const query = `query { lnv3TransferRecords(first: 20, orderBy: nonce, orderDirection: asc, skip: ${latestNonce}) { id, nonce, messageNonce, remoteChainId, provider, sourceToken, targetToken, sourceAmount, targetAmount, sender, receiver, timestamp, transactionHash, fee, transferId, hasWithdrawn } }`; + return await axios + .post(url, { + query: query, + variables: null, + }) + .then((res) => res.data?.data?.lnv3TransferRecords); + } + + async queryProviderInfo( + url: string, + chainId: number, + latestNonce: number + ): Promise { + const query = `query { lnv3RelayUpdateRecords(first: 20, orderBy: nonce, orderDirection: asc, skip: ${latestNonce}) { id, updateType, remoteChainId, provider, transactionHash, timestamp, sourceToken, targetToken, penalty, baseFee, liquidityFeeRate, transferLimit, paused } }`; + return await axios + .post(url, { + query: query, + variables: null, + }) + .then((res) => res.data?.data?.lnv3RelayUpdateRecords); + } + async queryRelayStatus( + url: string, + chainId: number, + transferId: string + ): Promise { + const query = `query { lnv3RelayRecord(id: "${transferId}") { id, relayer, timestamp, transactionHash, slashed, requestWithdrawTimestamp, fee }}`; + return await axios + .post(url, { + query: query, + variables: null, + }) + .then((res) => res.data?.data?.lnv3RelayRecord); + } + async batchQueryRelayStatus( + url: string, + chainId: number, + latestTimestamp: number + ): Promise { + const query = `query { lnv3RelayRecords(first: 20, orderBy: timestamp, orderDirection: asc, where: {timestamp_gt: "${latestTimestamp}", slashed: false}) { id, timestamp, requestWithdrawTimestamp, relayer, transactionHash, slashed, fee } }`; + return await axios + .post(url, { + query: query, + variables: null, + }) + .then((res) => res.data?.data?.lnv3RelayRecords); + } + async queryWithdrawStatus( + url: string, + chainId: number, + transferId: string + ): Promise { + const query = `query { lnv3TransferRecord(id: "${transferId}") { id, hasWithdrawn }}`; + return await axios + .post(url, { + query: query, + variables: null, + }) + .then((res) => res.data?.data?.lnv3TransferRecord); + } +} diff --git a/apollo/src/lnv3/transfer.service.ts b/apollo/src/lnv3/transfer.service.ts index 1d5395d..7e4de3e 100644 --- a/apollo/src/lnv3/transfer.service.ts +++ b/apollo/src/lnv3/transfer.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { HelixChain } from '@helixbridge/helixconf'; -import { BaseTransferServiceT2, PartnerT2, Level0Indexer } from '../base/TransferServiceT2'; +import { BaseTransferServiceT2, PartnerT2, Level0IndexerType } from '../base/TransferServiceT2'; import { AddressTokenMap } from '../base/AddressToken'; @Injectable() @@ -29,101 +29,177 @@ export class TransferService extends BaseTransferServiceT2 { formalChainTransfers: PartnerT2[] = [ { - level0Indexer: Level0Indexer.thegraph, - indexerUrl: this.polygonEndpoint, + level0Indexers: [ + { + indexerType: Level0IndexerType.thegraph, + url: this.polygonEndpoint, + }, + ], chainConfig: HelixChain.polygon, }, { - level0Indexer: Level0Indexer.thegraph, - indexerUrl: this.arbitrumEndpoint, + level0Indexers: [ + { + indexerType: Level0IndexerType.thegraph, + url: this.arbitrumEndpoint, + }, + ], chainConfig: HelixChain.arbitrum, }, { - level0Indexer: Level0Indexer.thegraph, - indexerUrl: this.bscEndpoint, + level0Indexers: [ + { + indexerType: Level0IndexerType.thegraph, + url: this.bscEndpoint, + }, + ], chainConfig: HelixChain.bsc, }, { - level0Indexer: Level0Indexer.thegraph, - indexerUrl: this.lineaEndpoint, + level0Indexers: [ + { + indexerType: Level0IndexerType.thegraph, + url: this.lineaEndpoint, + }, + ], chainConfig: HelixChain.linea, }, { - level0Indexer: Level0Indexer.thegraph, - indexerUrl: this.opEndpoint, + level0Indexers: [ + { + indexerType: Level0IndexerType.thegraph, + url: this.opEndpoint, + }, + ], chainConfig: HelixChain.op, }, { - level0Indexer: Level0Indexer.thegraph, - indexerUrl: this.gnosisEndpoint, + level0Indexers: [ + { + indexerType: Level0IndexerType.thegraph, + url: this.gnosisEndpoint, + }, + ], chainConfig: HelixChain.gnosis, }, { - level0Indexer: Level0Indexer.thegraph, - indexerUrl: this.mantleEndpoint, + level0Indexers: [ + { + indexerType: Level0IndexerType.thegraph, + url: this.mantleEndpoint, + }, + ], chainConfig: HelixChain.mantle, }, { - level0Indexer: Level0Indexer.thegraph, - indexerUrl: this.scrollEndpoint, + level0Indexers: [ + { + indexerType: Level0IndexerType.thegraph, + url: this.scrollEndpoint, + }, + ], chainConfig: HelixChain.scroll, }, { - level0Indexer: Level0Indexer.thegraph, - indexerUrl: this.darwiniaEndpoint, + level0Indexers: [ + { + indexerType: Level0IndexerType.thegraph, + url: this.darwiniaEndpoint, + }, + ], chainConfig: HelixChain.darwiniaDvm, }, { - level0Indexer: Level0Indexer.thegraph, - indexerUrl: this.blastEndpoint, + level0Indexers: [ + { + indexerType: Level0IndexerType.thegraph, + url: this.blastEndpoint, + }, + ], chainConfig: HelixChain.blast, }, { - level0Indexer: Level0Indexer.thegraph, - indexerUrl: this.astarZkEVMEndpoint, + level0Indexers: [ + { + indexerType: Level0IndexerType.thegraph, + url: this.astarZkEVMEndpoint, + }, + ], chainConfig: HelixChain.astarZkevm, }, { - level0Indexer: Level0Indexer.thegraph, - indexerUrl: this.moonbeamEndpoint, + level0Indexers: [ + { + indexerType: Level0IndexerType.thegraph, + url: this.moonbeamEndpoint, + }, + ], chainConfig: HelixChain.moonbeam, }, ]; testChainTransfers: PartnerT2[] = [ { - level0Indexer: Level0Indexer.thegraph, - indexerUrl: this.ethereumEndpoint, + level0Indexers: [ + { + indexerType: Level0IndexerType.thegraph, + url: this.ethereumEndpoint, + }, + ], chainConfig: HelixChain.sepolia, }, { - level0Indexer: Level0Indexer.thegraph, - indexerUrl: this.arbitrumEndpoint, + level0Indexers: [ + { + indexerType: Level0IndexerType.thegraph, + url: this.arbitrumEndpoint, + }, + ], chainConfig: HelixChain.arbitrumSepolia, }, { - level0Indexer: Level0Indexer.thegraph, - indexerUrl: this.zksyncEndpoint, + level0Indexers: [ + { + indexerType: Level0IndexerType.thegraph, + url: this.zksyncEndpoint, + }, + ], chainConfig: HelixChain.zksyncSepolia, }, { - level0Indexer: Level0Indexer.ponder, - indexerUrl: this.taikoEndpoint, + level0Indexers: [ + { + indexerType: Level0IndexerType.ponder, + url: this.taikoEndpoint, + }, + ], chainConfig: HelixChain.taikoHekla, }, { - level0Indexer: Level0Indexer.ponder, - indexerUrl: this.beraEndpoint, + level0Indexers: [ + { + indexerType: Level0IndexerType.thegraph, + url: this.beraEndpoint, + }, + ], chainConfig: HelixChain.bera, }, { - level0Indexer: Level0Indexer.ponder, - indexerUrl: this.morphEndpoint, + level0Indexers: [ + { + indexerType: Level0IndexerType.thegraph, + url: this.morphEndpoint, + }, + ], chainConfig: HelixChain.morph, }, { - level0Indexer: Level0Indexer.thegraph, - indexerUrl: this.baseEndpoint, + level0Indexers: [ + { + indexerType: Level0IndexerType.thegraph, + url: this.baseEndpoint, + }, + ], chainConfig: HelixChain.baseSepolia, }, ];