Skip to content

Conversation

@0xFirekeeper
Copy link
Member

@0xFirekeeper 0xFirekeeper commented Nov 19, 2025

Introduces a new GasMetricsChartCard component to visualize gas usage, average gas price, and cost efficiency across chains. Updates the analytics API and UserOpStats type to include gasUnits and avgGasPrice fields, and aggregates these metrics for display. Integrates the new chart into the account abstraction analytics page.

Closes BLD-460


PR-Codex overview

This PR enhances the analytics functionality by introducing gas metrics to track gas units and average gas prices for user operations. It modifies existing types, functions, and components to accommodate these new metrics.

Detailed summary

  • Added gasUnits and avgGasPrice to UserOpStats in analytics.ts.
  • Introduced random generation of gasUnits and avgGasPrice in storyUtils.ts.
  • Replaced SponsoredTransactionsChartCard with GasMetricsChartCard in aa-analytics.tsx.
  • Updated aggregation logic to include gasUnits and average avgGasPrice in analytics.ts.
  • Created GasMetricsChartCard component to visualize gas metrics.
  • Implemented metric selection and display logic for gas-related data in the chart.

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

Summary by CodeRabbit

  • New Features

    • Added a Gas Metrics chart to the Account Abstraction dashboard with metric toggles (sponsored transactions, gas units, average gas price, cost per gas unit).
    • Chart supports exporting gas analytics to CSV.
  • Improvements

    • Gas analytics now include gasUnits and avgGasPrice and use improved aggregation for more accurate average gas‑price reporting.
    • Dashboard view updated to show the new Gas Metrics chart in place of the previous chart.

✏️ Tip: You can customize this high-level summary in your review settings.

Introduces a new GasMetricsChartCard component to visualize gas usage, average gas price, and cost efficiency across chains. Updates the analytics API and UserOpStats type to include gasUnits and avgGasPrice fields, and aggregates these metrics for display. Integrates the new chart into the account abstraction analytics page.

Closes BLD-460
@0xFirekeeper 0xFirekeeper requested review from a team as code owners November 19, 2025 23:54
@linear
Copy link

linear bot commented Nov 19, 2025

@changeset-bot
Copy link

changeset-bot bot commented Nov 19, 2025

⚠️ No Changeset found

Latest commit: 4f21e90

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link

vercel bot commented Nov 19, 2025

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

Project Deployment Preview Comments Updated (UTC)
thirdweb-www Ready Ready Preview Comment Nov 20, 2025 0:28am
4 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
docs-v2 Skipped Skipped Nov 20, 2025 0:28am
nebula Skipped Skipped Nov 20, 2025 0:28am
thirdweb_playground Skipped Skipped Nov 20, 2025 0:28am
wallet-ui Skipped Skipped Nov 20, 2025 0:28am

@graphite-app
Copy link
Contributor

graphite-app bot commented Nov 19, 2025

How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • merge-queue - adds this PR to the back of the merge queue
  • hotfix - for urgent hot fixes, skip the queue and merge this PR next

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

@github-actions github-actions bot added the Dashboard Involves changes to the Dashboard. label Nov 19, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 19, 2025

Walkthrough

Adds gasUnits and avgGasPrice to analytics types and aggregation, introduces a new GasMetricsChartCard React component for gas-related charts, and replaces SponsoredTransactionsChartCard with GasMetricsChartCard in the Account Abstraction analytics layout.

Changes

Cohort / File(s) Summary
Types
apps/dashboard/src/@/types/analytics.ts
Added gasUnits: number and avgGasPrice: number to UserOpStats.
API aggregation
apps/dashboard/src/@/api/analytics.ts
getAggregateUserOpUsage accumulator now includes gasUnits, gasPriceSum, and gasPriceCount; computes avgGasPrice = gasPriceSum / gasPriceCount and returns narrowed UserOpStats (date, failed, sponsoredUsd, successful, gasUnits, avgGasPrice).
New UI component
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/AccountAbstractionAnalytics/GasMetricsChartCard.tsx
Added new client-side React component that renders a per-chain stacked bar chart with metric toggles (sponsoredTransactions, gasUnits, avgGasPrice, costPerGasUnit), top-chains + "Others" grouping, tooltips, CSV export, and empty-state docs.
Analytics composition
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/aa-analytics.tsx
Replaced import and JSX usage of SponsoredTransactionsChartCard with GasMetricsChartCard, passing existing userOpStats and isPending props.
Story / test data
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/AccountAbstractionAnalytics/storyUtils.ts
Story generator now populates gasUnits and avgGasPrice on synthetic UserOpStats entries for demo/testing.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Browser as Browser (GasMetricsChartCard)
  participant Server as Server (getAggregateUserOpUsage)
  participant Reducer as Aggregation Reducer
  participant Chart as Chart Renderer

  Browser->>Server: request aggregated userOpStats
  Server->>Reducer: filter production chains, reduce per-day
  note right of Reducer `#F9F5E7`: accumulate:\n- successful / failed / sponsoredUsd\n- gasUnits\n- gasPriceSum, gasPriceCount
  Reducer-->>Server: return UserOpStats[] (avgGasPrice computed)
  Server-->>Browser: respond with aggregated UserOpStats[]
  Browser->>Browser: transform per-day, select top chains, group "Others", build CSV
  Browser->>Chart: render stacked bars, tooltips, metric toggles
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Check accumulator typing in getAggregateUserOpUsage and division-by-zero guard for avgGasPrice.
  • Verify UserOpStats additions are used consistently across the new chart and story utilities.
  • Validate GasMetricsChartCard: top-chains selection, "Others" aggregation, metric value formatting (wei↔gwei, currency), and CSV output columns/rows.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'Add gas metrics chart to account abstraction analytics' accurately and concisely summarizes the main change: introducing a new chart component to visualize gas metrics in the analytics page.
Description check ✅ Passed The PR description addresses the template format, includes a comprehensive summary of changes, references the linked issue (BLD-460), and provides detailed information about modifications to types, functions, and components.
Linked Issues check ✅ Passed The PR successfully implements the requirements from BLD-460 by adding gasUnits and avgGasPrice fields to track gas consumption, creating GasMetricsChartCard to visualize these metrics, and integrating it into the AA analytics page.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing gas metrics visualization for AA analytics as specified in BLD-460; no unrelated modifications or feature additions are present in the changeset.
✨ 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 firekeeper/gas-analytics

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

@codecov
Copy link

codecov bot commented Nov 19, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 54.83%. Comparing base (b0e69b8) to head (4f21e90).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #8442   +/-   ##
=======================================
  Coverage   54.83%   54.83%           
=======================================
  Files         919      919           
  Lines       60868    60868           
  Branches     4141     4141           
=======================================
  Hits        33375    33375           
  Misses      27391    27391           
  Partials      102      102           
Flag Coverage Δ
packages 54.83% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@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: 1

🧹 Nitpick comments (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/AccountAbstractionAnalytics/GasMetricsChartCard.tsx (1)

145-148: Consider more intuitive formatting for cost per gas unit.

The micro-USD formatting ($0.0001µ) may be confusing for users. Consider alternative representations:

  • Scientific notation: $1.00e-7
  • Milli-USD with more decimals: $0.0001 (mUSD)
  • Simply higher precision USD: $0.00000010
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b0e69b8 and a93ef8f.

📒 Files selected for processing (4)
  • apps/dashboard/src/@/api/analytics.ts (2 hunks)
  • apps/dashboard/src/@/types/analytics.ts (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/AccountAbstractionAnalytics/GasMetricsChartCard.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/aa-analytics.tsx (2 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-05-29T00:46:09.063Z
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 7188
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-count.tsx:15-15
Timestamp: 2025-05-29T00:46:09.063Z
Learning: In the accounts component at apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-count.tsx, the 3-column grid layout (md:grid-cols-3) is intentionally maintained even when rendering only one StatCard, as part of the design structure for this component.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/AccountAbstractionAnalytics/GasMetricsChartCard.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/aa-analytics.tsx
📚 Learning: 2025-07-10T10:18:33.238Z
Learnt from: arcoraven
Repo: thirdweb-dev/js PR: 7505
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/analytics/components/WebhookAnalyticsCharts.tsx:186-204
Timestamp: 2025-07-10T10:18:33.238Z
Learning: The ThirdwebBarChart component in apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/analytics/components/WebhookAnalyticsCharts.tsx does not accept standard accessibility props like `aria-label` and `role` in its TypeScript interface, causing compilation errors when added.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/AccountAbstractionAnalytics/GasMetricsChartCard.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/aa-analytics.tsx
📚 Learning: 2025-06-10T00:50:20.795Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:153-226
Timestamp: 2025-06-10T00:50:20.795Z
Learning: In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx, the updateStatus function correctly expects a complete MultiStepState["status"] object. For pending states, { type: "pending" } is the entire status object. For error states, { type: "error", message: React.ReactNode } is the entire status object. The current code incorrectly spreads the entire step object instead of passing just the status object.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/AccountAbstractionAnalytics/GasMetricsChartCard.tsx
🧬 Code graph analysis (3)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/AccountAbstractionAnalytics/GasMetricsChartCard.tsx (3)
apps/dashboard/src/@/types/analytics.ts (1)
  • UserOpStats (21-29)
apps/dashboard/src/@/components/blocks/charts/bar-chart.tsx (1)
  • ThirdwebBarChart (49-125)
apps/dashboard/src/@/components/blocks/ExportToCSVButton.tsx (1)
  • ExportToCSVButton (9-57)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/aa-analytics.tsx (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/AccountAbstractionAnalytics/GasMetricsChartCard.tsx (1)
  • GasMetricsChartCard (25-237)
apps/dashboard/src/@/api/analytics.ts (1)
apps/dashboard/src/@/types/analytics.ts (1)
  • UserOpStats (21-29)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Unit Tests
  • GitHub Check: Size
  • GitHub Check: Build Packages
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: Lint Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (13)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/aa-analytics.tsx (2)

14-14: LGTM!

The import follows the existing pattern and is correctly placed with other chart card imports.


109-112: LGTM!

The GasMetricsChartCard is correctly integrated with the appropriate props and follows the established pattern for chart cards in this layout.

apps/dashboard/src/@/types/analytics.ts (1)

26-27: LGTM!

The new fields are properly typed and consistently integrated into the UserOpStats interface.

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/AccountAbstractionAnalytics/GasMetricsChartCard.tsx (7)

1-23: LGTM!

Imports and type definitions are well-structured and appropriate for the component's functionality.


25-32: LGTM!

Component props and state initialization are well-defined and sensible.


34-111: LGTM!

The chart data processing logic is well-structured with proper safeguards:

  • Division by zero is handled in the costPerGasUnit calculation (Line 53)
  • Top chains aggregation with "Others" category is implemented correctly
  • useMemo dependencies are appropriate

113-121: LGTM!

The disableActions logic correctly handles all edge cases including pending state, empty data, and zero values.


201-212: LGTM!

The CSV export logic correctly formats the data with proper headers and row values.


239-277: LGTM!

The empty state component provides helpful guidance with documentation links across multiple platforms.


134-138: Verify with backend API documentation that avgGasPrice returns wei units.

The code contains an explicit comment stating the conversion assumption ("Convert from wei to Gwei" at line 136), and the division by 1e9 is mathematically correct for wei→Gwei conversion. However, the backend API endpoint (v2/bundler/usage) is external and not present in this repository, so the unit assumption cannot be verified from the codebase. Confirm with your backend service documentation or team that avgGasPrice is indeed returned in wei units.

apps/dashboard/src/@/api/analytics.ts (3)

330-334: LGTM!

The average gas price calculation is correct with proper division-by-zero protection.


337-344: LGTM!

The return statement correctly excludes internal accumulator fields and returns only the public UserOpStats interface fields.


312-315: Verify if avgGasPrice from backend includes failed transactions.

The backend provides a pre-calculated avgGasPrice with each UserOpStats record (line 268, fetched from API). The frontend then re-weights these values at line 314:

acc.gasPriceSum += curr.avgGasPrice * curr.successful;
acc.gasPriceCount += curr.successful;

This assumes each backend avgGasPrice represents only successful transactions. If the backend includes both successful and failed transactions in its calculation, the weight should be (curr.successful + curr.failed) instead of curr.successful alone.

Check the backend API response format or documentation to confirm the scope of avgGasPrice—does it aggregate gas prices for all sponsored transactions or only successful ones?

@github-actions
Copy link
Contributor

github-actions bot commented Nov 20, 2025

size-limit report 📦

Path Size
@thirdweb-dev/nexus (esm) 104.88 KB (0%)
@thirdweb-dev/nexus (cjs) 316.6 KB (0%)

Added 'sponsoredTransactions' as a metric type to GasMetricsChartCard and removed the separate SponsoredTransactionsChartCard from aa-analytics.tsx. This simplifies the analytics UI by consolidating related metrics into a single chart component.
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground November 20, 2025 00:18 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui November 20, 2025 00:18 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 November 20, 2025 00:18 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula November 20, 2025 00:18 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui November 20, 2025 00:21 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula November 20, 2025 00:21 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 November 20, 2025 00:21 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground November 20, 2025 00:21 Inactive
Copy link
Contributor

@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: 1

♻️ Duplicate comments (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/AccountAbstractionAnalytics/GasMetricsChartCard.tsx (1)

246-252: Fix type inconsistency in tooltip formatter.

As previously noted, ChartData defines time: string (line 20), but line 248 casts it as number. This type mismatch should be corrected.

Apply the fix from the previous review:

       toolTipLabelFormatter={(_v, item) => {
         if (Array.isArray(item)) {
-          const time = item[0].payload.time as number;
+          const time = item[0].payload.time as string;
           return format(new Date(time), "MMM d, yyyy");
         }
         return undefined;
       }}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a93ef8f and 143e9d5.

📒 Files selected for processing (2)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/AccountAbstractionAnalytics/GasMetricsChartCard.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/aa-analytics.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/aa-analytics.tsx
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-05-29T00:46:09.063Z
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 7188
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-count.tsx:15-15
Timestamp: 2025-05-29T00:46:09.063Z
Learning: In the accounts component at apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-count.tsx, the 3-column grid layout (md:grid-cols-3) is intentionally maintained even when rendering only one StatCard, as part of the design structure for this component.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/AccountAbstractionAnalytics/GasMetricsChartCard.tsx
📚 Learning: 2025-07-10T10:18:33.238Z
Learnt from: arcoraven
Repo: thirdweb-dev/js PR: 7505
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/analytics/components/WebhookAnalyticsCharts.tsx:186-204
Timestamp: 2025-07-10T10:18:33.238Z
Learning: The ThirdwebBarChart component in apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/analytics/components/WebhookAnalyticsCharts.tsx does not accept standard accessibility props like `aria-label` and `role` in its TypeScript interface, causing compilation errors when added.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/AccountAbstractionAnalytics/GasMetricsChartCard.tsx
🧬 Code graph analysis (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/AccountAbstractionAnalytics/GasMetricsChartCard.tsx (3)
apps/dashboard/src/@/types/analytics.ts (1)
  • UserOpStats (21-29)
apps/dashboard/src/@/components/blocks/charts/bar-chart.tsx (1)
  • ThirdwebBarChart (49-125)
apps/dashboard/src/@/components/blocks/ExportToCSVButton.tsx (1)
  • ExportToCSVButton (9-57)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: Size
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: Unit Tests
  • GitHub Check: Lint Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/AccountAbstractionAnalytics/GasMetricsChartCard.tsx (2)

144-152: Verify that avgGasPrice is provided in wei.

The formatter divides avgGasPrice by 1,000,000,000 to convert from wei to Gwei. This assumes the backend provides gas prices in wei (the standard smallest unit). If the backend uses a different unit (e.g., Gwei or wei expressed differently), the displayed values will be incorrect.

Confirm the units used in the analytics API response. You can check the backend aggregation logic or add a comment documenting the expected unit:

avgGasPrice: {
  title: "Average Gas Price",
  description: "Average gas price in Gwei for sponsored transactions",
  fileName: "Average Gas Price",
  formatter: (value: number) => {
    // Backend provides avgGasPrice in wei; convert to Gwei for display
    const gwei = value / 1_000_000_000;
    return `${formatTickerNumber(gwei)} Gwei`;
  },
},

154-162: Verify micro-USD formatting convention.

The formatter displays cost per gas unit in micro-USD (µUSD) by multiplying by 1,000,000. The notation $${value}µ is unconventional—typically micro-USD is written as µ$ or microUSD.

Consider using a more standard format for clarity:

       formatter: (value: number) => {
         // Show in micro-USD for readability
-        return `$${(value * 1_000_000).toFixed(4)}µ`;
+        return `${(value * 1_000_000).toFixed(4)} µUSD`;
       },

Or add a comment explaining the choice if $...µ is your preferred notation for design consistency.

Comment on lines +53 to +72
if (metricType === "sponsoredTransactions") {
value = stat.successful;
} else if (metricType === "gasUnits") {
value = stat.gasUnits;
} else if (metricType === "avgGasPrice") {
value = stat.avgGasPrice;
} else {
// costPerGasUnit: USD spent per gas unit (helps identify price spike impact)
value = stat.gasUnits > 0 ? stat.sponsoredUsd / stat.gasUnits : 0;
}

// if no data for current day - create new entry
if (!chartData) {
_chartDataMap.set(stat.date, {
time: stat.date,
[chainName]: value,
} as ChartData);
} else {
chartData[chainName] = (chartData[chainName] || 0) + value;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix aggregation logic for average-based metrics.

The accumulation logic at line 71 uses simple addition for all metric types. This is mathematically correct for cumulative metrics (sponsoredTransactions, gasUnits) but incorrect for average-based metrics (avgGasPrice, costPerGasUnit).

When multiple UserOpStats entries share the same date and chain, summing avgGasPrice values produces a meaningless result (e.g., 50 Gwei + 60 Gwei = 110 Gwei is not a valid average). Similarly, summing cost-per-unit ratios distorts the true cost efficiency.

For average metrics, you need weighted aggregation:

  • avgGasPrice: Track total gas price sum and transaction count, then divide
  • costPerGasUnit: Track total sponsoredUsd and total gasUnits, then divide

Consider this approach:

-      let value: number;
-      if (metricType === "sponsoredTransactions") {
-        value = stat.successful;
-      } else if (metricType === "gasUnits") {
-        value = stat.gasUnits;
-      } else if (metricType === "avgGasPrice") {
-        value = stat.avgGasPrice;
-      } else {
-        // costPerGasUnit: USD spent per gas unit (helps identify price spike impact)
-        value = stat.gasUnits > 0 ? stat.sponsoredUsd / stat.gasUnits : 0;
-      }
+      // Store raw components for proper aggregation
+      const isSummableMetric = metricType === "sponsoredTransactions" || metricType === "gasUnits";

Then handle accumulation differently:

       if (!chartData) {
         _chartDataMap.set(stat.date, {
           time: stat.date,
-          [chainName]: value,
+          [chainName]: isSummableMetric ? value : { sum: stat.sponsoredUsd, units: stat.gasUnits, count: stat.successful, gasPriceSum: stat.avgGasPrice * stat.successful },
         } as ChartData);
       } else {
-        chartData[chainName] = (chartData[chainName] || 0) + value;
+        if (isSummableMetric) {
+          chartData[chainName] = (chartData[chainName] || 0) + value;
+        } else {
+          // Accumulate components for weighted average
+          const existing = chartData[chainName] || { sum: 0, units: 0, count: 0, gasPriceSum: 0 };
+          chartData[chainName] = {
+            sum: existing.sum + stat.sponsoredUsd,
+            units: existing.units + stat.gasUnits,
+            count: existing.count + stat.successful,
+            gasPriceSum: existing.gasPriceSum + (stat.avgGasPrice * stat.successful)
+          };
+        }
       }

Then compute final values after aggregation based on metricType.

Alternatively, if the backend guarantees unique date+chain combinations (one UserOpStats per date per chain), document this assumption clearly and add an assertion to catch violations early.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/AccountAbstractionAnalytics/GasMetricsChartCard.tsx
around lines 53 to 72, the code currently adds metric values naively which is
correct for cumulative metrics but wrong for average-based metrics; change the
aggregation to maintain weighted accumulators: for avgGasPrice store and sum
{totalGasPriceSum, txCount} (e.g., totalGasPriceSum += avgGasPrice * successful;
txCount += successful) and for costPerGasUnit store and sum {totalSponsoredUsd,
totalGasUnits} (totalSponsoredUsd += sponsoredUsd; totalGasUnits += gasUnits);
when creating a new chart entry initialize these accumulator fields, when
merging add to them instead of adding a single computed ratio, and after all
data is aggregated compute the final display value per date+chain by dividing
the appropriate totals based on metricType (avgGasPrice =
totalGasPriceSum/txCount, costPerGasUnit = totalSponsoredUsd/totalGasUnits),
with guards for zero counts; if the backend guarantees unique date+chain entries
either document that assumption or add an assertion to catch violations.

Copy link
Contributor

@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: 0

Caution

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

⚠️ Outside diff range comments (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/AccountAbstractionAnalytics/storyUtils.ts (1)

8-8: Fix double negative in comment.

The comment contains "doesn't not have" which is a confusing double negative. It should read "does not have" or "doesn't have" instead.

Apply this diff:

-    // don't use Math.floor because real data doesn't not have integer values
+    // don't use Math.floor because real data does not have integer values
🧹 Nitpick comments (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/AccountAbstractionAnalytics/storyUtils.ts (1)

12-13: Consider using integer values for gasUnits.

In EVM chains, gas units are always integers. The current implementation generates fractional values, which may not accurately reflect real-world data. Consider applying Math.floor() to gasUnits for more realistic stub data.

Apply this diff to generate integer gas units:

-    const gasUnits = Math.random() * 1000000; // Random gas units between 0-1M
+    const gasUnits = Math.floor(Math.random() * 1000000); // Random gas units between 0-1M

Additionally, verify that the consuming code (GasMetricsChartCard and analytics API) correctly handles or formats gasUnits values, especially if it expects integers.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 143e9d5 and 4f21e90.

📒 Files selected for processing (1)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/AccountAbstractionAnalytics/storyUtils.ts (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Size
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/AccountAbstractionAnalytics/storyUtils.ts (1)

21-22: LGTM!

The new gasUnits and avgGasPrice fields are correctly added to the stubbed data object, matching the updated UserOpStats type definition.

@0xFirekeeper 0xFirekeeper merged commit 82ba2b2 into main Nov 20, 2025
23 checks passed
@0xFirekeeper 0xFirekeeper deleted the firekeeper/gas-analytics branch November 20, 2025 00:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Dashboard Involves changes to the Dashboard.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants