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/continue develop scrvusd #610

Draft
wants to merge 23 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
2c6eee0
styling: fix input wallet balance font color
OnlyJousting Jan 8, 2025
7e04efe
Merge branch 'main' into feat/continue-develop-scrvusd
OnlyJousting Jan 8, 2025
e7819d0
set up statistics component
OnlyJousting Jan 9, 2025
a5d796e
set up historical scrvusd yield fetch
OnlyJousting Jan 9, 2025
044c1e3
Merge branch 'main' into feat/continue-develop-scrvusd
OnlyJousting Jan 12, 2025
f101e8d
add scrvusd historical revenue query
OnlyJousting Jan 12, 2025
d41a150
set up scrvusd metrics stack
OnlyJousting Jan 13, 2025
577d7bd
feat: add chart
OnlyJousting Jan 16, 2025
42d63e5
Merge branch 'main' into feat/continue-develop-scrvusd
OnlyJousting Jan 17, 2025
38da516
styling: configure MuiSelect
OnlyJousting Jan 19, 2025
30e8347
set up TimeOption
OnlyJousting Jan 19, 2025
67dfd0b
Line chart tooltip
OnlyJousting Jan 19, 2025
3f48ac6
move types
OnlyJousting Jan 20, 2025
9faab04
remove chart animation
OnlyJousting Jan 20, 2025
a50269a
Merge branch 'main' into feat/continue-develop-scrvusd
OnlyJousting Jan 20, 2025
f4aa942
update import paths
OnlyJousting Jan 20, 2025
e30ca22
calc revenue epochs
OnlyJousting Jan 20, 2025
6b07ac7
distributions bar chart
OnlyJousting Jan 22, 2025
6368ddc
Merge branch 'main' into feat/continue-develop-scrvusd
OnlyJousting Jan 22, 2025
fad34b3
chore: resolve merge from main issues
OnlyJousting Jan 22, 2025
e0cd0e8
distributions bar chart tooltip
OnlyJousting Jan 22, 2025
e9fada3
weekly accum revenue stat
OnlyJousting Jan 22, 2025
b9f13dc
Merge branch 'main' into feat/continue-develop-scrvusd
OnlyJousting Jan 22, 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import type { ScrvUsdRevenue } from '@loan/entities/scrvusdRevenue'
import { BarChart, Bar, Cell, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts'
import { formatNumber } from '@ui/utils/utilsFormat'
import { useTheme } from '@mui/material/styles'
import { SizesAndSpaces } from '@ui-kit/themes/design/1_sizes_spaces'
import { toUTC } from '@loan/components/PageCrvUsdStaking/utils'
import DistributionsChartTooltip from './DistributionsChartTooltip'

const { FontSize } = SizesAndSpaces

type RevenueDistributionsBarChartProps = {
data: ScrvUsdRevenue | null
height?: number
}

const RevenueDistributionsBarChart: React.FC<RevenueDistributionsBarChartProps> = ({ data, height = 400 }) => {
const {
design: { Color, Text },
} = useTheme()
const gridLineColor = Color.Neutral[300]
const gridTextColor = Text.TextColors.Tertiary
const barColor = Color.Secondary[500]

return (
<ResponsiveContainer width="100%" height={height} debounce={200}>
<BarChart
width={500}
height={300}
data={data?.epochs ?? []}
margin={{
top: 16,
right: 20,
left: undefined,
bottom: 16,
}}
>
<CartesianGrid stroke={gridLineColor} strokeWidth={0.3} vertical={true} />
<XAxis
dataKey="endDate"
tick={{ fill: gridTextColor, fontSize: FontSize.xs.desktop }}
tickLine={{ fill: gridLineColor, strokeWidth: 0.5 }}
axisLine={false}
minTickGap={20}
allowDataOverflow={false}
tickFormatter={(time) => {
const unix = toUTC(time as string | number) * 1000
return new Intl.DateTimeFormat(undefined, {
day: '2-digit',
month: '2-digit',
year: 'numeric',
}).format(unix)
}}
/>
<YAxis
dataKey="weeklyRevenue"
tick={{ fill: gridTextColor, fontSize: FontSize.xs.desktop }}
tickLine={{ fill: gridLineColor, strokeWidth: 0.5 }}
axisLine={{ opacity: 0.3, strokeWidth: 0.3 }}
tickFormatter={(value) => `$${formatNumber(value, { notation: 'compact' })}`}
/>
<Tooltip content={DistributionsChartTooltip} cursor={{ opacity: 0.3 }} />
<Bar dataKey="weeklyRevenue" label={false} fill={barColor} isAnimationActive={false}>
{data?.epochs.map((entry, index) => <Cell key={`$cell-${index}`} fill={barColor} />)}
</Bar>
</BarChart>
</ResponsiveContainer>
)
}

export default RevenueDistributionsBarChart
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import type { NameType, ValueType } from 'recharts/types/component/DefaultTooltipContent'
import { TooltipProps } from 'recharts'
import { t } from '@lingui/macro'
import { Paper, Stack, Typography } from '@mui/material'
import { SizesAndSpaces } from '@ui-kit/themes/design/1_sizes_spaces'
import { formatNumber } from '@ui/utils/utilsFormat'
import { toUTC } from '@loan/components/PageCrvUsdStaking/utils'

const { Spacing } = SizesAndSpaces

const DataSet = ({ label, value }: { label: string; value: string }) => (
<Stack direction="row" justifyContent="space-between" alignItems="center">
<Typography variant="bodySRegular">{label}</Typography>
<Typography variant="bodySBold">{value}</Typography>
</Stack>
)

const DistributionsChartTooltip = ({ active, payload }: TooltipProps<ValueType, NameType>) => {
if (active && payload && payload.length) {
const { endDate, weeklyRevenue } = payload[0].payload

const unixTimestamp = toUTC(endDate) * 1000
const formattedDate = new Intl.DateTimeFormat(undefined, {
month: 'short',
day: 'numeric',
year: 'numeric',
hour: 'numeric',
minute: '2-digit',
hour12: true,
}).format(unixTimestamp)

return (
<Paper
sx={{
backgroundColor: (theme) => theme.design.Layer[3].Fill,
padding: Spacing.md,
width: '20.5rem',
maxWidth: '100vw',
}}
elevation={2}
>
<Typography variant="bodyMBold">{formattedDate}</Typography>
<Stack
direction="column"
sx={{
marginTop: Spacing.sm,
padding: Spacing.sm,
gap: 1,
backgroundColor: (theme) => theme.design.Layer[2].Fill,
}}
>
<DataSet label={t`Weekly Revenue`} value={`$${formatNumber(weeklyRevenue, { notation: 'compact' })}`} />
</Stack>
</Paper>
)
}

return null
}

export default DistributionsChartTooltip
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import type { NameType, ValueType } from 'recharts/types/component/DefaultTooltipContent'
import { TooltipProps } from 'recharts'
import { t } from '@lingui/macro'
import { Paper, Stack, Typography } from '@mui/material'
import { SizesAndSpaces } from '@ui-kit/themes/design/1_sizes_spaces'
import { useTheme } from '@mui/material/styles'
import { toUTC } from '@loan/components/PageCrvUsdStaking/utils'

const { Spacing } = SizesAndSpaces

const DataSet = ({
label,
value,
lineColor,
dash,
}: {
label: string
value: string
lineColor: string
dash?: string
}) => (
<Stack direction="row" justifyContent="space-between" alignItems="center">
<Stack direction="row" spacing={2} alignItems="center">
<svg width="20" height="2">
<line x1="0" y1="1" x2="20" y2="1" stroke={lineColor} strokeWidth={2} strokeDasharray={dash} />
</svg>
<Typography variant="bodySRegular">{label}</Typography>
</Stack>
<Typography variant="bodySBold">{value}</Typography>
</Stack>
)

const CustomTooltip = ({ active, payload }: TooltipProps<ValueType, NameType>) => {
const {
design: { Color },
} = useTheme()

if (active && payload && payload.length) {
const { timestamp, proj_apy, proj_apy_7d_avg, proj_apy_total_avg } = payload[0].payload

const unixTimestamp = toUTC(timestamp) * 1000
const formattedDate = new Intl.DateTimeFormat(undefined, {
month: 'short',
day: 'numeric',
year: 'numeric',
hour: 'numeric',
minute: '2-digit',
hour12: true,
}).format(unixTimestamp)

return (
<Paper
sx={{
backgroundColor: (theme) => theme.design.Layer[3].Fill,
padding: Spacing.md,
width: '20.5rem',
maxWidth: '100vw',
}}
elevation={2}
>
<Typography variant="bodyMBold">{formattedDate}</Typography>
<Stack
direction="column"
sx={{
marginTop: Spacing.sm,
padding: Spacing.sm,
gap: 1,
backgroundColor: (theme) => theme.design.Layer[2].Fill,
}}
>
<DataSet label={t`APR`} value={proj_apy.toFixed(2) + '%'} lineColor={Color.Primary[500]} />
<DataSet
label={t`7-day MA APR`}
value={proj_apy_7d_avg.toFixed(2) + '%'}
lineColor={Color.Secondary[500]}
dash="2 2"
/>
<DataSet
label={t`Average APR`}
value={proj_apy_total_avg.toFixed(2) + '%'}
lineColor={Color.Tertiary[400]}
dash="4 4"
/>
</Stack>
</Paper>
)
}

return null
}

export default CustomTooltip
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import type { ScrvUsdYieldWithAverages } from '@loan/entities/scrvusdYield'
import { SizesAndSpaces } from '@ui-kit/themes/design/1_sizes_spaces'
import { useTheme } from '@mui/material/styles'
import { t } from '@lingui/macro'
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts'
import RevenueChartTooltip from './RevenueChartTooltip'
import { toUTC } from '@loan/components/PageCrvUsdStaking/utils'

const { FontSize, FontWeight } = SizesAndSpaces

type Props = {
data: ScrvUsdYieldWithAverages[]
height?: number
}

const LineChartComponent = ({ data, height = 400 }: Props) => {
const {
design: { Color, Text },
} = useTheme()
const gridLineColor = Color.Neutral[300]
const gridTextColor = Text.TextColors.Tertiary
const averageLineColor = Color.Tertiary[400]
const sevenDayAverageLineColor = Color.Secondary[500]
const mainLineColor = Color.Primary[500]

const labels = {
proj_apy: { text: t`APR`, dash: 'none' },
proj_apy_7d_avg: { text: t`7-day MA APR`, dash: '2 2' },
proj_apy_total_avg: { text: t`Average APR`, dash: '4 4' },
} as const

return (
<ResponsiveContainer width="100%" height={height} debounce={200}>
<LineChart
width={500}
height={300}
data={data}
margin={{
top: 16,
right: 16,
left: undefined,
bottom: 16,
}}
>
<CartesianGrid stroke={gridLineColor} strokeWidth={0.3} vertical={true} />
<XAxis
dataKey="timestamp"
tick={{ fill: gridTextColor, fontSize: FontSize.xs.desktop }}
tickLine={{ fill: gridLineColor, strokeWidth: 0.5 }}
axisLine={false}
minTickGap={20}
tickMargin={4}
tickFormatter={(time) => {
const unix = toUTC(time as string | number) * 1000
return new Intl.DateTimeFormat(undefined, {
day: '2-digit',
month: '2-digit',
year: 'numeric',
}).format(unix)
}}
/>
<YAxis
tick={{ fill: gridTextColor, fontSize: FontSize.xs.desktop }}
tickFormatter={(value) => `${value.toFixed(0)}%`}
tickLine={{ fill: gridLineColor, strokeWidth: 0.5 }}
axisLine={false}
dataKey={'proj_apy'}
/>
<Tooltip content={RevenueChartTooltip} cursor={{ opacity: 0.3 }} />
<Line
type="monotone"
dataKey="proj_apy"
stroke={mainLineColor}
strokeWidth={2}
activeDot={{ r: 4 }}
dot={false}
isAnimationActive={false}
/>
<Line
type="monotone"
dataKey="proj_apy_7d_avg"
stroke={sevenDayAverageLineColor}
strokeWidth={2}
strokeDasharray={labels['proj_apy_7d_avg'].dash}
activeDot={{ r: 4 }}
dot={false}
isAnimationActive={false}
/>
<Line
type="monotone"
dataKey="proj_apy_total_avg"
stroke={averageLineColor}
strokeWidth={2}
strokeDasharray={labels['proj_apy_total_avg'].dash}
activeDot={{ r: 4 }}
dot={false}
isAnimationActive={false}
/>
<Legend
margin={{ top: 16, bottom: 16 }}
verticalAlign="bottom"
align="left"
iconType="plainline"
iconSize={20}
height={32}
formatter={(value: keyof typeof labels) => labels[value].text}
wrapperStyle={{
fontWeight: FontWeight.Medium,
fontSize: FontSize.sm.desktop,
color: Text.TextColors.Secondary,
paddingLeft: 24,
}}
/>
</LineChart>
</ResponsiveContainer>
)
}

export default LineChartComponent
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Stack } from '@mui/material'
import { Metric } from '@ui-kit/shared/ui/Metric'
import { SizesAndSpaces } from '@ui-kit/themes/design/1_sizes_spaces'

import { useScrvUsdYield } from '@loan/entities/scrvusdYield'
import { useScrvUsdRevenue } from '@loan/entities/scrvusdRevenue'

const { Spacing } = SizesAndSpaces

const StatsStack = () => {
const { data: yieldData, error: yieldError, isFetching: yieldIsFetching } = useScrvUsdYield({ timeOption: '1d' })
const { data: revenueData, error: revenueError, isFetching: revenueIsFetching } = useScrvUsdRevenue({})

return (
<Stack direction="row" gap={Spacing.md} sx={{ justifyContent: 'space-between', width: '100%' }}>
<Metric
label="Total crvUSD Staked"
value={yieldData?.[yieldData.length - 1]?.supply ?? 0}
loading={yieldIsFetching}
unit="dollar"
/>
<Metric
label="Current APY"
value={yieldData?.[yieldData.length - 1]?.proj_apy ?? 0}
loading={yieldIsFetching}
decimals={2}
unit="percentage"
/>
<Metric
label="Total Revenue Distributed"
value={revenueData?.total_distributed ?? 0}
loading={revenueIsFetching}
unit="dollar"
/>
<Metric
label="Weekly Accumulated Revenue"
value={revenueData?.epochs[revenueData.epochs.length - 1].weeklyRevenue ?? 0}
loading={revenueIsFetching}
unit="dollar"
/>
</Stack>
)
}

export default StatsStack
Loading
Loading