Skip to content

Commit

Permalink
feat(staking): add restricted mode for non-fatf geofenced countries
Browse files Browse the repository at this point in the history
  • Loading branch information
cprussin committed Sep 25, 2024
1 parent 81b80c7 commit 328c48b
Show file tree
Hide file tree
Showing 13 changed files with 244 additions and 150 deletions.
1 change: 1 addition & 0 deletions apps/staking/src/app/restricted-mode/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { RestrictedMode as default } from "../../components/Home";
102 changes: 55 additions & 47 deletions apps/staking/src/components/AccountSummary/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type Props = {
availableRewards: bigint;
expiringRewards: Date | undefined;
availableToWithdraw: bigint;
restrictedMode?: boolean | undefined;
};

export const AccountSummary = ({
Expand All @@ -54,6 +55,7 @@ export const AccountSummary = ({
availableToWithdraw,
availableRewards,
expiringRewards,
restrictedMode,
}: Props) => (
<section className="relative w-full overflow-hidden sm:border sm:border-neutral-600/50 sm:bg-pythpurple-800">
<Image
Expand Down Expand Up @@ -118,7 +120,9 @@ export const AccountSummary = ({
</>
)}
<div className="mt-3 flex flex-row items-center gap-4 sm:mt-8">
<AddTokensButton walletAmount={walletAmount} api={api} />
{!restrictedMode && (
<AddTokensButton walletAmount={walletAmount} api={api} />
)}
{availableToWithdraw === 0n ? (
<DialogTrigger>
<Button variant="secondary" className="xl:hidden">
Expand All @@ -145,23 +149,25 @@ export const AccountSummary = ({
className="xl:hidden"
/>
)}
<DialogTrigger>
<Button variant="secondary" className="xl:hidden">
Claim
</Button>
{availableRewards === 0n ||
api.type === ApiStateType.LoadedNoStakeAccount ? (
<ModalDialog title="No Rewards" closeButtonText="Ok">
<p>You have no rewards available to be claimed</p>
</ModalDialog>
) : (
<ClaimDialog
expiringRewards={expiringRewards}
availableRewards={availableRewards}
api={api}
/>
)}
</DialogTrigger>
{!restrictedMode && (
<DialogTrigger>
<Button variant="secondary" className="xl:hidden">
Claim
</Button>
{availableRewards === 0n ||
api.type === ApiStateType.LoadedNoStakeAccount ? (
<ModalDialog title="No Rewards" closeButtonText="Ok">
<p>You have no rewards available to be claimed</p>
</ModalDialog>
) : (
<ClaimDialog
expiringRewards={expiringRewards}
availableRewards={availableRewards}
api={api}
/>
)}
</DialogTrigger>
)}
</div>
</div>
<div className="hidden w-auto items-stretch gap-4 xl:flex">
Expand All @@ -173,35 +179,37 @@ export const AccountSummary = ({
<WithdrawButton api={api} max={availableToWithdraw} size="small" />
}
/>
<BalanceCategory
name="Available Rewards"
amount={availableRewards}
description="Rewards you have earned from OIS"
action={
api.type === ApiStateType.Loaded ? (
<ClaimButton
size="small"
variant="secondary"
isDisabled={availableRewards === 0n}
api={api}
/>
) : (
<Button size="small" variant="secondary" isDisabled={true}>
Claim
</Button>
)
}
{...(expiringRewards !== undefined &&
availableRewards > 0n && {
warning: (
<>
Rewards expire one year from the epoch in which they were
earned. You have rewards expiring on{" "}
{expiringRewards.toLocaleDateString()}.
</>
),
})}
/>
{!restrictedMode && (
<BalanceCategory
name="Available Rewards"
amount={availableRewards}
description="Rewards you have earned from OIS"
action={
api.type === ApiStateType.Loaded ? (
<ClaimButton
size="small"
variant="secondary"
isDisabled={availableRewards === 0n}
api={api}
/>
) : (
<Button size="small" variant="secondary" isDisabled={true}>
Claim
</Button>
)
}
{...(expiringRewards !== undefined &&
availableRewards > 0n && {
warning: (
<>
Rewards expire one year from the epoch in which they were
earned. You have rewards expiring on{" "}
{expiringRewards.toLocaleDateString()}.
</>
),
})}
/>
)}
</div>
</div>
</section>
Expand Down
140 changes: 80 additions & 60 deletions apps/staking/src/components/Dashboard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ type Props = {
integrityStakingPublishers: ComponentProps<
typeof OracleIntegrityStaking
>["publishers"];
restrictedMode?: boolean | undefined;
};

export const Dashboard = ({
Expand All @@ -57,6 +58,7 @@ export const Dashboard = ({
integrityStakingPublishers,
unlockSchedule,
yieldRate,
restrictedMode,
}: Props) => {
const [tab, setTab] = useState<TabId>(TabIds.Empty);

Expand Down Expand Up @@ -126,7 +128,11 @@ export const Dashboard = ({
}, [tab]);

return (
<main className="flex w-full flex-col gap-8 xl:px-4 xl:py-6">
<main
className={clsx("flex w-full flex-col xl:px-4 xl:py-6", {
"gap-8": !restrictedMode,
})}
>
<AccountSummary
api={api}
locked={locked}
Expand All @@ -137,66 +143,80 @@ export const Dashboard = ({
availableToWithdraw={availableToWithdraw}
availableRewards={availableRewards}
expiringRewards={expiringRewards}
restrictedMode={restrictedMode}
/>
<Tabs
selectedKey={tab}
onSelectionChange={setTab}
className="group border-neutral-600/50 data-[empty]:my-[5dvh] data-[empty]:border data-[empty]:bg-white/10 data-[empty]:p-4 sm:p-4 data-[empty]:sm:my-0 data-[empty]:sm:border-0 data-[empty]:sm:bg-transparent data-[empty]:sm:p-0"
{...(tab === TabIds.Empty && { "data-empty": true })}
>
<h1 className="my-4 hidden text-center text-xl/tight font-light group-data-[empty]:mb-10 group-data-[empty]:block sm:mb-6 sm:text-3xl group-data-[empty]:sm:mb-6 lg:my-14 lg:text-5xl">
Choose Your Journey
</h1>
<TabList className="sticky top-header-height z-10 flex flex-row items-stretch justify-center group-data-[empty]:mx-auto group-data-[empty]:max-w-7xl group-data-[empty]:flex-col group-data-[empty]:gap-8 group-data-[empty]:sm:flex-row group-data-[empty]:sm:gap-2">
<Tab id={TabIds.Empty} className="hidden" />
<Journey
longText="Oracle Integrity Staking (OIS)"
shortText="OIS"
image={ois}
id={TabIds.IntegrityStaking}
>
<span>Secure the Oracle</span>
<br />
<span className="font-semibold">to Earn Rewards</span>
</Journey>
<Journey
longText="Pyth Governance"
shortText="Governance"
image={governanceImage}
id={TabIds.Governance}
>
<span>Gain Voting Power</span>
<br />
<span className="font-semibold">for Governance</span>
</Journey>
</TabList>
<TabPanel id={TabIds.Empty}></TabPanel>
<TabPanel id={TabIds.IntegrityStaking}>
<OracleIntegrityStaking
api={api}
currentEpoch={currentEpoch}
availableToStake={availableToStakeIntegrity}
locked={locked}
warmup={integrityStakingWarmup}
staked={integrityStakingStaked}
cooldown={integrityStakingCooldown}
cooldown2={integrityStakingCooldown2}
publishers={integrityStakingPublishers}
yieldRate={yieldRate}
/>
</TabPanel>
<TabPanel id={TabIds.Governance}>
<Governance
api={api}
currentEpoch={currentEpoch}
availableToStake={availableToStakeGovernance}
warmup={governance.warmup}
staked={governance.staked}
cooldown={governance.cooldown}
cooldown2={governance.cooldown2}
/>
</TabPanel>
</Tabs>
{restrictedMode ? (
<Governance
api={api}
currentEpoch={currentEpoch}
availableToStake={availableToStakeGovernance}
warmup={governance.warmup}
staked={governance.staked}
cooldown={governance.cooldown}
cooldown2={governance.cooldown2}
restrictedMode
/>
) : (
<Tabs
selectedKey={tab}
onSelectionChange={setTab}
className="group border-neutral-600/50 data-[empty]:my-[5dvh] data-[empty]:border data-[empty]:bg-white/10 data-[empty]:p-4 sm:p-4 data-[empty]:sm:my-0 data-[empty]:sm:border-0 data-[empty]:sm:bg-transparent data-[empty]:sm:p-0"
{...(tab === TabIds.Empty && { "data-empty": true })}
>
<h1 className="my-4 hidden text-center text-xl/tight font-light group-data-[empty]:mb-10 group-data-[empty]:block sm:mb-6 sm:text-3xl group-data-[empty]:sm:mb-6 lg:my-14 lg:text-5xl">
Choose Your Journey
</h1>
<TabList className="sticky top-header-height z-10 flex flex-row items-stretch justify-center group-data-[empty]:mx-auto group-data-[empty]:max-w-7xl group-data-[empty]:flex-col group-data-[empty]:gap-8 group-data-[empty]:sm:flex-row group-data-[empty]:sm:gap-2">
<Tab id={TabIds.Empty} className="hidden" />
<Journey
longText="Oracle Integrity Staking (OIS)"
shortText="OIS"
image={ois}
id={TabIds.IntegrityStaking}
>
<span>Secure the Oracle</span>
<br />
<span className="font-semibold">to Earn Rewards</span>
</Journey>
<Journey
longText="Pyth Governance"
shortText="Governance"
image={governanceImage}
id={TabIds.Governance}
>
<span>Gain Voting Power</span>
<br />
<span className="font-semibold">for Governance</span>
</Journey>
</TabList>
<TabPanel id={TabIds.Empty}></TabPanel>
<TabPanel id={TabIds.IntegrityStaking}>
<OracleIntegrityStaking
api={api}
currentEpoch={currentEpoch}
availableToStake={availableToStakeIntegrity}
locked={locked}
warmup={integrityStakingWarmup}
staked={integrityStakingStaked}
cooldown={integrityStakingCooldown}
cooldown2={integrityStakingCooldown2}
publishers={integrityStakingPublishers}
yieldRate={yieldRate}
/>
</TabPanel>
<TabPanel id={TabIds.Governance}>
<Governance
api={api}
currentEpoch={currentEpoch}
availableToStake={availableToStakeGovernance}
warmup={governance.warmup}
staked={governance.staked}
cooldown={governance.cooldown}
cooldown2={governance.cooldown2}
/>
</TabPanel>
</Tabs>
)}
</main>
);
};
Expand Down
9 changes: 7 additions & 2 deletions apps/staking/src/components/Governance/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ type Props = {
staked: bigint;
cooldown: bigint;
cooldown2: bigint;
restrictedMode?: boolean | undefined;
};

export const Governance = ({
Expand All @@ -20,6 +21,7 @@ export const Governance = ({
staked,
cooldown,
cooldown2,
restrictedMode,
}: Props) => (
<ProgramSection
name="Pyth Governance"
Expand All @@ -33,8 +35,6 @@ export const Governance = ({
staked,
cooldown,
cooldown2,
stake: api.type === ApiStateType.Loaded ? api.stakeGovernance : undefined,
stakeDescription: "Stake funds to participate in governance votes",
cancelWarmup:
api.type === ApiStateType.Loaded
? api.cancelWarmupGovernance
Expand All @@ -44,6 +44,11 @@ export const Governance = ({
unstake:
api.type === ApiStateType.Loaded ? api.unstakeGovernance : undefined,
unstakeDescription: "Unstake tokens from the Governance program",
...(!restrictedMode && {
stake:
api.type === ApiStateType.Loaded ? api.stakeGovernance : undefined,
stakeDescription: "Stake funds to participate in governance votes",
}),
}}
/>
);
6 changes: 5 additions & 1 deletion apps/staking/src/components/Header/current-stake-account.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
"use client";

import clsx from "clsx";
import { useSelectedLayoutSegment } from "next/navigation";
import { type HTMLProps } from "react";

import { VPN_BLOCKED_SEGMENT } from "../../config/isomorphic";
import { StateType as ApiStateType, useApi } from "../../hooks/use-api";
import { CopyButton } from "../CopyButton";
import { TruncatedKey } from "../TruncatedKey";
Expand All @@ -11,9 +13,11 @@ export const CurrentStakeAccount = ({
className,
...props
}: HTMLProps<HTMLDivElement>) => {
const segment = useSelectedLayoutSegment();
const isBlocked = segment === VPN_BLOCKED_SEGMENT;
const api = useApi();

return api.type === ApiStateType.Loaded ? (
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",
Expand Down
Loading

0 comments on commit 328c48b

Please sign in to comment.