From ab7af01a4582f46a7e1ca873d2ab203872a3d805 Mon Sep 17 00:00:00 2001 From: Rick Staa Date: Sun, 19 Jul 2026 21:09:53 +0200 Subject: [PATCH] fix: source current round timing on-chain instead of the subgraph /current-round mixed sources: round id/startBlock/initialized came from the subgraph, but the current block from a live RPC call. When subgraph indexing stalls the stale round is compared against a live block, so the tracker shows a stale round number with counters running past the round length. Read the timing from the RoundsManager contract (currentRound, currentRoundStartBlock, currentRoundInitialized, blockNum) via l2PublicClient, keeping startBlock and the current block consistent and independent of subgraph health. Response shape is unchanged; aggregate stats still use the subgraph. Co-Authored-By: Claude Opus 4.8 (1M context) --- pages/api/current-round.tsx | 48 +++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/pages/api/current-round.tsx b/pages/api/current-round.tsx index d0a64b58..d4ad704d 100644 --- a/pages/api/current-round.tsx +++ b/pages/api/current-round.tsx @@ -1,7 +1,9 @@ -import { getCacheControlHeader, getCurrentRound } from "@lib/api"; +import { getCacheControlHeader } from "@lib/api"; +import { roundsManager } from "@lib/api/abis/main/RoundsManager"; +import { getContractAddress } from "@lib/api/contracts"; import { internalError, methodNotAllowed } from "@lib/api/errors"; import { CurrentRoundInfo } from "@lib/api/types/get-current-round"; -import { l1PublicClient } from "@lib/chains"; +import { l2PublicClient } from "@lib/chains"; import { NextApiRequest, NextApiResponse } from "next"; const handler = async ( @@ -14,28 +16,38 @@ const handler = async ( if (method === "GET") { res.setHeader("Cache-Control", getCacheControlHeader("minute")); - const { - data: { protocol, _meta }, - } = await getCurrentRound(); - const currentRound = protocol?.currentRound; + const roundsManagerAddress = await getContractAddress("RoundsManager"); - if (!currentRound) { - throw new Error("No current round found"); - } + const contract = { + address: roundsManagerAddress, + abi: roundsManager, + } as const; - if (!_meta?.block) { - throw new Error("No block number found"); - } - - const { id, startBlock, initialized } = currentRound; - - const currentL2Block = _meta.block.number; - const currentL1Block = await l1PublicClient.getBlockNumber(); + const [id, startBlock, initialized, currentL1Block, currentL2Block] = + await Promise.all([ + l2PublicClient.readContract({ + ...contract, + functionName: "currentRound", + }), + l2PublicClient.readContract({ + ...contract, + functionName: "currentRoundStartBlock", + }), + l2PublicClient.readContract({ + ...contract, + functionName: "currentRoundInitialized", + }), + l2PublicClient.readContract({ + ...contract, + functionName: "blockNum", + }), + l2PublicClient.getBlockNumber(), + ]); const roundInfo: CurrentRoundInfo = { id: Number(id), startBlock: Number(startBlock), - initialized, + initialized: Boolean(initialized), currentL1Block: Number(currentL1Block), currentL2Block: Number(currentL2Block), };