From cb0d364c6e3ca94b0cc886bf8f247ddce4c5fb8d Mon Sep 17 00:00:00 2001 From: Stark Sama Date: Sat, 11 Jul 2026 00:07:47 +0800 Subject: [PATCH] Add annualized vault share price rate --- .../components/vault-share-price-chart.tsx | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/features/vault/components/vault-share-price-chart.tsx b/src/features/vault/components/vault-share-price-chart.tsx index 8180f3e3..a198dac7 100644 --- a/src/features/vault/components/vault-share-price-chart.tsx +++ b/src/features/vault/components/vault-share-price-chart.tsx @@ -7,10 +7,13 @@ import { TableContainerWithDescription } from '@/components/common/table-contain import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Spinner } from '@/components/ui/spinner'; import { useChartColors } from '@/constants/chartColors'; +import { useRateLabel } from '@/hooks/useRateLabel'; import { useVaultSharePriceHistory } from '@/hooks/useVaultSharePriceHistory'; +import { useAppSettings } from '@/stores/useAppSettings'; import { type ChartTimeframe, useMarketDetailChartState } from '@/stores/useMarketDetailChartState'; import { formatChartTime } from '@/utils/chart'; import type { SupportedNetworks } from '@/utils/networks'; +import { computeAnnualizedApyFromValueGrowth, formatRateAsPercentage, toDisplayRateFromApy } from '@/utils/rateMath'; import { ChartGradients, ChartTooltipContent, @@ -81,6 +84,15 @@ function formatChangePercent(value: number | null): string { return `${value >= 0 ? '+' : ''}${value.toFixed(4)}%`; } +function formatAnnualizedRate(annualizedApy: number | null, isAprDisplay: boolean): string { + if (annualizedApy === null || !Number.isFinite(annualizedApy)) { + return '--'; + } + + const displayRate = toDisplayRateFromApy(annualizedApy, isAprDisplay); + return formatRateAsPercentage(displayRate, 4); +} + function changeTextColor(value: number | null): string { if (value === null) { return 'text-secondary'; @@ -99,6 +111,8 @@ export function VaultSharePriceChart({ const selectedTimeframe = useMarketDetailChartState((state) => state.selectedTimeframe); const selectedTimeRange = useMarketDetailChartState((state) => state.selectedTimeRange); const setTimeframe = useMarketDetailChartState((state) => state.setTimeframe); + const { isAprDisplay } = useAppSettings(); + const { short: rateLabel } = useRateLabel(); const chartColors = useChartColors(); const { data, isError, isFetching, isLoading } = useVaultSharePriceHistory({ @@ -141,6 +155,15 @@ export function VaultSharePriceChart({ firstPoint && lastPoint && firstPoint.sharePrice > 0 ? ((lastPoint.sharePrice - firstPoint.sharePrice) / firstPoint.sharePrice) * 100 : null; + const periodSeconds = firstPoint && lastPoint ? lastPoint.x - firstPoint.x : 0; + const annualizedApy = + firstPoint && lastPoint + ? computeAnnualizedApyFromValueGrowth({ + currentValue: lastPoint.sharePrice, + pastValue: firstPoint.sharePrice, + periodSeconds, + }) + : null; const yAxisDomain = useMemo(() => getSharePriceDomain(chartData, selectedTimeframe), [chartData, selectedTimeframe]); const isInitialLoading = isLoading; const isUnavailable = data?.isUnsupportedNetwork || isError || (!isInitialLoading && chartData.length < 2); @@ -189,6 +212,10 @@ export function VaultSharePriceChart({

{TIMEFRAME_LABELS[selectedTimeframe]} Change

{formatChangePercent(changePercent)}

+
+

Annualized {rateLabel}

+

{formatAnnualizedRate(annualizedApy, isAprDisplay)}

+