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

fix: Update charts to use best te unit for values #527

Merged
merged 16 commits into from
Sep 4, 2024
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/brown-roses-trade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@blobscan/web": patch
---

Updated `DailyAvgBlobFeeChart` and `DailyAvgBlobGasPriceChart` to use the best unit for values
17 changes: 8 additions & 9 deletions apps/web/src/components/Charts/Block/DailyAvgBlobFeeChart.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import type { FC } from "react";
import { useMemo } from "react";
import type { EChartOption } from "echarts";

import { convertWei } from "@blobscan/eth-units";

import { ChartCard } from "~/components/Cards/ChartCard";
import { useScaledWeiAmounts } from "~/hooks/useScaledWeiAmounts";
import type { DailyBlockStats } from "~/types";
import { formatNumber } from "~/utils";
import { buildTimeSeriesOptions } from "~/utils";
Expand All @@ -16,23 +14,24 @@ export type DailyAvgBlobFeeChartProps = {

export const DailyAvgBlobFeeChart: FC<Partial<DailyAvgBlobFeeChartProps>> =
function ({ days, avgBlobFees }) {
const formattedAvgBlobFees = useMemo(
() => avgBlobFees?.map((fee) => convertWei(fee)),
[avgBlobFees]
);
const { scaledValues, unit } = useScaledWeiAmounts(avgBlobFees);

const options: EChartOption<EChartOption.SeriesBar> = {
...buildTimeSeriesOptions({
dates: days,
axisFormatters: {
yAxisTooltip: (value) => `${formatNumber(value)} Gwei`,
yAxisTooltip: (value) => `${formatNumber(value)} ${unit}`,
yAxisLabel: (value) => `${formatNumber(value)} ${unit}`,
},
yUnit: "ethereum",
}),
grid: {
containLabel: true,
},
series: [
{
name: "Avg. Blob Fees",
data: formattedAvgBlobFees,
data: scaledValues,
type: "bar",
},
],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import type { FC } from "react";
import { useMemo } from "react";
import type { EChartOption } from "echarts";

import { convertWei } from "@blobscan/eth-units";

import { ChartCard } from "~/components/Cards/ChartCard";
import { useScaledWeiAmounts } from "~/hooks/useScaledWeiAmounts";
import type { DailyBlockStats } from "~/types";
import { buildTimeSeriesOptions, formatNumber } from "~/utils";

Expand All @@ -16,23 +14,24 @@ export type DailyAvgBlobGasPriceChartProps = {
export const DailyAvgBlobGasPriceChart: FC<
Partial<DailyAvgBlobGasPriceChartProps>
> = function ({ days, avgBlobGasPrices }) {
const formattedAvgBlobGasPrices = useMemo(
() => avgBlobGasPrices?.map((price) => convertWei(price)),
[avgBlobGasPrices]
);
const { scaledValues, unit } = useScaledWeiAmounts(avgBlobGasPrices);

const options: EChartOption<EChartOption.SeriesBar> = {
...buildTimeSeriesOptions({
dates: days,
axisFormatters: {
yAxisTooltip: (value) => `${formatNumber(value)} Gwei`,
yAxisTooltip: (value) => `${formatNumber(value)} ${unit}`,
yAxisLabel: (value) => `${formatNumber(value)} ${unit}`,
},
yUnit: "ethereum",
}),
grid: {
containLabel: true,
},
series: [
{
name: "Avg. Blob Gas Prices",
data: formattedAvgBlobGasPrices,
data: scaledValues,
type: "bar",
},
],
Expand Down
18 changes: 10 additions & 8 deletions apps/web/src/components/Charts/Block/DailyBlobFeeChart.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import type { FC } from "react";
import { useMemo } from "react";
import type { EChartOption } from "echarts";

import { convertWei } from "@blobscan/eth-units";

import { ChartCard } from "~/components/Cards/ChartCard";
import { useScaledWeiAmounts } from "~/hooks/useScaledWeiAmounts";
import type { DailyBlockStats } from "~/types";
import { formatNumber } from "~/utils";
import { buildTimeSeriesOptions } from "~/utils";
Expand All @@ -16,22 +14,26 @@ export type DailyBlobFeeChartProps = {

export const DailyBlobFeeChart: FC<Partial<DailyBlobFeeChartProps>> =
function ({ days, blobFees }) {
const formattedBlobFees = useMemo(
() => blobFees?.map((fee) => convertWei(BigInt(fee))),
[blobFees]
const { scaledValues, unit } = useScaledWeiAmounts(
blobFees?.map((x) => Number(x))
);

const options: EChartOption<EChartOption.SeriesBar> = {
...buildTimeSeriesOptions({
dates: days,
axisFormatters: {
yAxisTooltip: (value) => `${formatNumber(value)} Gwei`,
yAxisTooltip: (value) => `${formatNumber(value)} ${unit}`,
yAxisLabel: (value) => `${formatNumber(value)} ${unit}`,
},
yUnit: "ethereum",
}),
grid: {
containLabel: true,
},
series: [
{
name: "Blob Fees",
data: formattedBlobFees,
data: scaledValues,
type: "bar",
},
],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import type { FC } from "react";
import type { EChartOption } from "echarts";

import { formatWei } from "@blobscan/eth-units";

import { ChartCard } from "~/components/Cards/ChartCard";
import { useScaledWeiAmounts } from "~/hooks/useScaledWeiAmounts";
import type { DailyTransactionStats } from "~/types";
import { buildTimeSeriesOptions } from "~/utils";
import { buildTimeSeriesOptions, formatNumber } from "~/utils";

export type DailyAvgMaxBlobGasFeeChartProps = {
days: DailyTransactionStats["days"];
Expand All @@ -16,20 +15,25 @@ export type DailyAvgMaxBlobGasFeeChartProps = {
export const DailyAvgMaxBlobGasFeeChart: FC<
Partial<DailyAvgMaxBlobGasFeeChartProps>
> = function ({ days, avgMaxBlobGasFees, compact = false }) {
const { scaledValues, unit } = useScaledWeiAmounts(avgMaxBlobGasFees);

const options: EChartOption<
EChartOption.SeriesBar | EChartOption.SeriesLine
> = {
...buildTimeSeriesOptions({
dates: days,
axisFormatters: {
yAxisTooltip: (value) => formatWei(value),
yAxisLabel: (value) => formatWei(value),
luis-herasme marked this conversation as resolved.
Show resolved Hide resolved
yAxisTooltip: (value) => `${formatNumber(value)} ${unit}`,
yAxisLabel: (value) => `${formatNumber(value)} ${unit}`,
},
}),
grid: {
containLabel: true,
},
series: [
{
name: "Avg. Max Blob Gas Fees",
data: avgMaxBlobGasFees,
data: scaledValues,
type: compact ? "line" : "bar",
smooth: true,
},
Expand Down
26 changes: 26 additions & 0 deletions apps/web/src/hooks/useScaledWeiAmounts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { useMemo } from "react";

import type { EtherUnit } from "@blobscan/eth-units";
import { convertWei, findBestUnit } from "@blobscan/eth-units";

type ScaledWeiAmounts = {
unit: EtherUnit;
scaledValues?: string[];
};

export function useScaledWeiAmounts(arr?: number[], toUnit?: EtherUnit) {
return useMemo<ScaledWeiAmounts>(() => {
if (!arr) {
return {
unit: "wei",
};
}

const unit = toUnit ?? findBestUnit(Math.max(...arr));

return {
unit,
scaledValues: arr.map((item) => convertWei(item, unit)),
};
}, [arr, toUnit]);
}
22 changes: 9 additions & 13 deletions packages/eth-format/index.ts
luis-herasme marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
const ETH_UNITS = { wei: 0, Gwei: 9, ether: 18 };

export type EthAmount = string | number | bigint;
export type EtherUnit = keyof typeof ETH_UNITS;

const compactFormatter = Intl.NumberFormat("en-US", {
notation: "compact",
maximumFractionDigits: 2,
});

const fullwideFormatter = Intl.NumberFormat("fullwide", {
useGrouping: false,
});

/**
* This function converts `wei` to the unit specified by `toUnit`,
* adds commas to the integer part of the converted value,
Expand All @@ -15,10 +20,7 @@ const compactFormatter = Intl.NumberFormat("en-US", {
* This function never converts the provided value to a Number
* ensuring that the full precision of the input is preserved.
*/
export function formatWei(
wei: string | number | bigint,
toUnit: EtherUnit = "Gwei"
): string {
export function formatWei(wei: EthAmount, toUnit: EtherUnit = "Gwei"): string {
const converted = convertWei(wei, toUnit);
const formatted = insertCommas(converted);
return `${formatted} ${toUnit}`;
Expand All @@ -42,10 +44,7 @@ export function prettyFormatWei(
/**
* This function converts `wei` to the unit specified by `toUnit`.
*/
export function convertWei(
wei: string | number | bigint,
toUnit: EtherUnit = "Gwei"
): string {
export function convertWei(wei: EthAmount, toUnit: EtherUnit = "Gwei"): string {
return shiftDecimal(wei, ETH_UNITS[toUnit]);
}

Expand Down Expand Up @@ -74,7 +73,7 @@ export function countIntegerDigits(value: string | number | bigint): number {
return 0; // Return 0 for Infinity, -Infinity, and NaN
}

value = value.toString();
value = fullwideFormatter.format(value as Intl.StringNumericLiteral);

const negative = value.startsWith("-");

Expand All @@ -90,10 +89,7 @@ export function countIntegerDigits(value: string | number | bigint): number {
/**
* This function moves the decimal point to the left by `decimals` places.
*/
export function shiftDecimal(
value: string | number | bigint,
decimals: number
): string {
export function shiftDecimal(value: EthAmount, decimals: number): string {
value = value.toString();

const negative = value.startsWith("-");
Expand Down
32 changes: 30 additions & 2 deletions packages/eth-format/test/eth-units.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,35 @@ describe("countIntegerDigits", () => {
test("handles edge cases", () => {
expect(countIntegerDigits("0.0")).toBe(1);
expect(countIntegerDigits("-0.0")).toBe(1);
expect(countIntegerDigits(".123")).toBe(0);
expect(countIntegerDigits("-.123")).toBe(0);
expect(countIntegerDigits(".123")).toBe(1);
expect(countIntegerDigits("-.123")).toBe(1);
expect(countIntegerDigits("0.123")).toBe(1);
expect(countIntegerDigits("-0.123")).toBe(1);
});

test("scientific notation", () => {
expect(countIntegerDigits("1e+0")).toBe(1);
expect(countIntegerDigits("1e+1")).toBe(2);
expect(countIntegerDigits("1e+2")).toBe(3);

expect(countIntegerDigits("1e-0")).toBe(1);
expect(countIntegerDigits("1e-1")).toBe(1);
expect(countIntegerDigits("1e-2")).toBe(1);

expect(countIntegerDigits("1.23e+0")).toBe(1);
expect(countIntegerDigits("1.23e+1")).toBe(2);
expect(countIntegerDigits("1.23e+2")).toBe(3);

expect(countIntegerDigits("1.23e-0")).toBe(1);
expect(countIntegerDigits("1.23e-1")).toBe(1);
expect(countIntegerDigits("1.23e-2")).toBe(1);

expect(countIntegerDigits("1.23123123123123123123123e+0")).toBe(1);
expect(countIntegerDigits("1.23123123123123123123123e+1")).toBe(2);
expect(countIntegerDigits("1.23123123123123123123123e+2")).toBe(3);

expect(countIntegerDigits("1.23123123123123123123123e+10")).toBe(11);
expect(countIntegerDigits("1.23123123123123123123123e+100")).toBe(101);
expect(countIntegerDigits("1.23123123123123123123123e+200")).toBe(201);
});
});
Loading