Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update home charts #732

Merged
merged 7 commits into from
Mar 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/mean-rivers-study.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@blobscan/api": minor
---

Added stat endpoint to return blobs per rollup data.
5 changes: 5 additions & 0 deletions .changeset/ninety-zebras-attack.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@blobscan/web": minor
---

Updated Home page charts: increase to 30 days the 'Blob Gas Price Expenditure' chart and replace Daily Transactions chart by 'Blobs per rollup'
7 changes: 4 additions & 3 deletions apps/web/src/components/Cards/ChartCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ type ChartCardProps = {

function getSeriesDataState(series: EChartOption.Series[] | undefined) {
return {
isLoading: series
? series.some(({ data }) => data === undefined || data === null)
: true,
isLoading:
series && series.length > 0
? series.some(({ data }) => data === undefined || data === null)
: true,
isEmpty: series ? series.some(({ data }) => data?.length === 0) : false,
};
}
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/components/Charts/Blob/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./DailyBlobsChart";
export * from "./DailyBlobSizeChart";
export * from "../DailyBlobsPerRollupChart";
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ import { buildTimeSeriesOptions } from "~/utils";
export type DailyAvgBlobGasPriceChartProps = {
days: DailyBlockStats["days"];
avgBlobGasPrices: DailyBlockStats["avgBlobGasPrices"];
opts?: EChartOption;
};

export const DailyAvgBlobGasPriceChart: FC<
Partial<DailyAvgBlobGasPriceChartProps>
> = function ({ days, avgBlobGasPrices }) {
> = function ({ days, avgBlobGasPrices, opts = {} }) {
const { unit } = useScaledWeiAmounts(avgBlobGasPrices);

const options: EChartOption<EChartOption.Series> = {
Expand All @@ -35,6 +36,7 @@ export const DailyAvgBlobGasPriceChart: FC<
},
],
animationEasing: "cubicOut",
...opts,
};

return (
Expand Down
40 changes: 40 additions & 0 deletions apps/web/src/components/Charts/DailyBlobsPerRollupChart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { FC } from "react";
import type { EChartOption } from "echarts";

import { ChartCard } from "~/components/Cards/ChartCard";
import type { Rollup, RollupDailyStats } from "~/types";
import { buildTimeSeriesOptions, capitalize, formatNumber } from "~/utils";

export type DailyRollupChartProps = {
days: RollupDailyStats["days"];
blobsPerRollup: RollupDailyStats["blobsPerRollup"];
};

export const DailyBlobsPerRollupChart: FC<Partial<DailyRollupChartProps>> =
function ({ days, blobsPerRollup }) {
const rollupNames =
blobsPerRollup && blobsPerRollup[0]
? (Object.keys(blobsPerRollup[0]) as Rollup[])
: [];

const options: EChartOption<EChartOption.SeriesBar> = {
...buildTimeSeriesOptions({
dates: days,
axisFormatters: {
yAxisTooltip: (value) => formatNumber(value),
},
}),
series: rollupNames.map((rollup) => ({
name: capitalize(rollup),
type: "bar",
stack: "total",
data: blobsPerRollup
? blobsPerRollup.map((dayEntry) => dayEntry[rollup as Rollup])
: undefined,
})),
animationEasing: "cubicOut",
toolbox: { show: false },
};

return <ChartCard title="Rollup Blob Usage" size="sm" options={options} />;
};
34 changes: 13 additions & 21 deletions apps/web/src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import { MetricCard } from "~/components/Cards/MetricCard";
import { BlobCard } from "~/components/Cards/SurfaceCards/BlobCard";
import { BlobTransactionCard } from "~/components/Cards/SurfaceCards/BlobTransactionCard";
import { BlockCard } from "~/components/Cards/SurfaceCards/BlockCard";
import { DailyBlobGasComparisonChart } from "~/components/Charts/Block";
import { DailyTransactionsChart } from "~/components/Charts/Transaction";
import { DailyBlobsPerRollupChart } from "~/components/Charts/Blob";
import { DailyAvgBlobGasPriceChart } from "~/components/Charts/Block";
import { Link } from "~/components/Link";
import { SearchInput } from "~/components/SearchInput";
import { SlidableList } from "~/components/SlidableList";
Expand All @@ -26,7 +26,6 @@ import {
} from "~/utils";

const LATEST_ITEMS_LENGTH = 5;
const DAILY_STATS_TIMEFRAME = "15d";

const CARD_HEIGHT = "sm:h-28";

Expand All @@ -46,14 +45,15 @@ const Home: NextPage = () => {
});
const { data: rawOverallStats, error: overallStatsErr } =
api.stats.getOverallStats.useQuery();
const { data: dailyTxStats, error: dailyTxStatsErr } =
api.stats.getTransactionDailyStats.useQuery({
timeFrame: DAILY_STATS_TIMEFRAME,
});
const { data: dailyBlockStats, error: dailyBlockStatsErr } =
api.stats.getBlockDailyStats.useQuery({
timeFrame: DAILY_STATS_TIMEFRAME,
timeFrame: "30d",
});
const { data: dailyRollupStats, error: dailyRollupStatsErr } =
api.stats.getRollupDailyStats.useQuery({
timeFrame: "90d",
});

const { blocks, transactions, blobs } = useMemo(() => {
if (!rawBlocksData) {
return { blocks: [], transactions: [], blobs: [] };
Expand Down Expand Up @@ -87,8 +87,8 @@ const Home: NextPage = () => {
const error =
latestBlocksError ||
overallStatsErr ||
dailyTxStatsErr ||
dailyBlockStatsErr;
dailyBlockStatsErr ||
dailyRollupStatsErr;

if (error) {
return (
Expand Down Expand Up @@ -116,12 +116,9 @@ const Home: NextPage = () => {
<div className="flex w-full flex-col gap-8 sm:gap-10">
<div className="grid grid-cols-2 space-y-6 lg:grid-cols-10 lg:gap-6 lg:space-y-0">
<div className="col-span-2 sm:col-span-4">
<DailyBlobGasComparisonChart
<DailyAvgBlobGasPriceChart
days={dailyBlockStats?.days}
blobAsCalldataGasUsed={
dailyBlockStats?.totalBlobAsCalldataGasUsed
}
blobGasUsed={dailyBlockStats?.totalBlobGasUsed}
avgBlobGasPrices={dailyBlockStats?.avgBlobGasPrices}
opts={{ toolbox: { show: false } }}
/>
</div>
Expand Down Expand Up @@ -170,12 +167,7 @@ const Home: NextPage = () => {
/>
</div>
<div className="col-span-2 sm:col-span-4">
<DailyTransactionsChart
days={dailyTxStats?.days}
transactions={dailyTxStats?.totalTransactions}
opts={{ toolbox: { show: false } }}
compact
/>
<DailyBlobsPerRollupChart {...dailyRollupStats} />
</div>
</div>
<div className="grid grid-cols-1 items-stretch justify-stretch gap-6 lg:grid-cols-3">
Expand Down
2 changes: 2 additions & 0 deletions apps/web/src/types/routers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,5 @@ export type DailyTransactionStats =
export type DailyStats = RouterOutputs["stats"]["getDailyStats"][number];

export type OverallStats = RouterOutputs["stats"]["getOverallStats"];

export type RollupDailyStats = RouterOutputs["stats"]["getRollupDailyStats"];
3 changes: 3 additions & 0 deletions packages/api/src/middlewares/withTimeFrame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const TIME_FRAMES = z.enum([
"7d",
"15d",
"30d",
"90d",
"180d",
"360d",
"All",
Expand All @@ -26,6 +27,8 @@ function getTimeFrameIntervals(timeFrame: TimeFrame): TimeInterval {
case "7d":
case "15d":
case "30d":
case "90d":
case "180d":
case "360d":
default: {
const day = parseInt(timeFrame.split("d")[0] ?? "1d");
Expand Down
70 changes: 70 additions & 0 deletions packages/api/src/routers/stats/getRollupDailyStats.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { z } from "@blobscan/zod";

import {
withTimeFrame,
withTimeFrameSchema,
} from "../../middlewares/withTimeFrame";
import { publicProcedure } from "../../procedures";
import { rollupSchema } from "../../utils";

const inputSchema = withTimeFrameSchema;

export const outputSchema = z.object({
days: z.array(z.string()),
blobsPerRollup: z.array(z.record(rollupSchema, z.number())),
});

type OutputSchema = z.infer<typeof outputSchema>;

export const getRollupDailyStats = publicProcedure
.input(inputSchema)
.use(withTimeFrame)
.output(outputSchema)
.query(async ({ ctx: { prisma, timeFrame } }) => {
const stats = await prisma.dailyStats.groupBy({
by: ["day", "rollup"],
_sum: {
totalBlobs: true,
},
where: {
AND: [
{
day: {
gte: timeFrame.initial.toDate(),
lte: timeFrame.final.toDate(),
},
},
{
category: null,
},
],
},
orderBy: {
day: "asc",
},
});

if (stats.length === 0) {
return { days: [], blobsPerRollup: [] };
}

const uniqueDays = Array.from(
new Set(stats.map((item) => item.day.toISOString()))
);

const formattedStats: OutputSchema = {
days: uniqueDays,
blobsPerRollup: uniqueDays.map((day) =>
stats.reduce((acc, item) => {
if (item.day.toISOString() === day && item.rollup) {
const lowercaseRollup = item.rollup.toLowerCase();
acc[lowercaseRollup] =
(acc[lowercaseRollup] ?? 0) + (item._sum.totalBlobs ?? 0);
}
return acc;
}, {} as { [key: string]: number })
),
};

return formattedStats;
});

Check warning on line 70 in packages/api/src/routers/stats/getRollupDailyStats.ts

View check run for this annotation

Codecov / codecov/patch

packages/api/src/routers/stats/getRollupDailyStats.ts#L24-L70

Added lines #L24 - L70 were not covered by tests
2 changes: 2 additions & 0 deletions packages/api/src/routers/stats/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { getBlockDailyStats } from "./getBlockDailyStats";
import { getBlockOverallStats } from "./getBlockOverallStats";
import { getDailyStats } from "./getDailyStats";
import { getOverallStats } from "./getOverallStats";
import { getRollupDailyStats } from "./getRollupDailyStats";
import { getTransactionDailyStats } from "./getTransactionDailyStats";
import { getTransactionOverallStats } from "./getTransactionOverallStats";

Expand All @@ -17,4 +18,5 @@ export const statsRouter = t.router({
getBlockOverallStats,
getTransactionDailyStats,
getTransactionOverallStats,
getRollupDailyStats,
});
Loading