From 92efb88ede97dfd217f02115eadf1b206e4ea176 Mon Sep 17 00:00:00 2001 From: Connor Prussin Date: Tue, 8 Oct 2024 16:15:09 -0700 Subject: [PATCH] feat(staking): add stats to navbar --- .../Header/current-stake-account.tsx | 2 +- .../src/components/Header/help-menu.tsx | 6 +- apps/staking/src/components/Header/index.tsx | 46 ++++++----- ...-pramaeters.tsx => program-parameters.tsx} | 0 apps/staking/src/components/Header/stats.tsx | 81 +++++++++++++++++++ apps/staking/src/components/Tokens/index.tsx | 2 + .../src/components/WalletButton/index.tsx | 3 +- 7 files changed, 117 insertions(+), 23 deletions(-) rename apps/staking/src/components/Header/{program-pramaeters.tsx => program-parameters.tsx} (100%) create mode 100644 apps/staking/src/components/Header/stats.tsx diff --git a/apps/staking/src/components/Header/current-stake-account.tsx b/apps/staking/src/components/Header/current-stake-account.tsx index 553be7578..a003ad0e7 100644 --- a/apps/staking/src/components/Header/current-stake-account.tsx +++ b/apps/staking/src/components/Header/current-stake-account.tsx @@ -20,7 +20,7 @@ export const CurrentStakeAccount = ({ return api.type === ApiStateType.Loaded && !isBlocked ? (
{ return ( <> - diff --git a/apps/staking/src/components/Header/index.tsx b/apps/staking/src/components/Header/index.tsx index 7772af727..f04896dc4 100644 --- a/apps/staking/src/components/Header/index.tsx +++ b/apps/staking/src/components/Header/index.tsx @@ -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"; @@ -13,22 +14,31 @@ export const Header = ({ className, ...props }: Omit, "children">) => ( -
-
- - - - - -
- - - -
-
-
-
+ <> +
+
+ +
+ + + + + +
+
+ + + +
+
+
+
+ + ); diff --git a/apps/staking/src/components/Header/program-pramaeters.tsx b/apps/staking/src/components/Header/program-parameters.tsx similarity index 100% rename from apps/staking/src/components/Header/program-pramaeters.tsx rename to apps/staking/src/components/Header/program-parameters.tsx diff --git a/apps/staking/src/components/Header/stats.tsx b/apps/staking/src/components/Header/stats.tsx new file mode 100644 index 000000000..bc867c80a --- /dev/null +++ b/apps/staking/src/components/Header/stats.tsx @@ -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) => { + const { connection } = useConnection(); + const state = useData("poolStats", () => fetchStats(connection), { + refreshInterval: REFRESH_INTERVAL, + }); + + return ( +
+
+ {state.type === StateType.Loaded ? ( + + {state.data.totalStaked} + + ) : ( + + )} +
+ OIS Total Staked +
+
+
+
+ {state.type === StateType.Loaded ? ( + + {state.data.rewardsDistributed} + + ) : ( + + )} +
+ OIS Rewards Distributed +
+
+
+ ); +}; + +const Loading = () => ( +
+); + +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); diff --git a/apps/staking/src/components/Tokens/index.tsx b/apps/staking/src/components/Tokens/index.tsx index e25f5c7fd..6c7d5e046 100644 --- a/apps/staking/src/components/Tokens/index.tsx +++ b/apps/staking/src/components/Tokens/index.tsx @@ -1,3 +1,5 @@ +"use client"; + import clsx from "clsx"; import * as dnum from "dnum"; import { type ComponentProps, useMemo } from "react"; diff --git a/apps/staking/src/components/WalletButton/index.tsx b/apps/staking/src/components/WalletButton/index.tsx index 8c4837063..f84b7a15d 100644 --- a/apps/staking/src/components/WalletButton/index.tsx +++ b/apps/staking/src/components/WalletButton/index.tsx @@ -295,7 +295,8 @@ const ButtonComponent = ({ ...props }: ButtonComponentProps) => (