Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
8e35750
feat(pages/resources): get blobscan api data
TylerAPfledderer Apr 21, 2025
25597af
feat(pages/resources): add pectra schedule
TylerAPfledderer Apr 22, 2025
b9158d7
refactor(page/resources): show average blob fee in usd
TylerAPfledderer Apr 28, 2025
a504bc1
fix(useResources): to avg blob fee conversion from wei
TylerAPfledderer Apr 28, 2025
55a27de
Merge remote-tracking branch 'upstream/dev' into feat/dashboard-pectr…
TylerAPfledderer May 7, 2025
d31aa0e
add mock data for blobscanOverallStats
pettinarip May 8, 2025
040d7bb
refactor(useResources): simplify formatSmallUSD
TylerAPfledderer May 8, 2025
eba75bf
refactor(useResources): add countdown for scaling upgrade
TylerAPfledderer May 9, 2025
9771acf
refactor(useResources): set link for Pectra page
TylerAPfledderer May 9, 2025
472b762
Merge remote-tracking branch 'upstream/dev' into feat/dashboard-pectr…
TylerAPfledderer May 18, 2025
15408bb
Merge remote-tracking branch 'upstream/dev' into feat/dashboard-pectr…
TylerAPfledderer May 23, 2025
bf9423a
refactor(useResources): update label for latest scaling upgrade
TylerAPfledderer May 23, 2025
c35f66d
Merge branch 'dev' into pr/15324
wackerow Oct 31, 2025
2aaa16f
refactor: extract client-side component
wackerow Oct 31, 2025
69de9e1
fix: blobstats fetch data struct
wackerow Oct 31, 2025
195836c
refactor: use humanize-duration
wackerow Oct 31, 2025
1dd199b
patch: typo
wackerow Oct 31, 2025
bbfe6eb
fix(ui): layout padding, use BigNumber
wackerow Nov 4, 2025
edd4626
i18n: extract strings
wackerow Nov 4, 2025
2a924eb
i18n: localize humanizeDuration options
wackerow Nov 5, 2025
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
21 changes: 16 additions & 5 deletions app/[locale]/resources/_components/resources.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,24 @@ import { useTranslation } from "@/hooks/useTranslation"
import heroImg from "@/public/images/heroes/guides-hub-hero.jpg"
interface ResourcesPageProps {
txCostsMedianUsd: MetricReturnData
totalBlobs: string
avgBlobFee: number
}

const EVENT_CATEGORY = "dashboard"

const ResourcesPage = ({ txCostsMedianUsd }: ResourcesPageProps) => {
const ResourcesPage = ({
txCostsMedianUsd,
totalBlobs,
avgBlobFee,
}: ResourcesPageProps) => {
const { t } = useTranslation("page-resources")
const resourceSections = useResources({ txCostsMedianUsd })

const resourceSections = useResources({
txCostsMedianUsd,
totalBlobs,
avgBlobFee,
})
const activeSection = useActiveHash(
resourceSections.map(({ key }) => key),
"0% 0% -70% 0%"
Expand Down Expand Up @@ -114,22 +125,22 @@ const ResourcesPage = ({ txCostsMedianUsd }: ResourcesPageProps) => {
{boxes.map(({ title, metric, items, className }) => (
<div
className={cn(
"overflow-hidden rounded-2xl border shadow-lg",
"grid grid-rows-[min-content] overflow-hidden rounded-2xl border shadow-lg",
className
)}
key={title}
>
<div className="border-b bg-[#ffffff] px-6 py-4 font-bold dark:bg-[#171717]">
{title}
</div>
<div className="h-full bg-background bg-gradient-to-br from-white to-primary/10 px-2 py-6 dark:from-transparent dark:to-primary/10">
<Stack className="gap-2 bg-background bg-gradient-to-br from-white to-primary/10 px-2 py-6 dark:from-transparent dark:to-primary/10">
{metric && metric}
<ResourcesContainer>
{items.map((item) => (
<ResourceItem item={item} key={item.title} />
))}
</ResourcesContainer>
</div>
</Stack>
</div>
))}
</div>
Expand Down
22 changes: 19 additions & 3 deletions app/[locale]/resources/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,17 @@ import { BASE_TIME_UNIT } from "@/lib/constants"

import ResourcesPage from "./_components/resources"

import { fetchBlobscanStats } from "@/lib/api/fetchBlobscanStats"
import { fetchGrowThePie } from "@/lib/api/fetchGrowThePie"

// In seconds
const REVALIDATE_TIME = BASE_TIME_UNIT * 1

const loadData = dataLoader(
[["growThePieData", fetchGrowThePie]],
[
["growThePieData", fetchGrowThePie],
["blobscanOverallStats", fetchBlobscanStats],
],
REVALIDATE_TIME * 1000
)

Expand All @@ -38,12 +42,24 @@ const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => {
const messages = pick(allMessages, requiredNamespaces)

// Load data
const [growThePieData] = await loadData()
const [growThePieData, blobscanOverallStats] = await loadData()

const { txCostsMedianUsd } = growThePieData

const { totalBlobs, avgBlobFee } = blobscanOverallStats

const formattedTotalBlobs = new Intl.NumberFormat(undefined, {
notation: "compact",
maximumFractionDigits: 1,
}).format(totalBlobs)

return (
<I18nProvider locale={locale} messages={messages}>
<ResourcesPage txCostsMedianUsd={txCostsMedianUsd} />
<ResourcesPage
txCostsMedianUsd={txCostsMedianUsd}
totalBlobs={formattedTotalBlobs}
avgBlobFee={avgBlobFee}
/>
</I18nProvider>
)
}
Expand Down
40 changes: 37 additions & 3 deletions src/components/Resources/useResources.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import RadialChart from "../RadialChart"

import type { DashboardBox, DashboardSection } from "./types"

import { useEthPrice } from "@/hooks/useEthPrice"
import { useTranslation } from "@/hooks/useTranslation"
import IconBeaconchain from "@/public/images/resources/beaconcha-in.png"
import IconBlobsGuru from "@/public/images/resources/blobsguru.png"
Expand Down Expand Up @@ -58,11 +59,22 @@ const formatSmallUSD = (value: number, locale: string): string =>
maximumSignificantDigits: 2,
}).format(value)

export const useResources = ({ txCostsMedianUsd }): DashboardSection[] => {
export const useResources = ({
txCostsMedianUsd,
totalBlobs,
avgBlobFee,
}): DashboardSection[] => {
const { t } = useTranslation("page-resources")
const locale = useLocale()
const localeForNumberFormat = getLocaleForNumberFormat(locale! as Lang)

const ethPrice = useEthPrice()
const avgBlobFeeUsd = formatSmallUSD(
// Converting value from gwei to USD
avgBlobFee * 1e-9 * ethPrice,
localeForNumberFormat
).replace(/[A-Za-z]$/, "")

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I double-checked in a converter, and this value should be correct, returning $2.4 here.

Copy link
Member

Choose a reason for hiding this comment

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

Hey @TylerAPfledderer I think that the problem is that avgBlobFee is in wei, not gwei. That is why we get it in billions. So, if we do

Suggested change
const ethPrice = useEthPrice()
const avgBlobFeeUsd = formatSmallUSD(
// Converting value from gwei to USD
avgBlobFee * 1e-9 * ethPrice,
localeForNumberFormat
).replace(/[A-Za-z]$/, "")
const ethPrice = useEthPrice()
const avgBlobFeeUsd = formatSmallUSD(
// Converting value from wei to USD
avgBlobFee * 1e-18 * ethPrice,
localeForNumberFormat
)

we shouldn't need to replace anything.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@pettinarip ah, that did it! Pushed the change 😄

const medianTxCost =
"error" in txCostsMedianUsd
? { error: txCostsMedianUsd.error }
Expand Down Expand Up @@ -343,7 +355,14 @@ export const useResources = ({ txCostsMedianUsd }): DashboardSection[] => {
const scalingBoxes: DashboardBox[] = [
{
title: t("page-resources-roadmap-title"),
// TODO: Add metric
metric: (
<div className="grid place-items-center py-5">
<div className="text-sm">Next upgrade</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

@TylerAPfledderer from my end we just need to change this details to "Latest upgrade" because it's live now

<div className="text-5xl font-bold">Pectra</div>
{/* TODO: Convert date to a countdown */}
<div className="text-xl font-bold text-body-medium">07 May 2025</div>
Copy link
Contributor Author

@TylerAPfledderer TylerAPfledderer Apr 28, 2025

Choose a reason for hiding this comment

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

Any suggestions on which way to go here? Kinda already doing an approach in useResources for "Time to next block". Use that approach for this?

There is also something more robust like the react-countdown component if this is to used again for something else.

</div>
),
items: [
{
title: "Ethereum Roadmap",
Expand All @@ -355,7 +374,22 @@ export const useResources = ({ txCostsMedianUsd }): DashboardSection[] => {
},
{
title: t("page-resources-blobs-title"),
// TODO: Add metric
metric: (
<div className="flex [&>*]:grid [&>*]:flex-1 [&>*]:place-items-center">
<div>
<div className="text-[42px] font-bold leading-2xs">
{totalBlobs}
</div>
<div className="text-sm text-body-medium">Total blobs</div>
</div>
<div>
<div className="text-[42px] font-bold leading-2xs">
{avgBlobFeeUsd}
</div>
<div className="text-sm text-body-medium">Average Blob Fee</div>
</div>
</div>
),
items: [
{
title: "Blob Scan",
Expand Down
57 changes: 57 additions & 0 deletions src/lib/api/fetchBlobscanStats.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
type BlobscanOverallStats = {
avgBlobAsCalldataFee: number
avgBlobFee: number
avgBlobGasPrice: number
avgMaxBlobGasFee: number
totalBlobGasUsed: string
totalBlobAsCalldataGasUsed: string
totalBlobFee: string
totalBlobAsCalldataFee: string
totalBlobs: number
totalBlobSize: string
totalBlocks: number
totalTransactions: number
totalUniqueBlobs: number
totalUniqueReceivers: number
totalUniqueSenders: number
updatedAt: string
}

type BlobscanOverallStatsErr = {
message: string
code: string
issues: [message: string]
}

/**
* Fetch the overall stats from Blobscan
*
* @see https://api.blobscan.com/#/stats/stats-getOverallStats
*
*/
export const fetchBlobscanStats = async () => {
const data = await fetch("https://api.blobscan.com/stats/overall").then(
(res) => responseHandler(res)
)

return data
}

type BlobscanResponse =
| (Omit<Response, "json"> & {
json: () => BlobscanOverallStats | PromiseLike<BlobscanOverallStats>
})
| (Omit<Response, "json"> & {
json: () => BlobscanOverallStatsErr | PromiseLike<BlobscanOverallStatsErr>
})

const responseHandler = async (response: Response) => {
const res = await (response as BlobscanResponse).json()

if ("message" in res) {
throw Error(`Code ${res.code}: Failed to fetch Blobscan Overall Stats`, {
cause: res.message,
})
}
return res
}
Loading