Skip to content

feat: oracle live checks#400

Merged
antoncoding merged 4 commits intomasterfrom
oracle/staleness
Feb 18, 2026
Merged

feat: oracle live checks#400
antoncoding merged 4 commits intomasterfrom
oracle/staleness

Conversation

@antoncoding
Copy link
Copy Markdown
Owner

@antoncoding antoncoding commented Feb 18, 2026

Summary by CodeRabbit

  • New Features

    • Added feed freshness indicators across oracle feeds (last updated, age, stale/derived status) with periodic refresh; tooltips for all feed types now surface these details.
    • Improved vendor icon rendering to show known vendor icons more broadly.
  • Chores

    • Renamed environment variable for oracle gist base URL to NEXT_PUBLIC_ORACLE_GIST_BASE_URL.
    • Oracle metadata fetching switched to the configured Gist endpoint.

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Feb 18, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
monarch Ready Ready Preview, Comment Feb 18, 2026 1:03am

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 18, 2026

📝 Walkthrough

Walkthrough

Adds per-feed freshness tracking and UI: a new hook fetches feed snapshots via multicall, oracle metadata fetching is shifted to direct Gist URLs (env var renamed), feed-freshness UI component and ABI added, and freshness data is threaded into tooltip and feed components across MarketOracle.

Changes

Cohort / File(s) Summary
Environment Configuration
​.env.local.example
Renamed ORACLE_GIST_BASE_URLNEXT_PUBLIC_ORACLE_GIST_BASE_URL.
Documentation
AGENTS.md
Added mandatory "Post-Implementation Consolidation" checklist section.
API Route Removal
app/api/oracle-metadata/[chainId]/route.ts
Deleted Next.js API route that proxied oracle metadata; direct Gist fetching replaces it.
ABIs & Utilities
src/abis/chainlink-aggregator-v3.ts, src/utils/oracle.ts
Added Chainlink Aggregator v3 ABI. Introduced FeedFreshnessStatus, FeedUpdateKind, formatting helpers, and getFeedFreshnessStatus.
Feed Snapshot Hook
src/hooks/useFeedLastUpdatedByChain.ts
New hook computing per-address FeedSnapshot via batched multicalls (latestRoundData + decimals), 60s refresh, returns FeedSnapshotByAddress.
Metadata Fetching & Queries
src/hooks/useOracleMetadata.ts, src/components/providers/QueryProvider.tsx
useOracleMetadata now fetches directly from Gist base URL; added feed-snapshot to actionable query root keys for error reporting.
Feed Freshness UI
src/features/markets/components/oracle/MarketOracle/FeedFreshnessSection.tsx
New component rendering price, last-updated, age, derived/stale indicators.
Tooltips & Feed Integration
src/features/markets/components/oracle/MarketOracle/...
Extended all feed tooltip variants (Chainlink, Compound, Pendle, Redstone, General, Unknown) to accept feedFreshness and adjusted tooltip width/layout. FeedEntry, MarketOracleFeedInfo, MetaOracleInfo threaded feedSnapshotsByAddress and compute/forward freshness; vendor icon rendering simplified.

Sequence Diagram

sequenceDiagram
    participant UI as MarketOracle UI
    participant Hook as useFeedLastUpdatedByChain
    participant QueryCache as React Query
    participant Multicall as Multicall Contract
    participant Tooltip as Feed Tooltip

    UI->>Hook: request feedSnapshotsByAddress(chainId)
    Hook->>Hook: derive feed addresses & hints from oracle metadata
    Hook->>QueryCache: subscribe with key ['feed-snapshot', chainId, ...] (60s refetch)
    QueryCache->>Multicall: batch call latestRoundData + decimals for addresses
    Multicall-->>QueryCache: return roundData & decimals
    QueryCache-->>Hook: deliver results
    Hook->>Hook: compute FeedSnapshot (updatedAt, normalizedPrice, updateKind)
    Hook-->>UI: return FeedSnapshotByAddress
    UI->>Tooltip: pass feedFreshness prop
    Tooltip->>Tooltip: render FeedFreshnessSection (price, timestamp, age, stale/derived)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'oracle live checks' accurately describes the main change: adding feed freshness monitoring and live status checks to oracle components.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch oracle/staleness

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot added feature request Specific feature ready to be implemented ui User interface labels Feb 18, 2026
Copy link
Copy Markdown
Collaborator

@starksama starksama left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Clean implementation for oracle feed freshness indicators.

Reviewed:

  • useFeedLastUpdatedByChain hook - good batching and fingerprinting approach
  • FeedFreshnessSection component - clean UI for freshness display
  • ✅ Derived vs reported feed detection (Pendle handling)
  • ✅ Direct Gist fetching (API route removal)
  • ✅ Type safety and edge case handling

Minor note: ageSeconds computed at render time means display can drift between 60s refetches - acceptable tradeoff.

Ship it 🚀

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/hooks/useOracleMetadata.ts (1)

113-131: ⚠️ Potential issue | 🟡 Minor

response.json() not awaited — JSON parse errors escape the try-catch

If the Gist returns malformed JSON, the rejected Promise bypasses the catch block, so the query errors out instead of returning null as intended. As per coding guidelines, promises in async functions should always be awaited.

🔧 Fix
-    return response.json();
+    return await response.json();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/hooks/useOracleMetadata.ts` around lines 113 - 131, In
useOracleMetadata.ts inside the hook's fetch block, await the response.json()
call so JSON parse errors are caught by the surrounding try/catch; replace the
bare return response.json() with e.g. const data = await response.json(); return
data (while keeping the existing handling of ORACLE_GIST_BASE_URL, chainId,
response.ok checks and the catch that logs and returns null).
🧹 Nitpick comments (3)
src/features/markets/components/oracle/MarketOracle/FeedFreshnessSection.tsx (1)

56-61: Redundant guard on staleAfterSeconds != null

isStale is only ever true when staleAfterSeconds != null (see getFeedFreshnessStatus in oracle.ts), so the second condition is always true when the first holds.

♻️ Simplify
-      {feedFreshness.isStale && feedFreshness.staleAfterSeconds != null && (
+      {feedFreshness.isStale && (
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/features/markets/components/oracle/MarketOracle/FeedFreshnessSection.tsx`
around lines 56 - 61, The JSX condition currently checks both
feedFreshness.isStale and feedFreshness.staleAfterSeconds != null redundantly;
remove the unnecessary staleAfterSeconds != null guard and render the "Stale"
block solely when feedFreshness.isStale is true (the isStale invariant is set by
getFeedFreshnessStatus), leaving the fragment that references
feedFreshness.isStale unchanged otherwise.
src/utils/oracle.ts (1)

718-726: formatOracleTimestampCompact hardcodes MM/DD while formatOracleTimestamp is locale-aware

The compact variant uses getMonth()/getDate() giving a fixed US-format MM/DD, while formatOracleTimestamp delegates to toLocaleString(). Users outside North America will see date parts in the wrong order from formatOracleTimestampCompact.

♻️ One option — use `Intl.DateTimeFormat` for both parts
 export function formatOracleTimestampCompact(seconds: number): string {
   const date = new Date(seconds * 1000);
-  const hours = `${date.getHours()}`.padStart(2, '0');
-  const minutes = `${date.getMinutes()}`.padStart(2, '0');
-  const month = `${date.getMonth() + 1}`.padStart(2, '0');
-  const day = `${date.getDate()}`.padStart(2, '0');
-
-  return `${hours}:${minutes} ${month}/${day}`;
+  const time = date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
+  const datePart = date.toLocaleDateString([], { month: '2-digit', day: '2-digit' });
+  return `${time} ${datePart}`;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/oracle.ts` around lines 718 - 726, formatOracleTimestampCompact
currently builds the date part as MM/DD using date.getMonth()/getDate(), causing
a fixed US order that can conflict with the locale-aware formatOracleTimestamp;
change formatOracleTimestampCompact to use an Intl.DateTimeFormat (or
Date.prototype.toLocaleDateString) to produce the localized date portion and
keep the time portion formatted as before, e.g., obtain localized month/day
ordering from new Intl.DateTimeFormat(undefined, { month: '2-digit', day:
'2-digit' }).format(date) (or date.toLocaleDateString()) and combine that with
the existing hours:minutes string so the function respects user locale like
formatOracleTimestamp does.
src/hooks/useFeedLastUpdatedByChain.ts (1)

155-157: Redundant RPC call — getBlock() alone gives you both number and timestamp.

publicClient.getBlock() returns the latest block including .number and .timestamp, saving one round-trip.

Suggested fix
-      const blockNumber = await publicClient.getBlockNumber();
-      const block = await publicClient.getBlock({ blockNumber });
-      const queryBlockTimestamp = Number(block.timestamp);
+      const block = await publicClient.getBlock();
+      const blockNumber = block.number;
+      const queryBlockTimestamp = Number(block.timestamp);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/hooks/useFeedLastUpdatedByChain.ts` around lines 155 - 157, The code in
useFeedLastUpdatedByChain.ts makes a redundant RPC call by calling
publicClient.getBlockNumber() then publicClient.getBlock({ blockNumber });
instead call publicClient.getBlock() once and read both .number and .timestamp
from its result; update the logic that assigns blockNumber and
queryBlockTimestamp to use the single getBlock() response (replace references
that use getBlockNumber() + getBlock(...) with a single getBlock() call and
extract .number and .timestamp).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/hooks/useOracleMetadata.ts`:
- Around line 113-131: In useOracleMetadata.ts inside the hook's fetch block,
await the response.json() call so JSON parse errors are caught by the
surrounding try/catch; replace the bare return response.json() with e.g. const
data = await response.json(); return data (while keeping the existing handling
of ORACLE_GIST_BASE_URL, chainId, response.ok checks and the catch that logs and
returns null).

---

Nitpick comments:
In
`@src/features/markets/components/oracle/MarketOracle/FeedFreshnessSection.tsx`:
- Around line 56-61: The JSX condition currently checks both
feedFreshness.isStale and feedFreshness.staleAfterSeconds != null redundantly;
remove the unnecessary staleAfterSeconds != null guard and render the "Stale"
block solely when feedFreshness.isStale is true (the isStale invariant is set by
getFeedFreshnessStatus), leaving the fragment that references
feedFreshness.isStale unchanged otherwise.

In `@src/hooks/useFeedLastUpdatedByChain.ts`:
- Around line 155-157: The code in useFeedLastUpdatedByChain.ts makes a
redundant RPC call by calling publicClient.getBlockNumber() then
publicClient.getBlock({ blockNumber }); instead call publicClient.getBlock()
once and read both .number and .timestamp from its result; update the logic that
assigns blockNumber and queryBlockTimestamp to use the single getBlock()
response (replace references that use getBlockNumber() + getBlock(...) with a
single getBlock() call and extract .number and .timestamp).

In `@src/utils/oracle.ts`:
- Around line 718-726: formatOracleTimestampCompact currently builds the date
part as MM/DD using date.getMonth()/getDate(), causing a fixed US order that can
conflict with the locale-aware formatOracleTimestamp; change
formatOracleTimestampCompact to use an Intl.DateTimeFormat (or
Date.prototype.toLocaleDateString) to produce the localized date portion and
keep the time portion formatted as before, e.g., obtain localized month/day
ordering from new Intl.DateTimeFormat(undefined, { month: '2-digit', day:
'2-digit' }).format(date) (or date.toLocaleDateString()) and combine that with
the existing hours:minutes string so the function respects user locale like
formatOracleTimestamp does.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
src/utils/oracle.ts (1)

730-731: Magic numbers 36 and 8 should be named constants.

As per coding guidelines, extract these with descriptive names.

Proposed fix
+const MAX_FEED_DECIMALS = 36;
+const DEFAULT_FEED_DECIMALS = 8;

 export function formatOraclePrice(answerRaw: bigint, decimals: number, maxFractionDigits = 8): string {
-  const safeDecimals = Number.isFinite(decimals) ? Math.max(0, Math.min(36, Math.floor(decimals))) : 8;
+  const safeDecimals = Number.isFinite(decimals) ? Math.max(0, Math.min(MAX_FEED_DECIMALS, Math.floor(decimals))) : DEFAULT_FEED_DECIMALS;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/oracle.ts` around lines 730 - 731, The magic numbers 36 and 8 in
formatOraclePrice should be replaced with named constants; introduce descriptive
constants (e.g., MAX_SAFE_DECIMALS = 36 and DEFAULT_FRACTION_DIGITS = 8) and use
them where Number.isFinite(decimals) bounds decimals and as the fallback for
maxFractionDigits; update the function signature/defaults and the local
safeDecimals calculation to reference these constants (symbols:
formatOraclePrice, decimals, maxFractionDigits, safeDecimals) so the intent is
clear and the values are maintainable.
src/features/markets/components/oracle/MarketOracle/FeedFreshnessSection.tsx (2)

15-16: hasTimestamp/hasPrice not reused in JSX.

Both are computed for the guard but the JSX re-checks updatedAt != null / normalizedPrice != null directly. Either use the variables consistently in JSX, or inline the guard and drop the variables.

Proposed fix (use variables in JSX)
-      {normalizedPrice != null && (
+      {hasPrice && (
         ...
-      {updatedAt != null && (
+      {hasTimestamp && (
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/features/markets/components/oracle/MarketOracle/FeedFreshnessSection.tsx`
around lines 15 - 16, The component computes hasTimestamp and hasPrice but the
JSX redundantly re-checks updatedAt != null and normalizedPrice != null; update
the JSX in FeedFreshnessSection to use the computed booleans (hasTimestamp and
hasPrice) wherever those null-checks are currently repeated (e.g., conditional
rendering or ternaries), or remove the variables and inline the checks
consistently—preferably replace direct checks of updatedAt != null /
normalizedPrice != null in the JSX with hasTimestamp / hasPrice to avoid
duplication and keep intent clear.

10-10: Missing explicit return type.

Per coding guidelines, add an explicit return type for clarity.

Proposed fix
-export function FeedFreshnessSection({ feedFreshness, className }: FeedFreshnessSectionProps) {
+export function FeedFreshnessSection({ feedFreshness, className }: FeedFreshnessSectionProps): JSX.Element | null {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/features/markets/components/oracle/MarketOracle/FeedFreshnessSection.tsx`
at line 10, The function FeedFreshnessSection is missing an explicit return
type; update its signature to include an explicit JSX return type (e.g., change
export function FeedFreshnessSection({ feedFreshness, className }:
FeedFreshnessSectionProps) to export function FeedFreshnessSection({
feedFreshness, className }: FeedFreshnessSectionProps): JSX.Element and ensure
JSX types are available (add an import for React or JSX types if your tsconfig
requires it); keep the existing props type FeedFreshnessSectionProps and body
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/features/markets/components/oracle/MarketOracle/FeedFreshnessSection.tsx`:
- Around line 56-61: The "Stale" status rendered when feedFreshness.isStale in
FeedFreshnessSection lacks ARIA — update the element that outputs "Stale" to
provide an accessibility cue (e.g., add role="status" and aria-live="polite"
and/or an aria-label like "Feed data is stale") so screen readers announce
severity; keep the visible text unchanged and apply the attributes to the
existing span that renders the status.

In `@src/utils/oracle.ts`:
- Around line 718-725: The compact timestamp formatter
formatOracleTimestampCompact omits the year causing identical renderings for
dates across different years; update the options passed to new
Date(...).toLocaleString in formatOracleTimestampCompact to include year:
'2-digit' (i.e., add year: '2-digit' to the locale options) so timestamps
display the two-digit year in the compact format.
- Line 702: The isStale computation currently uses a strict greater-than check
(ageSeconds > staleAfterSeconds) which treats entries exactly equal to the
heartbeat as fresh; if the intended semantics are "stale at or past the
heartbeat" change the comparison to >=. Update the expression where isStale is
set (referencing the symbols isStale, ageSeconds, and staleAfterSeconds) to use
a greater-than-or-equal comparison so records whose age equals staleAfterSeconds
are flagged stale.

---

Nitpick comments:
In
`@src/features/markets/components/oracle/MarketOracle/FeedFreshnessSection.tsx`:
- Around line 15-16: The component computes hasTimestamp and hasPrice but the
JSX redundantly re-checks updatedAt != null and normalizedPrice != null; update
the JSX in FeedFreshnessSection to use the computed booleans (hasTimestamp and
hasPrice) wherever those null-checks are currently repeated (e.g., conditional
rendering or ternaries), or remove the variables and inline the checks
consistently—preferably replace direct checks of updatedAt != null /
normalizedPrice != null in the JSX with hasTimestamp / hasPrice to avoid
duplication and keep intent clear.
- Line 10: The function FeedFreshnessSection is missing an explicit return type;
update its signature to include an explicit JSX return type (e.g., change export
function FeedFreshnessSection({ feedFreshness, className }:
FeedFreshnessSectionProps) to export function FeedFreshnessSection({
feedFreshness, className }: FeedFreshnessSectionProps): JSX.Element and ensure
JSX types are available (add an import for React or JSX types if your tsconfig
requires it); keep the existing props type FeedFreshnessSectionProps and body
unchanged.

In `@src/utils/oracle.ts`:
- Around line 730-731: The magic numbers 36 and 8 in formatOraclePrice should be
replaced with named constants; introduce descriptive constants (e.g.,
MAX_SAFE_DECIMALS = 36 and DEFAULT_FRACTION_DIGITS = 8) and use them where
Number.isFinite(decimals) bounds decimals and as the fallback for
maxFractionDigits; update the function signature/defaults and the local
safeDecimals calculation to reference these constants (symbols:
formatOraclePrice, decimals, maxFractionDigits, safeDecimals) so the intent is
clear and the values are maintainable.

Comment on lines +56 to +61
{feedFreshness.isStale && (
<div className="flex items-center justify-between gap-1">
<span className="font-zen text-xs text-gray-600 dark:text-gray-400">Status:</span>
<span className="text-right font-zen text-xs font-medium text-yellow-700 dark:text-yellow-300">Stale</span>
</div>
)}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

"Stale" status has no ARIA indicator.

Screen readers see the yellow text as plain text with no hint of severity. A role="status" or aria-label would help. As per coding guidelines, use semantic HTML and ARIA attributes for accessibility.

Proposed fix
-          <span className="text-right font-zen text-xs font-medium text-yellow-700 dark:text-yellow-300">Stale</span>
+          <span role="status" aria-label="Feed is stale" className="text-right font-zen text-xs font-medium text-yellow-700 dark:text-yellow-300">Stale</span>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{feedFreshness.isStale && (
<div className="flex items-center justify-between gap-1">
<span className="font-zen text-xs text-gray-600 dark:text-gray-400">Status:</span>
<span className="text-right font-zen text-xs font-medium text-yellow-700 dark:text-yellow-300">Stale</span>
</div>
)}
{feedFreshness.isStale && (
<div className="flex items-center justify-between gap-1">
<span className="font-zen text-xs text-gray-600 dark:text-gray-400">Status:</span>
<span role="status" aria-label="Feed is stale" className="text-right font-zen text-xs font-medium text-yellow-700 dark:text-yellow-300">Stale</span>
</div>
)}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/features/markets/components/oracle/MarketOracle/FeedFreshnessSection.tsx`
around lines 56 - 61, The "Stale" status rendered when feedFreshness.isStale in
FeedFreshnessSection lacks ARIA — update the element that outputs "Stale" to
provide an accessibility cue (e.g., add role="status" and aria-live="polite"
and/or an aria-label like "Feed data is stale") so screen readers announce
severity; keep the visible text unchanged and apply the attributes to the
existing span that renders the status.

Comment thread src/utils/oracle.ts
updatedAt,
ageSeconds,
staleAfterSeconds,
isStale: staleAfterSeconds != null ? ageSeconds > staleAfterSeconds : false,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Stale boundary is exclusive — confirm intent.

ageSeconds > staleAfterSeconds means a feed whose age equals the heartbeat exactly is not flagged stale. If the intention is "at or past heartbeat = stale," change to >=.

Proposed fix
-    isStale: staleAfterSeconds != null ? ageSeconds > staleAfterSeconds : false,
+    isStale: staleAfterSeconds != null ? ageSeconds >= staleAfterSeconds : false,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
isStale: staleAfterSeconds != null ? ageSeconds > staleAfterSeconds : false,
isStale: staleAfterSeconds != null ? ageSeconds >= staleAfterSeconds : false,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/oracle.ts` at line 702, The isStale computation currently uses a
strict greater-than check (ageSeconds > staleAfterSeconds) which treats entries
exactly equal to the heartbeat as fresh; if the intended semantics are "stale at
or past the heartbeat" change the comparison to >=. Update the expression where
isStale is set (referencing the symbols isStale, ageSeconds, and
staleAfterSeconds) to use a greater-than-or-equal comparison so records whose
age equals staleAfterSeconds are flagged stale.

Comment thread src/utils/oracle.ts
Comment on lines +718 to +725
export function formatOracleTimestampCompact(seconds: number): string {
return new Date(seconds * 1000).toLocaleString(undefined, {
hour: '2-digit',
minute: '2-digit',
month: '2-digit',
day: '2-digit',
});
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Compact format omits the year.

Two timestamps a year apart will render identically (e.g. 02/15, 10:30 AM). Consider adding year: '2-digit' if this surface is ever used across year boundaries.

Proposed fix
 export function formatOracleTimestampCompact(seconds: number): string {
   return new Date(seconds * 1000).toLocaleString(undefined, {
     hour: '2-digit',
     minute: '2-digit',
     month: '2-digit',
     day: '2-digit',
+    year: '2-digit',
   });
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function formatOracleTimestampCompact(seconds: number): string {
return new Date(seconds * 1000).toLocaleString(undefined, {
hour: '2-digit',
minute: '2-digit',
month: '2-digit',
day: '2-digit',
});
}
export function formatOracleTimestampCompact(seconds: number): string {
return new Date(seconds * 1000).toLocaleString(undefined, {
hour: '2-digit',
minute: '2-digit',
month: '2-digit',
day: '2-digit',
year: '2-digit',
});
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/oracle.ts` around lines 718 - 725, The compact timestamp formatter
formatOracleTimestampCompact omits the year causing identical renderings for
dates across different years; update the options passed to new
Date(...).toLocaleString in formatOracleTimestampCompact to include year:
'2-digit' (i.e., add year: '2-digit' to the locale options) so timestamps
display the two-digit year in the compact format.

@antoncoding antoncoding merged commit 87a314d into master Feb 18, 2026
4 checks passed
@antoncoding antoncoding deleted the oracle/staleness branch February 18, 2026 01:09
@coderabbitai coderabbitai Bot mentioned this pull request Mar 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature request Specific feature ready to be implemented ui User interface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants