Skip to content
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
4 changes: 4 additions & 0 deletions apps/staking/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@
"@solana/wallet-adapter-wallets": "0.19.10",
"@solana/web3.js": "^1.95.2",
"clsx": "^2.1.1",
"dnum": "^2.13.1",
"next": "^14.2.5",
"pino": "^9.3.2",
"react": "^18.3.1",
"react-aria": "^3.34.3",
"react-aria-components": "^1.3.3",
"react-dom": "^18.3.1",
"recharts": "^2.12.7",
"swr": "^2.2.5",
Expand All @@ -61,6 +63,8 @@
"postcss": "^8.4.40",
"prettier": "^3.3.2",
"tailwindcss": "^3.4.7",
"tailwindcss-animate": "^1.0.7",
"tailwindcss-react-aria-components": "^1.1.5",
"typescript": "^5.5.4",
"vercel": "^35.2.2"
}
Expand Down
6 changes: 3 additions & 3 deletions apps/staking/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export type StakeDetails = ReturnType<
>;

export enum AccountHistoryItemType {
Deposit,
AddTokens,
LockedDeposit,
Withdrawal,
RewardsCredited,
Expand All @@ -97,7 +97,7 @@ export enum AccountHistoryItemType {
}

const AccountHistoryAction = {
Deposit: () => ({ type: AccountHistoryItemType.Deposit as const }),
AddTokens: () => ({ type: AccountHistoryItemType.AddTokens as const }),
LockedDeposit: (unlockDate: Date) => ({
type: AccountHistoryItemType.LockedDeposit as const,
unlockDate,
Expand Down Expand Up @@ -506,7 +506,7 @@ const MOCK_DATA: Record<string, Data> = {
const mkMockHistory = (): AccountHistory => [
{
timestamp: new Date("2024-06-10T00:00:00Z"),
action: AccountHistoryAction.Deposit(),
action: AccountHistoryAction.AddTokens(),
amount: 2_000_000n,
accountTotal: 2_000_000n,
availableRewards: 0n,
Expand Down
89 changes: 21 additions & 68 deletions apps/staking/src/components/AccountHistory/index.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,26 @@
import useSWR from "swr";
import { ArrowPathIcon } from "@heroicons/react/24/outline";

import {
type AccountHistoryAction,
type StakeDetails,
AccountHistoryItemType,
StakeType,
loadAccountHistory,
} from "../../api";
import { useApiContext } from "../../hooks/use-api-context";
import { LoadingSpinner } from "../LoadingSpinner";
import { StateType, useAccountHistory } from "../../hooks/use-account-history";
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;

export const AccountHistory = () => {
const history = useAccountHistoryData();
const history = useAccountHistory();

switch (history.type) {
case DataStateType.NotLoaded:
case DataStateType.Loading: {
return <LoadingSpinner />;
case StateType.NotLoaded:
case StateType.Loading: {
return <ArrowPathIcon className="size-6 animate-spin" />;
}
case DataStateType.Error: {
case StateType.Error: {
return <p>Uh oh, an error occured!</p>;
}
case DataStateType.Loaded: {
case StateType.Loaded: {
return (
<table className="text-sm">
<thead className="font-medium">
Expand Down Expand Up @@ -56,7 +50,9 @@ export const AccountHistory = () => {
) => (
<tr key={i}>
<td className="pr-4">{timestamp.toLocaleString()}</td>
<td className="pr-4">{mkDescription(action)}</td>
<td className="pr-4">
<Description>{action}</Description>
</td>
<td className="pr-4">
<Tokens>{amount}</Tokens>
</td>
Expand All @@ -82,37 +78,37 @@ export const AccountHistory = () => {
}
};

const mkDescription = (action: AccountHistoryAction): string => {
switch (action.type) {
const Description = ({ children }: { children: AccountHistoryAction }) => {
switch (children.type) {
case AccountHistoryItemType.Claim: {
return "Rewards claimed";
}
case AccountHistoryItemType.Deposit: {
return "Tokens deposited";
case AccountHistoryItemType.AddTokens: {
return "Tokens added";
}
case AccountHistoryItemType.LockedDeposit: {
return `Locked tokens deposited, unlocking ${action.unlockDate.toLocaleString()}`;
return `Locked tokens deposited, unlocking ${children.unlockDate.toLocaleString()}`;
}
case AccountHistoryItemType.RewardsCredited: {
return "Rewards credited";
}
case AccountHistoryItemType.Slash: {
return `Staked tokens slashed from ${action.publisherName}`;
return `Staked tokens slashed from ${children.publisherName}`;
}
case AccountHistoryItemType.StakeCreated: {
return `Created stake position for ${getStakeDetails(action.details)}`;
return `Created stake position for ${getStakeDetails(children.details)}`;
}
case AccountHistoryItemType.StakeFinishedWarmup: {
return `Warmup complete for position for ${getStakeDetails(action.details)}`;
return `Warmup complete for position for ${getStakeDetails(children.details)}`;
}
case AccountHistoryItemType.Unlock: {
return "Locked tokens unlocked";
}
case AccountHistoryItemType.UnstakeCreated: {
return `Requested unstake for position for ${getStakeDetails(action.details)}`;
return `Requested unstake for position for ${getStakeDetails(children.details)}`;
}
case AccountHistoryItemType.UnstakeExitedCooldown: {
return `Cooldown completed for ${getStakeDetails(action.details)}`;
return `Cooldown completed for ${getStakeDetails(children.details)}`;
}
case AccountHistoryItemType.Withdrawal: {
return "Tokens withdrawn to wallet";
Expand All @@ -130,46 +126,3 @@ const getStakeDetails = (details: StakeDetails): string => {
}
}
};

const useAccountHistoryData = () => {
const apiContext = useApiContext();

const { data, isLoading, ...rest } = useSWR(
`${apiContext.stakeAccount.address.toBase58()}/history`,
() => loadAccountHistory(apiContext),
{
refreshInterval: REFRESH_INTERVAL,
},
);
const error = rest.error as unknown;

if (error) {
return DataState.ErrorState(error);
} else if (isLoading) {
return DataState.Loading();
} else if (data) {
return DataState.Loaded(data);
} else {
return DataState.NotLoaded();
}
};

enum DataStateType {
NotLoaded,
Loading,
Loaded,
Error,
}
const DataState = {
NotLoaded: () => ({ type: DataStateType.NotLoaded as const }),
Loading: () => ({ type: DataStateType.Loading as const }),
Loaded: (data: Awaited<ReturnType<typeof loadAccountHistory>>) => ({
type: DataStateType.Loaded as const,
data,
}),
ErrorState: (error: unknown) => ({
type: DataStateType.Error as const,
error,
}),
};
type DataState = ReturnType<(typeof DataState)[keyof typeof DataState]>;
42 changes: 21 additions & 21 deletions apps/staking/src/components/AccountSummary/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,16 @@ export const AccountSummary = ({
<Image
src={background}
alt=""
className="absolute -right-40 h-full object-right [mask-image:linear-gradient(to_right,_transparent,_black_50%)]"
className="absolute -right-40 hidden h-full object-cover object-right [mask-image:linear-gradient(to_right,_transparent,_black_50%)] md:block"
/>
<div className="relative flex flex-col items-start justify-between gap-16 px-12 py-20 md:flex-row md:items-center">
<div className="relative flex flex-col items-start justify-between gap-8 px-6 py-10 sm:gap-16 sm:px-12 sm:py-20 lg:flex-row lg:items-center">
<div>
<div className="mb-4 inline-block border border-neutral-600/50 bg-neutral-900 px-4 py-1 text-xs text-neutral-400">
<div className="mb-2 inline-block border border-neutral-600/50 bg-neutral-900 px-4 py-1 text-xs text-neutral-400 sm:mb-4">
Total Balance
</div>
<div className="flex flex-row items-center gap-8">
<span>
<Tokens className="text-6xl font-light">{total}</Tokens>
<Tokens className="text-4xl font-light sm:text-6xl">{total}</Tokens>
</span>
{lastSlash && (
<p className="max-w-48 text-sm text-red-600">
Expand All @@ -65,19 +65,11 @@ export const AccountSummary = ({
</p>
)}
</div>
<div className="mt-8 flex flex-row items-center gap-4">
<TransferButton
actionDescription="Add funds to your balance"
actionName="Deposit"
max={walletAmount}
transfer={deposit}
/>
</div>
{locked > 0n && (
<>
<div className="mt-6 flex flex-row items-center gap-1 text-xl text-pythpurple-100/50">
<div className="mt-3 flex flex-row items-center gap-1 text-pythpurple-100/50 sm:mt-6 sm:text-xl">
<Tokens>{locked}</Tokens>
<div>locked</div>
<div>locked included</div>
</div>
<Modal>
<ModalButton
Expand All @@ -90,7 +82,7 @@ export const AccountSummary = ({
title="Unlock Schedule"
description="Your tokens will become available for withdrawal and for participation in Integrity Staking according to this schedule"
>
<div className="border border-neutral-600/50 bg-pythpurple-100/10 px-8 py-6">
<div className="border border-neutral-600/50 bg-pythpurple-100/10 p-4 sm:px-8 sm:py-6">
<table>
<thead className="font-medium">
<tr>
Expand All @@ -101,7 +93,7 @@ export const AccountSummary = ({
<tbody>
{unlockSchedule.map((unlock, i) => (
<tr key={i}>
<td className="pr-12 text-sm opacity-80">
<td className="pr-12 text-xs opacity-80 sm:text-sm">
{unlock.date.toLocaleString()}
</td>
<td>
Expand All @@ -116,12 +108,20 @@ export const AccountSummary = ({
</Modal>
</>
)}
<div className="mt-3 flex flex-row items-center gap-4 sm:mt-8">
<TransferButton
actionDescription="Add funds to your balance"
actionName="Add Tokens"
max={walletAmount}
transfer={deposit}
/>
</div>
</div>
<div className="flex flex-col items-stretch gap-4 xl:flex-row">
<div className="flex w-full flex-col items-stretch gap-4 lg:w-auto xl:flex-row">
<BalanceCategory
name="Available for Withdrawal"
name="Unlocked & Unstaked"
amount={availableToWithdraw}
description="The lesser of the amount you have available to stake in governance & integrity staking"
description="The amount of unlocked tokens that are not staked in either program"
action={
<TransferButton
small
Expand All @@ -137,7 +137,7 @@ export const AccountSummary = ({
<BalanceCategory
name="Available Rewards"
amount={availableRewards}
description="Rewards you have earned but not yet claimed from the Integrity Staking program"
description="Rewards you have earned from OIS"
action={<ClaimButton disabled={availableRewards === 0n} />}
{...(expiringRewards !== undefined &&
expiringRewards.amount > 0n && {
Expand Down Expand Up @@ -169,7 +169,7 @@ const BalanceCategory = ({
action,
warning,
}: BalanceCategoryProps) => (
<div className="flex flex-col justify-between border border-neutral-600/50 bg-pythpurple-800/60 p-6 backdrop-blur">
<div className="flex w-full flex-col justify-between border border-neutral-600/50 bg-pythpurple-800/60 p-6 backdrop-blur lg:w-96">
<div>
<div className="mb-4 inline-block border border-neutral-600/50 bg-neutral-900 px-4 py-1 text-xs text-neutral-400">
{name}
Expand Down
16 changes: 2 additions & 14 deletions apps/staking/src/components/Amplitude/index.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,13 @@
"use client";

import * as amplitude from "@amplitude/analytics-browser";
import { autocapturePlugin } from "@amplitude/plugin-autocapture-browser";
import { useEffect, useRef } from "react";
import { useAmplitude } from "../../hooks/use-amplitude";

type Props = {
apiKey: string | undefined;
};

export const Amplitude = ({ apiKey }: Props) => {
const amplitudeInitialized = useRef(false);

useEffect(() => {
if (!amplitudeInitialized.current && apiKey) {
amplitude.add(autocapturePlugin());
amplitude.init(apiKey, {
defaultTracking: true,
});
amplitudeInitialized.current = true;
}
}, [apiKey]);
useAmplitude(apiKey);

// eslint-disable-next-line unicorn/no-null
return null;
Expand Down
2 changes: 1 addition & 1 deletion apps/staking/src/components/Button/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ const ButtonBase = ({

export const Button = Styled(
ButtonBase,
"border border-pythpurple-600 bg-pythpurple-600/50 data-[small]:text-sm data-[small]:px-6 data-[small]:py-1 data-[secondary]:bg-pythpurple-600/20 px-8 py-2 data-[nopad]:px-0 data-[nopad]:py-0 disabled:cursor-not-allowed disabled:bg-neutral-50/10 disabled:border-neutral-50/10 disabled:text-white/60 disabled:data-[loading]:cursor-wait hover:bg-pythpurple-600/60 data-[secondary]:hover:bg-pythpurple-600/60 data-[secondary]:disabled:bg-neutral-50/10 focus-visible:ring-1 focus-visible:ring-pythpurple-400 focus:outline-none justify-center",
"border border-pythpurple-600 bg-pythpurple-600/50 data-[small]:text-sm data-[small]:px-6 data-[small]:py-1 data-[secondary]:bg-pythpurple-600/20 px-2 sm:px-4 md:px-8 py-2 data-[nopad]:px-0 data-[nopad]:py-0 disabled:cursor-not-allowed disabled:bg-neutral-50/10 disabled:border-neutral-50/10 disabled:text-white/60 disabled:data-[loading]:cursor-wait hover:bg-pythpurple-600/60 data-[secondary]:hover:bg-pythpurple-600/60 data-[secondary]:disabled:bg-neutral-50/10 focus-visible:ring-1 focus-visible:ring-pythpurple-400 focus:outline-none",
);
11 changes: 8 additions & 3 deletions apps/staking/src/components/Dashboard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,15 @@ export const Dashboard = ({
expiringRewards={expiringRewards}
/>
<TabGroup as="section">
<TabList className="flex w-full flex-row font-medium">
<TabList className="flex w-full flex-row text-sm font-medium sm:text-base">
<DashboardTab>Overview</DashboardTab>
<DashboardTab>Governance</DashboardTab>
<DashboardTab>Oracle Integrity Staking</DashboardTab>
<DashboardTab>
<span className="sm:hidden">Integrity Staking</span>
<span className="hidden sm:inline">
Oracle Integrity Staking (OIS)
</span>
</DashboardTab>
</TabList>
<TabPanels className="mt-8">
<DashboardTabPanel>
Expand Down Expand Up @@ -159,7 +164,7 @@ export const Dashboard = ({

const DashboardTab = Styled(
Tab,
"grow border-b border-neutral-600/50 px-4 py-2 focus-visible:outline-none data-[selected]:cursor-default data-[selected]:border-pythpurple-400 data-[selected]:data-[hover]:bg-transparent data-[hover]:text-pythpurple-400 data-[selected]:text-pythpurple-400 data-[focus]:outline-none data-[focus]:ring-1 data-[focus]:ring-pythpurple-400",
"grow basis-0 border-b border-neutral-600/50 px-4 py-2 focus-visible:outline-none data-[selected]:cursor-default data-[selected]:border-pythpurple-400 data-[selected]:data-[hover]:bg-transparent data-[hover]:text-pythpurple-400 data-[selected]:text-pythpurple-400 data-[focus]:outline-none data-[focus]:ring-1 data-[focus]:ring-pythpurple-400",
);

const DashboardTabPanel = Styled(
Expand Down
Loading
Loading