Skip to content

Commit

Permalink
fix(staking): use the sdk to drive epoch timestamps
Browse files Browse the repository at this point in the history
  • Loading branch information
cprussin committed Sep 11, 2024
1 parent 158e50c commit 1b37e08
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 40 deletions.
39 changes: 12 additions & 27 deletions apps/staking/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const publishersRankingSchema = z
type Data = {
total: bigint;
availableRewards: bigint;
currentEpoch: bigint;
lastSlash:
| {
amount: bigint;
Expand Down Expand Up @@ -202,21 +203,19 @@ const loadDataForStakeAccount = async (
stakeAccountCustody,
unlockSchedule,
claimableRewards,
currentEpoch,
] = await Promise.all([
loadBaseInfo(client, hermesClient),
client.getStakeAccountCustody(stakeAccount.address),
client.getUnlockSchedule(stakeAccount.address),
client.getClaimableRewards(stakeAccount.address),
getCurrentEpoch(client.connection),
]);

const filterGovernancePositions = (positionState: PositionState) =>
getAmountByTargetAndState({
stakeAccountPositions: stakeAccount,
targetWithParameters: { voting: {} },
positionState,
epoch: currentEpoch,
epoch: baseInfo.currentEpoch,
});

const filterOISPositions = (
Expand All @@ -227,7 +226,7 @@ const loadDataForStakeAccount = async (
stakeAccountPositions: stakeAccount,
targetWithParameters: { integrityPool: { publisher } },
positionState,
epoch: currentEpoch,
epoch: baseInfo.currentEpoch,
});

return {
Expand Down Expand Up @@ -271,13 +270,15 @@ const loadBaseInfo = async (
client: PythStakingClient,
hermesClient: HermesClient,
) => {
const [publishers, walletAmount, poolConfig] = await Promise.all([
loadPublisherData(client, hermesClient),
client.getOwnerPythBalance(),
client.getPoolConfigAccount(),
]);

return { yieldRate: poolConfig.y, walletAmount, publishers };
const [publishers, walletAmount, poolConfig, currentEpoch] =
await Promise.all([
loadPublisherData(client, hermesClient),
client.getOwnerPythBalance(),
client.getPoolConfigAccount(),
getCurrentEpoch(client.connection),
]);

return { yieldRate: poolConfig.y, walletAmount, publishers, currentEpoch };
};

const loadPublisherData = async (
Expand Down Expand Up @@ -454,22 +455,6 @@ export const optPublisherOut = async (
throw new NotImplementedError();
};

export const getUpcomingEpoch = (): Date => {
const d = new Date();
d.setUTCDate(d.getUTCDate() + ((5 + 7 - d.getUTCDay()) % 7 || 7));
d.setUTCHours(0);
d.setUTCMinutes(0);
d.setUTCSeconds(0);
d.setUTCMilliseconds(0);
return d;
};

export const getNextFullEpoch = (): Date => {
const d = getUpcomingEpoch();
d.setUTCDate(d.getUTCDate() + 7);
return d;
};

const MOCK_DELAY = 500;

const mkMockHistory = (): AccountHistory => [
Expand Down
4 changes: 4 additions & 0 deletions apps/staking/src/components/Dashboard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Styled } from "../Styled";

type Props = {
api: States[ApiStateType.Loaded] | States[ApiStateType.LoadedNoStakeAccount];
currentEpoch: bigint;
total: bigint;
lastSlash:
| {
Expand Down Expand Up @@ -42,6 +43,7 @@ type Props = {

export const Dashboard = ({
api,
currentEpoch,
total,
lastSlash,
walletAmount,
Expand Down Expand Up @@ -150,6 +152,7 @@ export const Dashboard = ({
<DashboardTabPanel id={TabIds.Governance}>
<Governance
api={api}
currentEpoch={currentEpoch}
availableToStake={availableToStakeGovernance}
warmup={governance.warmup}
staked={governance.staked}
Expand All @@ -160,6 +163,7 @@ export const Dashboard = ({
<DashboardTabPanel id={TabIds.IntegrityStaking}>
<OracleIntegrityStaking
api={api}
currentEpoch={currentEpoch}
availableToStake={availableToStakeIntegrity}
locked={locked}
warmup={integrityStakingWarmup}
Expand Down
3 changes: 3 additions & 0 deletions apps/staking/src/components/Governance/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ProgramSection } from "../ProgramSection";

type Props = {
api: States[ApiStateType.Loaded] | States[ApiStateType.LoadedNoStakeAccount];
currentEpoch: bigint;
availableToStake: bigint;
warmup: bigint;
staked: bigint;
Expand All @@ -12,6 +13,7 @@ type Props = {

export const Governance = ({
api,
currentEpoch,
availableToStake,
warmup,
staked,
Expand All @@ -21,6 +23,7 @@ export const Governance = ({
<ProgramSection
name="Governance"
description="Vote and Influence the Network"
currentEpoch={currentEpoch}
available={availableToStake}
warmup={warmup}
staked={staked}
Expand Down
20 changes: 18 additions & 2 deletions apps/staking/src/components/OracleIntegrityStaking/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const PAGE_SIZE = 10;

type Props = {
api: States[ApiStateType.Loaded] | States[ApiStateType.LoadedNoStakeAccount];
currentEpoch: bigint;
availableToStake: bigint;
locked: bigint;
warmup: bigint;
Expand All @@ -59,6 +60,7 @@ type Props = {

export const OracleIntegrityStaking = ({
api,
currentEpoch,
availableToStake,
locked,
warmup,
Expand Down Expand Up @@ -88,6 +90,7 @@ export const OracleIntegrityStaking = ({
name="Oracle Integrity Staking (OIS)"
description="Protect DeFi"
className="pb-0 sm:pb-0"
currentEpoch={currentEpoch}
available={availableToStake}
warmup={warmup}
staked={staked}
Expand Down Expand Up @@ -129,6 +132,7 @@ export const OracleIntegrityStaking = ({
<Publisher
api={api}
isSelf
currentEpoch={currentEpoch}
availableToStake={availableToStake}
publisher={self}
totalStaked={staked}
Expand All @@ -147,6 +151,7 @@ export const OracleIntegrityStaking = ({
>
<PublisherList
api={api}
currentEpoch={currentEpoch}
title={self ? "Other Publishers" : "Publishers"}
availableToStake={availableToStake}
publishers={otherPublishers}
Expand Down Expand Up @@ -401,6 +406,7 @@ const OptOutButton = ({ api, self }: OptOutButtonProps) => {

type PublisherListProps = {
api: States[ApiStateType.Loaded] | States[ApiStateType.LoadedNoStakeAccount];
currentEpoch: bigint;
title: string;
availableToStake: bigint;
totalStaked: bigint;
Expand All @@ -410,6 +416,7 @@ type PublisherListProps = {

const PublisherList = ({
api,
currentEpoch,
title,
availableToStake,
publishers,
Expand Down Expand Up @@ -583,6 +590,7 @@ const PublisherList = ({
{paginatedPublishers.map((publisher) => (
<Publisher
api={api}
currentEpoch={currentEpoch}
key={publisher.publicKey.toBase58()}
availableToStake={availableToStake}
publisher={publisher}
Expand Down Expand Up @@ -686,6 +694,7 @@ const PublisherTableHeader = Styled(

type PublisherProps = {
api: States[ApiStateType.Loaded] | States[ApiStateType.LoadedNoStakeAccount];
currentEpoch: bigint;
availableToStake: bigint;
totalStaked: bigint;
isSelf?: boolean;
Expand Down Expand Up @@ -713,6 +722,7 @@ type PublisherProps = {

const Publisher = ({
api,
currentEpoch,
publisher,
availableToStake,
totalStaked,
Expand Down Expand Up @@ -837,6 +847,7 @@ const Publisher = ({
>
<StakeToPublisherButton
api={api}
currentEpoch={currentEpoch}
availableToStake={availableToStake}
publisher={publisher}
yieldRate={yieldRate}
Expand Down Expand Up @@ -913,7 +924,10 @@ const Publisher = ({
max={staked}
transfer={unstake}
>
<StakingTimeline cooldownOnly />
<StakingTimeline
cooldownOnly
currentEpoch={currentEpoch}
/>
</TransferButton>
</td>
</tr>
Expand All @@ -933,12 +947,14 @@ const PublisherTableCell = Styled("td", "py-4 px-5 whitespace-nowrap");
type StakeToPublisherButtonProps = {
api: States[ApiStateType.Loaded] | States[ApiStateType.LoadedNoStakeAccount];
publisher: PublisherProps["publisher"];
currentEpoch: bigint;
availableToStake: bigint;
yieldRate: bigint;
};

const StakeToPublisherButton = ({
api,
currentEpoch,
availableToStake,
publisher,
yieldRate,
Expand Down Expand Up @@ -987,7 +1003,7 @@ const StakeToPublisherButton = ({
%
</div>
</div>
<StakingTimeline />
<StakingTimeline currentEpoch={currentEpoch} />
</>
)}
</TransferButton>
Expand Down
14 changes: 8 additions & 6 deletions apps/staking/src/components/ProgramSection/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { ArrowLongDownIcon } from "@heroicons/react/24/outline";
import { epochToDate } from "@pythnetwork/staking-sdk";
import clsx from "clsx";
import type { HTMLAttributes, ReactNode, ComponentProps } from "react";

import { getUpcomingEpoch, getNextFullEpoch } from "../../api";
import { StakingTimeline } from "../StakingTimeline";
import { Tokens } from "../Tokens";
import { TransferButton } from "../TransferButton";

type Props = HTMLAttributes<HTMLDivElement> & {
name: string;
description: string;
currentEpoch: bigint;
warmup: bigint;
staked: bigint;
cooldown: bigint;
Expand Down Expand Up @@ -45,6 +46,7 @@ export const ProgramSection = ({
name,
description,
children,
currentEpoch,
warmup,
staked,
cooldown,
Expand Down Expand Up @@ -82,7 +84,7 @@ export const ProgramSection = ({
max={available}
transfer={stake}
>
<StakingTimeline />
<StakingTimeline currentEpoch={currentEpoch} />
</TransferButton>
),
})}
Expand All @@ -96,7 +98,7 @@ export const ProgramSection = ({
{...(warmup > 0n && {
details: (
<div className="mt-2 text-xs text-neutral-500">
Staking {getUpcomingEpoch().toLocaleString()}
Staking {epochToDate(currentEpoch + 1n).toLocaleString()}
</div>
),
})}
Expand Down Expand Up @@ -131,7 +133,7 @@ export const ProgramSection = ({
max={staked}
transfer={unstake}
>
<StakingTimeline cooldownOnly />
<StakingTimeline cooldownOnly currentEpoch={currentEpoch} />
</TransferButton>
),
})}
Expand All @@ -147,13 +149,13 @@ export const ProgramSection = ({
{cooldown > 0n && (
<div className="mt-2 text-xs text-neutral-500">
<Tokens>{cooldown}</Tokens> end{" "}
{getUpcomingEpoch().toLocaleString()}
{epochToDate(currentEpoch + 1n).toLocaleString()}
</div>
)}
{cooldown2 > 0n && (
<div className="mt-2 text-xs text-neutral-500">
<Tokens>{cooldown2}</Tokens> end{" "}
{getNextFullEpoch().toLocaleString()}
{epochToDate(currentEpoch + 2n).toLocaleString()}
</div>
)}
</>
Expand Down
12 changes: 7 additions & 5 deletions apps/staking/src/components/StakingTimeline/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { ArrowLongDownIcon } from "@heroicons/react/24/outline";

import { getUpcomingEpoch, getNextFullEpoch } from "../../api";
import { epochToDate } from "@pythnetwork/staking-sdk";

type Props = {
cooldownOnly?: boolean | undefined;
currentEpoch: bigint;
};

export const StakingTimeline = ({ cooldownOnly }: Props) => (
export const StakingTimeline = ({ cooldownOnly, currentEpoch }: Props) => (
<div className="mb-2 flex flex-col gap-1">
<div className="text-sm">Timeline</div>
<div className="grid grid-cols-[max-content_1fr_max-content] items-center gap-x-4 gap-y-3 border border-neutral-600/50 bg-pythpurple-100/10 px-8 py-6 text-sm font-light">
Expand All @@ -15,7 +15,7 @@ export const StakingTimeline = ({ cooldownOnly }: Props) => (
<div className="size-4 rounded-full border border-dashed border-pythpurple-100" />
<div>Warmup</div>
<div className="text-right">
{getUpcomingEpoch().toLocaleString()}
{epochToDate(currentEpoch + 1n).toLocaleString()}
</div>
<ArrowLongDownIcon className="size-4 scale-y-[200%] [mask-image:linear-gradient(to_bottom,_transparent,_black_125%)]" />
<div>Staking</div>
Expand All @@ -25,7 +25,9 @@ export const StakingTimeline = ({ cooldownOnly }: Props) => (
<div className="size-4 rounded-full border border-pythpurple-100 bg-pythpurple-600" />
<div>Cooldown</div>
<div className="text-right">
{cooldownOnly ? getNextFullEpoch().toLocaleString() : "One full epoch"}
{cooldownOnly
? epochToDate(currentEpoch + 2n).toLocaleString()
: "One full epoch"}
</div>
</div>
</div>
Expand Down

0 comments on commit 1b37e08

Please sign in to comment.