Skip to content

Commit

Permalink
feat(staking): add stats to navbar
Browse files Browse the repository at this point in the history
  • Loading branch information
cprussin committed Oct 8, 2024
1 parent 7254d7b commit 92efb88
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const CurrentStakeAccount = ({
return api.type === ApiStateType.Loaded && !isBlocked ? (
<div
className={clsx(
"hidden flex-col items-end justify-center text-xs xs:flex md:flex-row md:items-center md:text-sm",
"hidden flex-col items-end justify-center text-xs xs:flex xl:flex-row xl:items-center xl:text-sm",
className,
)}
{...props}
Expand Down
6 changes: 3 additions & 3 deletions apps/staking/src/components/Header/help-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
import { useState, useCallback } from "react";
import { MenuTrigger, Button } from "react-aria-components";

import { ProgramParameters } from "./program-pramaeters";
import { ProgramParameters } from "./program-parameters";
import { StateType, useApi } from "../../hooks/use-api";
import { GeneralFaq } from "../GeneralFaq";
import { GovernanceGuide } from "../GovernanceGuide";
Expand Down Expand Up @@ -45,9 +45,9 @@ export const HelpMenu = () => {
return (
<>
<MenuTrigger>
<Button className="group -mx-2 flex flex-row items-center gap-2 rounded-sm p-2 transition hover:bg-white/10 focus:outline-none focus-visible:ring-1 focus-visible:ring-pythpurple-400 pressed:bg-white/10 sm:-mx-4 sm:px-4">
<Button className="group -mx-2 flex flex-row items-center gap-2 rounded-sm p-2 transition hover:bg-white/10 focus:outline-none focus-visible:ring-1 focus-visible:ring-pythpurple-400 pressed:bg-white/10 md:-mx-4 md:px-4">
<QuestionMarkCircleIcon className="size-6 flex-none" />
<span className="sr-only xs:not-sr-only">Help</span>
<span className="sr-only md:not-sr-only">Help</span>
<ChevronDownIcon className="size-4 flex-none opacity-60 transition duration-300 group-data-[pressed]:-rotate-180" />
</Button>
<Menu placement="bottom end">
Expand Down
46 changes: 28 additions & 18 deletions apps/staking/src/components/Header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { CurrentStakeAccount } from "./current-stake-account";
import { HelpMenu } from "./help-menu";
import Logo from "./logo.svg";
import Logomark from "./logomark.svg";
import { Stats } from "./stats";
import { Link } from "../Link";
import { MaxWidth } from "../MaxWidth";
import { WalletButton } from "../WalletButton";
Expand All @@ -13,22 +14,31 @@ export const Header = ({
className,
...props
}: Omit<HTMLAttributes<HTMLElement>, "children">) => (
<header className={clsx("sticky top-0 w-full lg:px-4", className)} {...props}>
<div className="border-b border-neutral-600/50 bg-pythpurple-800 lg:border-x">
<MaxWidth className="flex h-header items-center justify-between gap-2 lg:-mx-4">
<Link
href="/"
className="-mx-2 h-[calc(var(--header-height)_-_0.5rem)] rounded-sm p-2 text-pythpurple-100 focus:outline-none focus-visible:ring-1 focus-visible:ring-pythpurple-400"
>
<Logo className="hidden h-full sm:block" />
<Logomark className="h-full sm:hidden" />
</Link>
<div className="flex flex-none flex-row items-stretch gap-4 sm:gap-8">
<CurrentStakeAccount />
<WalletButton className="flex-none" />
<HelpMenu />
</div>
</MaxWidth>
</div>
</header>
<>
<header
className={clsx("sticky top-0 w-full lg:px-4", className)}
{...props}
>
<div className="border-b border-neutral-600/50 bg-pythpurple-800 lg:border-x">
<MaxWidth className="flex h-header items-center justify-between gap-2 lg:-mx-4">
<div className="flex flex-row items-center gap-8 lg:gap-12">
<Link
href="/"
className="-mx-2 h-[calc(var(--header-height)_-_0.5rem)] rounded-sm p-2 text-pythpurple-100 focus:outline-none focus-visible:ring-1 focus-visible:ring-pythpurple-400"
>
<Logo className="hidden h-full lg:block" />
<Logomark className="h-full lg:hidden" />
</Link>
<Stats className="hidden gap-4 sm:flex lg:gap-6" />
</div>
<div className="flex flex-none flex-row items-stretch gap-4 md:gap-8">
<CurrentStakeAccount />
<WalletButton className="flex-none" />
<HelpMenu />
</div>
</MaxWidth>
</div>
</header>
<Stats className="border-b border-neutral-600/50 py-4 text-center sm:hidden" />
</>
);
81 changes: 81 additions & 0 deletions apps/staking/src/components/Header/stats.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"use client";

import { PythStakingClient } from "@pythnetwork/staking-sdk";
import { useConnection } from "@solana/wallet-adapter-react";
import { Connection } from "@solana/web3.js";
import clsx from "clsx";
import type { HTMLProps } from "react";

import { StateType, useData } from "../../hooks/use-data";
import { Tokens } from "../Tokens";

const ONE_SECOND_IN_MS = 1000;
const ONE_MINUTE_IN_MS = 60 * ONE_SECOND_IN_MS;
const REFRESH_INTERVAL = 1 * ONE_MINUTE_IN_MS;
const INITIAL_REWARD_POOL_SIZE = 60_000_000_000_000n;

export const Stats = ({ className, ...props }: HTMLProps<HTMLDivElement>) => {
const { connection } = useConnection();
const state = useData("poolStats", () => fetchStats(connection), {
refreshInterval: REFRESH_INTERVAL,
});

return (
<div className={clsx("flex flex-row items-stretch", className)} {...props}>
<div className="flex-1 sm:flex-none">
{state.type === StateType.Loaded ? (
<Tokens className="mb-1 text-xl font-semibold leading-none">
{state.data.totalStaked}
</Tokens>
) : (
<Loading />
)}
<div className="text-xs leading-none text-pythpurple-400">
OIS Total Staked
</div>
</div>
<div className="border-l border-neutral-600/50" />
<div className="flex-1 sm:flex-none">
{state.type === StateType.Loaded ? (
<Tokens className="mb-1 text-xl font-semibold leading-none">
{state.data.rewardsDistributed}
</Tokens>
) : (
<Loading />
)}
<div className="text-xs leading-none text-pythpurple-400">
OIS Rewards Distributed
</div>
</div>
</div>
);
};

const Loading = () => (
<div className="mb-1 h-5 w-10 animate-pulse rounded-md bg-white/30" />
);

const fetchStats = async (connection: Connection) => {
const client = new PythStakingClient({ connection });
const poolData = await client.getPoolDataAccount();
const totalDelegated = sum(
poolData.delState.map(
({ totalDelegation, deltaDelegation }) =>
totalDelegation + deltaDelegation,
),
);
const totalSelfStaked = sum(
poolData.selfDelState.map(
({ totalDelegation, deltaDelegation }) =>
totalDelegation + deltaDelegation,
),
);

return {
totalStaked: totalDelegated + totalSelfStaked,
rewardsDistributed: poolData.claimableRewards + INITIAL_REWARD_POOL_SIZE,
};
};

const sum = (values: bigint[]): bigint =>
values.reduce((acc, value) => acc + value, 0n);
2 changes: 2 additions & 0 deletions apps/staking/src/components/Tokens/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"use client";

import clsx from "clsx";
import * as dnum from "dnum";
import { type ComponentProps, useMemo } from "react";
Expand Down
3 changes: 2 additions & 1 deletion apps/staking/src/components/WalletButton/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,8 @@ const ButtonComponent = ({
...props
}: ButtonComponentProps) => (
<Button
className={clsx("w-36 text-sm sm:w-52 sm:text-base", className)}
className={clsx("w-36 text-sm lg:w-52 lg:text-base", className)}
size="nopad"
{...props}
>
<WalletIcon className="size-4 flex-none opacity-60" />
Expand Down

0 comments on commit 92efb88

Please sign in to comment.