Skip to content

Commit 7643f98

Browse files
authored
Merge pull request #1989 from cprussin/add-devnet-switch
feat(staking): add a switch to flip between mainnet & devnet
2 parents cec695e + b83ab65 commit 7643f98

File tree

11 files changed

+212
-97
lines changed

11 files changed

+212
-97
lines changed

apps/staking/src/app/api/v1/cmc/supply/route.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,17 @@ import { clusterApiUrl, Connection } from "@solana/web3.js";
44
import type { NextRequest } from "next/server";
55
import { z } from "zod";
66

7-
import { IS_MAINNET, RPC } from "../../../../../config/server";
7+
import { MAINNET_RPC } from "../../../../../config/server";
88

99
const querySchema = z.enum(["totalSupply", "circulatingSupply"]);
1010

1111
export async function GET(req: NextRequest) {
12+
const isMainnet = req.nextUrl.searchParams.get("devnet") !== "true";
1213
const stakingClient = new PythStakingClient({
1314
connection: new Connection(
14-
RPC ??
15-
clusterApiUrl(
16-
IS_MAINNET
17-
? WalletAdapterNetwork.Mainnet
18-
: WalletAdapterNetwork.Devnet,
19-
),
15+
isMainnet && MAINNET_RPC !== undefined
16+
? MAINNET_RPC
17+
: clusterApiUrl(WalletAdapterNetwork.Devnet),
2018
{
2119
httpHeaders: {
2220
Origin: req.nextUrl.origin,

apps/staking/src/app/api/v1/locked_accounts/route.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { clusterApiUrl, Connection, PublicKey } from "@solana/web3.js";
44
import type { NextRequest } from "next/server";
55
import { z } from "zod";
66

7-
import { IS_MAINNET, RPC } from "../../../../config/server";
7+
import { MAINNET_RPC } from "../../../../config/server";
88
import { tokensToString } from "../../../../tokens";
99

1010
const UnlockScheduleSchema = z.object({
@@ -35,14 +35,12 @@ const isValidPublicKey = (publicKey: string) => {
3535
};
3636

3737
export async function GET(req: NextRequest) {
38+
const isMainnet = req.nextUrl.searchParams.get("devnet") !== "true";
3839
const stakingClient = new PythStakingClient({
3940
connection: new Connection(
40-
RPC ??
41-
clusterApiUrl(
42-
IS_MAINNET
43-
? WalletAdapterNetwork.Mainnet
44-
: WalletAdapterNetwork.Devnet,
45-
),
41+
isMainnet && MAINNET_RPC !== undefined
42+
? MAINNET_RPC
43+
: clusterApiUrl(WalletAdapterNetwork.Devnet),
4644
{
4745
httpHeaders: {
4846
Origin: req.nextUrl.origin,

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

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,13 @@ export const Menu = <T extends object>({
2323
...props
2424
}: MenuProps<T>) => (
2525
<Popover
26-
className="data-[entering]:animate-in data-[exiting]:animate-out data-[entering]:fade-in data-[exiting]:fade-out"
26+
className={clsx(
27+
"flex origin-top-right flex-col border border-neutral-400 bg-pythpurple-100 py-2 text-sm text-pythpurple-950 shadow shadow-neutral-400 data-[entering]:animate-in data-[exiting]:animate-out data-[entering]:fade-in data-[exiting]:fade-out",
28+
className,
29+
)}
2730
{...(placement && { placement })}
2831
>
29-
<BaseMenu
30-
className={clsx(
31-
"flex origin-top-right flex-col border border-neutral-400 bg-pythpurple-100 py-2 text-sm text-pythpurple-950 shadow shadow-neutral-400 outline-none",
32-
className,
33-
)}
34-
{...props}
35-
/>
32+
<BaseMenu className="outline-none" {...props} />
3633
</Popover>
3734
);
3835

@@ -51,7 +48,7 @@ export const MenuItem = ({
5148
<BaseMenuItem
5249
textValue={textValue ?? (typeof children === "string" ? children : "")}
5350
className={clsx(
54-
"flex cursor-pointer items-center gap-2 whitespace-nowrap px-4 py-2 text-left data-[disabled]:cursor-default data-[focused]:bg-pythpurple-800/20 data-[has-submenu]:data-[open]:bg-pythpurple-800/10 data-[has-submenu]:data-[open]:data-[focused]:bg-pythpurple-800/20 focus:outline-none focus-visible:outline-none",
51+
"flex cursor-pointer items-center gap-2 whitespace-nowrap px-4 py-2 text-left outline-none data-[disabled]:cursor-default data-[focused]:bg-pythpurple-800/20 data-[has-submenu]:data-[open]:bg-pythpurple-800/10 data-[has-submenu]:data-[open]:data-[focused]:bg-pythpurple-800/20",
5552
className,
5653
)}
5754
{...props}

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

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ import {
3030
Label,
3131
TextField,
3232
Form,
33-
Switch,
3433
MenuTrigger,
3534
} from "react-aria-components";
3635

@@ -50,6 +49,7 @@ import { Select } from "../Select";
5049
import { SparkChart } from "../SparkChart";
5150
import { StakingTimeline } from "../StakingTimeline";
5251
import { Styled } from "../Styled";
52+
import { Switch } from "../Switch";
5353
import { Tokens } from "../Tokens";
5454
import { AmountType, TransferButton } from "../TransferButton";
5555
import { TruncatedKey } from "../TruncatedKey";
@@ -709,15 +709,8 @@ const PublisherList = ({
709709
<Switch
710710
isSelected={yoursFirst}
711711
onChange={updateYoursFirst}
712-
className="group flex cursor-pointer flex-row items-center gap-2"
713-
>
714-
<div className="whitespace-nowrap opacity-80">
715-
Show your positions first
716-
</div>
717-
<div className="h-8 w-16 flex-none rounded-full border border-neutral-400/50 bg-neutral-800/50 p-1 transition group-data-[selected]:border-pythpurple-600 group-data-[selected]:bg-pythpurple-600/10">
718-
<div className="aspect-square h-full rounded-full bg-neutral-400/50 transition group-data-[selected]:translate-x-8 group-data-[selected]:bg-pythpurple-600" />
719-
</div>
720-
</Switch>
712+
preLabel="Show your positions first"
713+
/>
721714
</div>
722715
</div>
723716

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

Lines changed: 42 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { GoogleAnalytics } from "@next/third-parties/google";
2-
import { WalletAdapterNetwork } from "@solana/wallet-adapter-base";
32
import clsx from "clsx";
43
import { Red_Hat_Text, Red_Hat_Mono } from "next/font/google";
5-
import type { ReactNode, CSSProperties } from "react";
4+
import type { ReactNode, CSSProperties, HTMLProps } from "react";
65

76
import { I18nProvider } from "./i18n-provider";
87
import { RestrictedRegionBanner } from "./restricted-region-banner";
@@ -11,12 +10,12 @@ import {
1110
GOOGLE_ANALYTICS_ID,
1211
AMPLITUDE_API_KEY,
1312
WALLETCONNECT_PROJECT_ID,
14-
RPC,
13+
MAINNET_RPC,
1514
HERMES_URL,
16-
IS_MAINNET,
1715
} from "../../config/server";
1816
import { ApiProvider } from "../../hooks/use-api";
1917
import { LoggerProvider } from "../../hooks/use-logger";
18+
import { NetworkProvider } from "../../hooks/use-network";
2019
import { Amplitude } from "../Amplitude";
2120
import { Footer } from "../Footer";
2221
import { Header } from "../Header";
@@ -40,49 +39,48 @@ type Props = {
4039
};
4140

4241
export const Root = ({ children }: Props) => (
42+
<HtmlWithProviders
43+
lang="en"
44+
dir="ltr"
45+
style={
46+
{
47+
"--header-height": "4rem",
48+
} as CSSProperties
49+
}
50+
className={clsx(
51+
"scroll-pt-header-height",
52+
redHatText.variable,
53+
redHatMono.variable,
54+
)}
55+
>
56+
<body className="grid min-h-dvh grid-rows-[auto_auto_1fr_auto] text-pythpurple-100 [background:radial-gradient(20rem_50rem_at_50rem_10rem,_rgba(119,_49,_234,_0.20)_0%,_rgba(17,_15,_35,_0.00)_100rem),_#0A0814] selection:bg-pythpurple-600/60">
57+
<Header className="z-10" />
58+
<RestrictedRegionBanner />
59+
<MaxWidth className="z-0 min-h-[calc(100dvh_-_var(--header-height))] py-8 sm:min-h-0">
60+
{children}
61+
</MaxWidth>
62+
<Footer className="z-10" />
63+
</body>
64+
{GOOGLE_ANALYTICS_ID && <GoogleAnalytics gaId={GOOGLE_ANALYTICS_ID} />}
65+
{AMPLITUDE_API_KEY && <Amplitude apiKey={AMPLITUDE_API_KEY} />}
66+
{!IS_PRODUCTION_SERVER && <ReportAccessibility />}
67+
</HtmlWithProviders>
68+
);
69+
70+
const HtmlWithProviders = ({ lang, ...props }: HTMLProps<HTMLHtmlElement>) => (
4371
<I18nProvider>
4472
<RouterProvider>
4573
<LoggerProvider>
46-
<WalletProvider
47-
walletConnectProjectId={WALLETCONNECT_PROJECT_ID}
48-
rpc={RPC}
49-
network={
50-
IS_MAINNET
51-
? WalletAdapterNetwork.Mainnet
52-
: WalletAdapterNetwork.Devnet
53-
}
54-
>
55-
<ApiProvider hermesUrl={HERMES_URL}>
56-
<html
57-
lang="en"
58-
dir="ltr"
59-
style={
60-
{
61-
"--header-height": "4rem",
62-
} as CSSProperties
63-
}
64-
className={clsx(
65-
"scroll-pt-header-height",
66-
redHatText.variable,
67-
redHatMono.variable,
68-
)}
69-
>
70-
<body className="grid min-h-dvh grid-rows-[auto_auto_1fr_auto] text-pythpurple-100 [background:radial-gradient(20rem_50rem_at_50rem_10rem,_rgba(119,_49,_234,_0.20)_0%,_rgba(17,_15,_35,_0.00)_100rem),_#0A0814] selection:bg-pythpurple-600/60">
71-
<Header className="z-10" />
72-
<RestrictedRegionBanner />
73-
<MaxWidth className="z-0 min-h-[calc(100dvh_-_var(--header-height))] py-8 sm:min-h-0">
74-
{children}
75-
</MaxWidth>
76-
<Footer className="z-10" />
77-
</body>
78-
{GOOGLE_ANALYTICS_ID && (
79-
<GoogleAnalytics gaId={GOOGLE_ANALYTICS_ID} />
80-
)}
81-
{AMPLITUDE_API_KEY && <Amplitude apiKey={AMPLITUDE_API_KEY} />}
82-
{!IS_PRODUCTION_SERVER && <ReportAccessibility />}
83-
</html>
84-
</ApiProvider>
85-
</WalletProvider>
74+
<NetworkProvider>
75+
<WalletProvider
76+
walletConnectProjectId={WALLETCONNECT_PROJECT_ID}
77+
mainnetRpc={MAINNET_RPC}
78+
>
79+
<ApiProvider hermesUrl={HERMES_URL}>
80+
<html lang={lang} {...props} />
81+
</ApiProvider>
82+
</WalletProvider>
83+
</NetworkProvider>
8684
</LoggerProvider>
8785
</RouterProvider>
8886
</I18nProvider>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import clsx from "clsx";
2+
import type { ComponentProps, ReactNode } from "react";
3+
import { Switch as BaseSwitch } from "react-aria-components";
4+
5+
type Props = Omit<ComponentProps<typeof BaseSwitch>, "children"> & {
6+
preLabel?: ReactNode;
7+
postLabel?: ReactNode;
8+
size?: "small";
9+
};
10+
11+
export const Switch = ({
12+
preLabel,
13+
postLabel,
14+
className,
15+
size,
16+
...props
17+
}: Props) => (
18+
<BaseSwitch
19+
className={clsx(
20+
"group flex cursor-pointer flex-row items-center gap-2",
21+
className,
22+
)}
23+
{...props}
24+
>
25+
{preLabel && <div className="whitespace-nowrap opacity-80">{preLabel}</div>}
26+
<div
27+
className={clsx(
28+
"flex-none rounded-full border border-neutral-400/50 bg-neutral-800/50 p-1 transition group-data-[selected]:border-pythpurple-600 group-data-[selected]:bg-pythpurple-600/10",
29+
size === "small" ? "h-6 w-10" : "h-8 w-16",
30+
)}
31+
>
32+
<div
33+
className={clsx(
34+
"aspect-square h-full rounded-full bg-neutral-400/50 transition group-data-[selected]:bg-pythpurple-600",
35+
size === "small"
36+
? "group-data-[selected]:translate-x-4"
37+
: "group-data-[selected]:translate-x-8",
38+
)}
39+
/>
40+
</div>
41+
{postLabel && (
42+
<div className="whitespace-nowrap opacity-80">{postLabel}</div>
43+
)}
44+
</BaseSwitch>
45+
);

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
SubmenuTrigger,
2727
Header,
2828
Collection,
29+
MenuItem as BaseMenuItem,
2930
} from "react-aria-components";
3031

3132
import { VPN_BLOCKED_SEGMENT } from "../../config/isomorphic";
@@ -36,9 +37,11 @@ import {
3637
} from "../../hooks/use-api";
3738
import { StateType as DataStateType, useData } from "../../hooks/use-data";
3839
import { useLogger } from "../../hooks/use-logger";
40+
import { useNetwork } from "../../hooks/use-network";
3941
import { usePrimaryDomain } from "../../hooks/use-primary-domain";
4042
import { Button } from "../Button";
4143
import { Menu, MenuItem, Section, Separator } from "../Menu";
44+
import { Switch } from "../Switch";
4245
import { TruncatedKey } from "../TruncatedKey";
4346

4447
const ONE_SECOND_IN_MS = 1000;
@@ -106,6 +109,7 @@ const ConnectedButton = ({
106109
logger.error(error);
107110
});
108111
}, [wallet, logger]);
112+
const { isMainnet, toggleMainnet } = useNetwork();
109113

110114
return (
111115
<MenuTrigger>
@@ -139,6 +143,20 @@ const ConnectedButton = ({
139143
Disconnect
140144
</MenuItem>
141145
</Section>
146+
<Separator />
147+
<Section>
148+
<BaseMenuItem
149+
className="outline-none data-[focused]:bg-pythpurple-800/20"
150+
onAction={toggleMainnet}
151+
>
152+
<Switch
153+
isSelected={isMainnet}
154+
postLabel="Mainnet"
155+
className="px-4 py-1"
156+
size="small"
157+
/>
158+
</BaseMenuItem>
159+
</Section>
142160
</Menu>
143161
</MenuTrigger>
144162
);

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

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,35 @@ import {
2020
import { clusterApiUrl } from "@solana/web3.js";
2121
import { type ReactNode, useMemo } from "react";
2222

23+
import { useNetwork } from "../../hooks/use-network";
2324
import { metadata } from "../../metadata";
2425

2526
type Props = {
26-
network: WalletAdapterNetwork.Devnet | WalletAdapterNetwork.Mainnet;
2727
children?: ReactNode | ReactNode[] | undefined;
2828
walletConnectProjectId?: string | undefined;
29-
rpc?: string | undefined;
29+
mainnetRpc?: string | undefined;
3030
};
3131

3232
export const WalletProvider = ({
33-
network,
3433
children,
3534
walletConnectProjectId,
36-
rpc,
35+
mainnetRpc,
3736
}: Props) => {
38-
const endpoint = useMemo(() => rpc ?? clusterApiUrl(network), [rpc, network]);
37+
const { isMainnet } = useNetwork();
38+
39+
const network = useMemo(
40+
() =>
41+
isMainnet ? WalletAdapterNetwork.Mainnet : WalletAdapterNetwork.Devnet,
42+
[isMainnet],
43+
);
44+
45+
const endpoint = useMemo(
46+
() =>
47+
network === WalletAdapterNetwork.Mainnet && mainnetRpc !== undefined
48+
? mainnetRpc
49+
: clusterApiUrl(network),
50+
[mainnetRpc, network],
51+
);
3952

4053
const wallets = useMemo(
4154
() => [

apps/staking/src/config/server.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,7 @@ export const AMPLITUDE_API_KEY = demandInProduction("AMPLITUDE_API_KEY");
5151
export const WALLETCONNECT_PROJECT_ID = demandInProduction(
5252
"WALLETCONNECT_PROJECT_ID",
5353
);
54-
export const RPC = process.env.RPC;
55-
export const IS_MAINNET = process.env.IS_MAINNET !== undefined;
54+
export const MAINNET_RPC = process.env.MAINNET_RPC;
5655
export const HERMES_URL = getOr("HERMES_URL", "https://hermes.pyth.network");
5756
export const BLOCKED_REGIONS = transformOr("BLOCKED_REGIONS", fromCsv, []);
5857
export const PROXYCHECK_API_KEY = demandInProduction("PROXYCHECK_API_KEY");

0 commit comments

Comments
 (0)