Skip to content

Commit 12536a5

Browse files
authored
Merge pull request #1998 from cprussin/enable-governance-only
feat(staking): allow governance only for some regions
2 parents 4b08055 + 0c65ca2 commit 12536a5

File tree

11 files changed

+110
-54
lines changed

11 files changed

+110
-54
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { GeoBlockedHome as default } from "../../components/Home";
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { GovernanceOnlyHome as default } from "../../components/Home";

apps/staking/src/app/restricted-mode/page.tsx

Lines changed: 0 additions & 1 deletion
This file was deleted.

apps/staking/src/components/AccountSummary/index.tsx

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ type Props = {
4343
availableRewards: bigint;
4444
expiringRewards: Date | undefined;
4545
availableToWithdraw: bigint;
46-
restrictedMode?: boolean | undefined;
46+
enableGovernance: boolean;
47+
enableOis: boolean;
4748
integrityStakingWarmup: bigint;
4849
integrityStakingStaked: bigint;
4950
integrityStakingCooldown: bigint;
@@ -61,7 +62,8 @@ export const AccountSummary = ({
6162
availableToWithdraw,
6263
availableRewards,
6364
expiringRewards,
64-
restrictedMode,
65+
enableGovernance,
66+
enableOis,
6567
integrityStakingWarmup,
6668
integrityStakingStaked,
6769
integrityStakingCooldown,
@@ -131,7 +133,7 @@ export const AccountSummary = ({
131133
</>
132134
)}
133135
<div className="mt-3 flex flex-row items-center gap-4 sm:mt-8">
134-
{!restrictedMode && (
136+
{(enableGovernance || enableOis) && (
135137
<TransferButton
136138
actionName="Add tokens"
137139
actionDescription="Add funds to your balance"
@@ -167,7 +169,7 @@ export const AccountSummary = ({
167169
className="xl:hidden"
168170
/>
169171
)}
170-
{!restrictedMode && (
172+
{enableOis && (
171173
<DialogTrigger>
172174
<Button variant="secondary" className="xl:hidden">
173175
Claim
@@ -188,7 +190,7 @@ export const AccountSummary = ({
188190
)}
189191
</div>
190192
</div>
191-
{restrictedMode && api.type === ApiStateType.Loaded && (
193+
{!enableOis && api.type === ApiStateType.Loaded && (
192194
<OisUnstake
193195
api={api}
194196
className="max-w-sm xl:hidden"
@@ -208,7 +210,7 @@ export const AccountSummary = ({
208210
<WithdrawButton api={api} max={availableToWithdraw} size="small" />
209211
}
210212
/>
211-
{restrictedMode && api.type === ApiStateType.Loaded && (
213+
{!enableOis && api.type === ApiStateType.Loaded && (
212214
<OisUnstake
213215
api={api}
214216
warmup={integrityStakingWarmup}
@@ -218,7 +220,7 @@ export const AccountSummary = ({
218220
currentEpoch={currentEpoch}
219221
/>
220222
)}
221-
{!restrictedMode && (
223+
{enableOis && (
222224
<BalanceCategory
223225
name="Available Rewards"
224226
amount={availableRewards}

apps/staking/src/components/Dashboard/index.tsx

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ type Props = {
5050
integrityStakingPublishers: ComponentProps<
5151
typeof OracleIntegrityStaking
5252
>["publishers"];
53-
restrictedMode?: boolean | undefined;
53+
enableGovernance: boolean;
54+
enableOis: boolean;
5455
};
5556

5657
export const Dashboard = ({
@@ -65,7 +66,8 @@ export const Dashboard = ({
6566
integrityStakingPublishers,
6667
unlockSchedule,
6768
yieldRate,
68-
restrictedMode,
69+
enableGovernance,
70+
enableOis,
6971
}: Props) => {
7072
const [tab, setTab] = useState<TabId>(TabIds.Empty);
7173

@@ -138,7 +140,7 @@ export const Dashboard = ({
138140
<>
139141
<main
140142
className={clsx("flex w-full flex-col gap-8 xl:px-4 xl:py-6", {
141-
"sm:gap-0": restrictedMode,
143+
"sm:gap-0": !enableOis,
142144
})}
143145
>
144146
<AccountSummary
@@ -151,25 +153,15 @@ export const Dashboard = ({
151153
availableToWithdraw={availableToWithdraw}
152154
availableRewards={availableRewards}
153155
expiringRewards={expiringRewards}
154-
restrictedMode={restrictedMode}
156+
enableGovernance={enableGovernance}
157+
enableOis={enableOis}
155158
integrityStakingWarmup={integrityStakingWarmup}
156159
integrityStakingStaked={integrityStakingStaked}
157160
integrityStakingCooldown={integrityStakingCooldown}
158161
integrityStakingCooldown2={integrityStakingCooldown2}
159162
currentEpoch={currentEpoch}
160163
/>
161-
{restrictedMode ? (
162-
<Governance
163-
api={api}
164-
currentEpoch={currentEpoch}
165-
availableToStake={availableToStakeGovernance}
166-
warmup={governance.warmup}
167-
staked={governance.staked}
168-
cooldown={governance.cooldown}
169-
cooldown2={governance.cooldown2}
170-
restrictedMode
171-
/>
172-
) : (
164+
{enableOis ? (
173165
<Tabs
174166
selectedKey={tab}
175167
onSelectionChange={setTab}
@@ -229,6 +221,17 @@ export const Dashboard = ({
229221
/>
230222
</TabPanel>
231223
</Tabs>
224+
) : (
225+
<Governance
226+
api={api}
227+
currentEpoch={currentEpoch}
228+
availableToStake={availableToStakeGovernance}
229+
warmup={governance.warmup}
230+
staked={governance.staked}
231+
cooldown={governance.cooldown}
232+
cooldown2={governance.cooldown2}
233+
allowStaking={enableGovernance}
234+
/>
232235
)}
233236
</main>
234237
<Disclosure />

apps/staking/src/components/Governance/index.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ type Props = {
1212
staked: bigint;
1313
cooldown: bigint;
1414
cooldown2: bigint;
15-
restrictedMode?: boolean | undefined;
15+
allowStaking?: boolean | undefined;
1616
};
1717

1818
export const Governance = ({
@@ -23,10 +23,10 @@ export const Governance = ({
2323
staked,
2424
cooldown,
2525
cooldown2,
26-
restrictedMode,
26+
allowStaking,
2727
}: Props) => (
2828
<ProgramSection
29-
className={clsx({ "border-t sm:border-t-0": restrictedMode })}
29+
className={clsx({ "border-t sm:border-t-0": !allowStaking })}
3030
name="Pyth Governance"
3131
helpDialog={<GovernanceGuide />}
3232
tagline="Vote and Influence the Network"
@@ -47,7 +47,7 @@ export const Governance = ({
4747
unstake:
4848
api.type === ApiStateType.Loaded ? api.unstakeGovernance : undefined,
4949
unstakeDescription: "Unstake tokens from the Governance program",
50-
...(!restrictedMode && {
50+
...(allowStaking && {
5151
stake:
5252
api.type === ApiStateType.Loaded ? api.stakeGovernance : undefined,
5353
stakeDescription: "Stake funds to participate in governance votes",

apps/staking/src/components/Home/index.tsx

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,34 @@ const ONE_SECOND_IN_MS = 1000;
2020
const ONE_MINUTE_IN_MS = 60 * ONE_SECOND_IN_MS;
2121
const REFRESH_INTERVAL = 1 * ONE_MINUTE_IN_MS;
2222

23-
export const Home = () => <HomeImpl />;
24-
export const RestrictedMode = () => <HomeImpl restrictedMode />;
23+
export const Home = () => <HomeImpl enableGovernance enableOis />;
24+
export const GeoBlockedHome = () => <HomeImpl />;
25+
export const GovernanceOnlyHome = () => <HomeImpl enableGovernance />;
2526

2627
type HomeImplProps = {
27-
restrictedMode?: boolean | undefined;
28+
enableGovernance?: boolean | undefined;
29+
enableOis?: boolean | undefined;
2830
};
2931

30-
export const HomeImpl = ({ restrictedMode }: HomeImplProps) => {
32+
export const HomeImpl = ({ enableGovernance, enableOis }: HomeImplProps) => {
3133
const isSSR = useIsSSR();
3234

33-
return isSSR ? <Loading /> : <MountedHome restrictedMode={restrictedMode} />;
35+
return isSSR ? (
36+
<Loading />
37+
) : (
38+
<MountedHome
39+
enableGovernance={enableGovernance ?? false}
40+
enableOis={enableOis ?? false}
41+
/>
42+
);
3443
};
3544

3645
type MountedHomeProps = {
37-
restrictedMode?: boolean | undefined;
46+
enableGovernance: boolean;
47+
enableOis: boolean;
3848
};
3949

40-
const MountedHome = ({ restrictedMode }: MountedHomeProps) => {
50+
const MountedHome = ({ enableGovernance, enableOis }: MountedHomeProps) => {
4151
const api = useApi();
4252

4353
switch (api.type) {
@@ -56,20 +66,26 @@ const MountedHome = ({ restrictedMode }: MountedHomeProps) => {
5666
case ApiStateType.LoadedNoStakeAccount:
5767
case ApiStateType.Loaded: {
5868
return (
59-
<StakeAccountLoadedHome restrictedMode={restrictedMode} api={api} />
69+
<StakeAccountLoadedHome
70+
enableGovernance={enableGovernance}
71+
enableOis={enableOis}
72+
api={api}
73+
/>
6074
);
6175
}
6276
}
6377
};
6478

6579
type StakeAccountLoadedHomeProps = {
6680
api: States[ApiStateType.Loaded] | States[ApiStateType.LoadedNoStakeAccount];
67-
restrictedMode?: boolean | undefined;
81+
enableGovernance: boolean;
82+
enableOis: boolean;
6883
};
6984

7085
const StakeAccountLoadedHome = ({
7186
api,
72-
restrictedMode,
87+
enableGovernance,
88+
enableOis,
7389
}: StakeAccountLoadedHomeProps) => {
7490
const data = useData(api.dashboardDataCacheKey, api.loadData, {
7591
refreshInterval: REFRESH_INTERVAL,
@@ -87,7 +103,12 @@ const StakeAccountLoadedHome = ({
87103

88104
case DashboardDataStateType.Loaded: {
89105
return (
90-
<Dashboard {...data.data} api={api} restrictedMode={restrictedMode} />
106+
<Dashboard
107+
{...data.data}
108+
api={api}
109+
enableGovernance={enableGovernance}
110+
enableOis={enableOis}
111+
/>
91112
);
92113
}
93114
}

apps/staking/src/components/Root/restricted-region-banner.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@
22

33
import { useSelectedLayoutSegment } from "next/navigation";
44

5-
import { RESTRICTED_MODE_SEGMENT } from "../../config/isomorphic";
5+
import {
6+
GEO_BLOCKED_SEGMENT,
7+
GOVERNANCE_ONLY_SEGMENT,
8+
} from "../../config/isomorphic";
69
import { Link } from "../Link";
710

811
export const RestrictedRegionBanner = () => {
912
const segment = useSelectedLayoutSegment();
10-
const isRestrictedMode = segment === RESTRICTED_MODE_SEGMENT;
13+
const isRestrictedMode =
14+
segment === GEO_BLOCKED_SEGMENT || segment === GOVERNANCE_ONLY_SEGMENT;
1115

1216
return isRestrictedMode ? (
1317
<div className="mx-auto mt-8 flex max-w-3xl flex-col gap-2 bg-red-900 px-8 py-6">

apps/staking/src/config/isomorphic.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,26 @@
1313
export const IS_PRODUCTION_BUILD = process.env.NODE_ENV === "production";
1414

1515
/**
16-
* Region or VPN-blocked requests will be redirected here if they are eligible
17-
* for "restricted mode" (aka only allowing withdrawals). This is used in the
16+
* Region blocked requests will be rewritten here. This is used in the
1817
* middleware to implement the block, and also consumed in any components that
1918
* are part of the page layout but need to know if the request is blocked from
2019
* accessing the app, such as the WalletButton in the app header.
2120
*
2221
* Don't change unless you also change the relevant app route path to match.
2322
*/
24-
export const RESTRICTED_MODE_SEGMENT = "restricted-mode";
23+
export const GEO_BLOCKED_SEGMENT = "geo-blocked";
2524

2625
/**
27-
* Similar to `RESTRICTED_MODE_SEGMENT`; this is where vpn-blocked traffic will
28-
* be rewritten to if it isn't eligible for restricted mode.
26+
* Similar to `GEO_BLOCKED_SEGMENT`; this is where governance-only region
27+
* requests are rewritten to.
28+
*
29+
* Don't change unless you also change the relevant app route path to match.
30+
*/
31+
export const GOVERNANCE_ONLY_SEGMENT = "governance-only";
32+
33+
/**
34+
* Similar to `GEO_BLOCKED_SEGMENT`; this is where vpn-blocked traffic will be
35+
* rewritten to.
2936
*
3037
* Don't change unless you also change the relevant app route path to match.
3138
*/

apps/staking/src/config/server.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ export const WALLETCONNECT_PROJECT_ID = demandInProduction(
5454
export const MAINNET_RPC = process.env.MAINNET_RPC;
5555
export const HERMES_URL = getOr("HERMES_URL", "https://hermes.pyth.network");
5656
export const BLOCKED_REGIONS = transformOr("BLOCKED_REGIONS", fromCsv, []);
57+
export const GOVERNANCE_ONLY_REGIONS = transformOr(
58+
"GOVERNANCE_ONLY_REGIONS",
59+
fromCsv,
60+
[],
61+
);
5762
export const PROXYCHECK_API_KEY = demandInProduction("PROXYCHECK_API_KEY");
5863

5964
class MissingEnvironmentError extends Error {

apps/staking/src/middleware.ts

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,31 @@ import { type NextRequest, NextResponse } from "next/server";
22
import ProxyCheck from "proxycheck-ts";
33

44
import {
5-
RESTRICTED_MODE_SEGMENT,
5+
GEO_BLOCKED_SEGMENT,
6+
GOVERNANCE_ONLY_SEGMENT,
67
VPN_BLOCKED_SEGMENT,
78
} from "./config/isomorphic";
8-
import { BLOCKED_REGIONS, PROXYCHECK_API_KEY } from "./config/server";
9+
import {
10+
BLOCKED_REGIONS,
11+
GOVERNANCE_ONLY_REGIONS,
12+
PROXYCHECK_API_KEY,
13+
} from "./config/server";
914

10-
const RESTRICTED_MODE_PATH = `/${RESTRICTED_MODE_SEGMENT}`;
11-
const VPN_BLOCK_PATH = `/${VPN_BLOCKED_SEGMENT}`;
15+
const GEO_BLOCKED_PATH = `/${GEO_BLOCKED_SEGMENT}`;
16+
const GOVERNANCE_ONLY_PATH = `/${GOVERNANCE_ONLY_SEGMENT}`;
17+
const VPN_BLOCKED_PATH = `/${VPN_BLOCKED_SEGMENT}`;
1218

1319
const proxyCheckClient = PROXYCHECK_API_KEY
1420
? new ProxyCheck({ api_key: PROXYCHECK_API_KEY })
1521
: undefined;
1622

1723
export const middleware = async (request: NextRequest) => {
1824
if (await isProxyBlocked(request)) {
19-
return rewrite(request, VPN_BLOCK_PATH);
25+
return rewrite(request, VPN_BLOCKED_PATH);
26+
} else if (isGovernanceOnlyRegion(request)) {
27+
return rewrite(request, GOVERNANCE_ONLY_PATH);
2028
} else if (isRegionBlocked(request)) {
21-
return rewrite(request, RESTRICTED_MODE_PATH);
29+
return rewrite(request, GEO_BLOCKED_PATH);
2230
} else if (isBlockedSegment(request)) {
2331
return rewrite(request, "/not-found");
2432
} else {
@@ -29,6 +37,10 @@ export const middleware = async (request: NextRequest) => {
2937
const rewrite = (request: NextRequest, path: string) =>
3038
NextResponse.rewrite(new URL(path, request.url));
3139

40+
const isGovernanceOnlyRegion = ({ geo }: NextRequest) =>
41+
geo?.country !== undefined &&
42+
GOVERNANCE_ONLY_REGIONS.includes(geo.country.toLowerCase());
43+
3244
const isRegionBlocked = ({ geo }: NextRequest) =>
3345
geo?.country !== undefined &&
3446
BLOCKED_REGIONS.includes(geo.country.toLowerCase());
@@ -43,8 +55,9 @@ const isProxyBlocked = async ({ ip }: NextRequest) => {
4355
};
4456

4557
const isBlockedSegment = ({ nextUrl: { pathname } }: NextRequest) =>
46-
pathname.startsWith(`/${VPN_BLOCKED_SEGMENT}`) ||
47-
pathname.startsWith(`/${RESTRICTED_MODE_SEGMENT}`);
58+
pathname.startsWith(VPN_BLOCKED_PATH) ||
59+
pathname.startsWith(GEO_BLOCKED_PATH) ||
60+
pathname.startsWith(GOVERNANCE_ONLY_PATH);
4861

4962
export const config = {
5063
// Next.js requires that this is a static string and fails to read it if it's

0 commit comments

Comments
 (0)