Skip to content

Commit 2f7d072

Browse files
authored
Merge pull request #2019 from cprussin/add-changelog
feat(staking): add changelog
2 parents 37fb9b6 + 667c4fc commit 2f7d072

File tree

5 files changed

+255
-11
lines changed

5 files changed

+255
-11
lines changed
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
"use client";
2+
3+
import type { ReactNode } from "react";
4+
import { useDateFormatter } from "react-aria";
5+
6+
import { useChangelog } from "../../hooks/use-changelog";
7+
import { Link } from "../Link";
8+
import { ModalDialog } from "../ModalDialog";
9+
10+
export const Changelog = () => {
11+
const { isOpen, toggleOpen } = useChangelog();
12+
13+
return (
14+
<ModalDialog title="Changelog" isOpen={isOpen} onOpenChange={toggleOpen}>
15+
<ul className="flex max-w-prose flex-col divide-y divide-neutral-600/50">
16+
{messages.map(({ id, message }) => (
17+
<li key={id}>{message}</li>
18+
))}
19+
</ul>
20+
</ModalDialog>
21+
);
22+
};
23+
24+
type ChangelogMessageProps = {
25+
date: Date;
26+
children: ReactNode | ReactNode[];
27+
};
28+
29+
export const ChangelogMessage = ({ date, children }: ChangelogMessageProps) => {
30+
const dateFormatter = useDateFormatter({
31+
year: "numeric",
32+
month: "short",
33+
day: "numeric",
34+
});
35+
36+
return (
37+
<section className="py-8">
38+
<h2 className="text-sm uppercase text-pythpurple-400">
39+
{dateFormatter.format(date)}
40+
</h2>
41+
{children}
42+
</section>
43+
);
44+
};
45+
46+
type ChangelogSectionProps = {
47+
title: ReactNode;
48+
children: ReactNode | ReactNode[];
49+
};
50+
51+
export const ChangelogSection = ({
52+
title,
53+
children,
54+
}: ChangelogSectionProps) => (
55+
<section className="mt-4">
56+
<h3 className="text-lg font-semibold text-white">{title}</h3>
57+
<div className="flex flex-col gap-2 pl-2 text-sm opacity-70">
58+
{children}
59+
</div>
60+
</section>
61+
);
62+
63+
export const messages = [
64+
{
65+
id: 1,
66+
message: (
67+
<ChangelogMessage date={new Date("2024-10-10")}>
68+
<ChangelogSection title="Milestones">
69+
<div>
70+
<p>
71+
We are pleased to announce the following Oracle Integrity Staking
72+
milestones:
73+
</p>
74+
<ul className="list-disc pl-8">
75+
<li>143M PYTH staked and securing DeFi.</li>
76+
<li>9.6K unique stakers participating.</li>
77+
<li>237K in PYTH programmatically distributed.</li>
78+
</ul>
79+
</div>
80+
<p>We’re thrilled to see so many community participants.</p>
81+
</ChangelogSection>
82+
<ChangelogSection title="New Features to the Staking Frontend">
83+
<ul className="list-disc pl-4">
84+
<li>
85+
New sort filter for publishers list. Publishers with self-stake
86+
are displayed first by default. You can sort by publisher details,
87+
pool composition, and more.
88+
</li>
89+
<li>
90+
Publishers interested in de-anonymizing themselves can have their
91+
names displayed in the publisher list.
92+
</li>
93+
<li>New OIS live stats added to navigation bar.</li>
94+
<li>
95+
New dialogue added under “Help” where you can view current program
96+
parameters.
97+
</li>
98+
<li>
99+
Option to remove PYTH from the smart contract program for parties
100+
with restricted access to the staking frontend.
101+
</li>
102+
<li>
103+
Full access to Pyth Governance for certain restricted
104+
jurisdictions.
105+
</li>
106+
<li>APYs are now shown as net of delegation fees.</li>
107+
<li>
108+
Updates to educational materials (all Guides and FAQs) for clarity
109+
and readability.
110+
</li>
111+
<li>
112+
New Oracle Integrity Staking{" "}
113+
<Link
114+
href="https://forum.pyth.network/c/oracle-integrity-staking-ois-discussion/8"
115+
className="underline"
116+
target="_blank"
117+
>
118+
discussion catalogue
119+
</Link>{" "}
120+
opened in Pyth DAO forum. Let the community know your thoughts and
121+
feedback!
122+
</li>
123+
</ul>
124+
</ChangelogSection>
125+
<ChangelogSection title="Security">
126+
<p>
127+
The Pyth contributors take security extremely seriously. The
128+
contract code is{" "}
129+
<Link
130+
href="https://github.com/pyth-network/governance/tree/main/staking/programs/staking"
131+
className="underline"
132+
target="_blank"
133+
>
134+
open source
135+
</Link>{" "}
136+
and the upgrade authority is governed by the Pyth DAO. The official{" "}
137+
<Link
138+
href="https://github.com/pyth-network/audit-reports/blob/main/2024_09_11/pyth_cip_final_report.pdf"
139+
className="underline"
140+
target="_blank"
141+
>
142+
audit report
143+
</Link>{" "}
144+
is publicly accessible. All on-chain contract codes are verified
145+
using{" "}
146+
<Link
147+
href="https://github.com/Ellipsis-Labs/solana-verifiable-build/"
148+
className="underline"
149+
target="_blank"
150+
>
151+
Solana verifiable build
152+
</Link>{" "}
153+
and the Pyth DAO governs the upgrade authority.
154+
</p>
155+
</ChangelogSection>
156+
<ChangelogSection title="Best Practices">
157+
<p>
158+
Please remember that publishers have priority for programmatic
159+
rewards distributions. By protocol design, if a pool’s stake cap is
160+
exceeded, the programmatic reward rate for other stakers
161+
participating in that pool will be lower than the Pyth DAO-set
162+
maximum reward rate.
163+
</p>
164+
</ChangelogSection>
165+
<ChangelogSection title="Acknowledgements">
166+
<p>
167+
The Pyth contributors are glad to see so many network participants
168+
getting involved with Oracle Integrity Staking to help secure the
169+
oracle and protect the wider DeFi industry. OIS wouldn’t be possible
170+
without you!
171+
</p>
172+
</ChangelogSection>
173+
<ChangelogSection title="Feedback">
174+
<p>
175+
Please reach out in the official{" "}
176+
<Link
177+
href="https://discord.com/invite/PythNetwork"
178+
className="underline"
179+
target="_blank"
180+
>
181+
Pyth Discord
182+
</Link>{" "}
183+
or the{" "}
184+
<Link
185+
href="https://forum.pyth.network"
186+
className="underline"
187+
target="_blank"
188+
>
189+
Pyth DAO Forum
190+
</Link>{" "}
191+
to share your questions, ideas, or feedback. We want to hear what
192+
you think.
193+
</p>
194+
</ChangelogSection>
195+
</ChangelogMessage>
196+
),
197+
},
198+
];

apps/staking/src/components/Header/help-menu.tsx

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { MenuTrigger, Button } from "react-aria-components";
99

1010
import { ProgramParameters } from "./program-parameters";
1111
import { StateType, useApi } from "../../hooks/use-api";
12+
import { useChangelog } from "../../hooks/use-changelog";
1213
import { GeneralFaq } from "../GeneralFaq";
1314
import { GovernanceGuide } from "../GovernanceGuide";
1415
import { Menu, MenuItem, Section, Separator } from "../Menu";
@@ -41,6 +42,7 @@ export const HelpMenu = () => {
4142
const openParameters = useCallback(() => {
4243
setParametersOpen(true);
4344
}, [setParametersOpen]);
45+
const { open: openChangelog } = useChangelog();
4446

4547
return (
4648
<>
@@ -73,17 +75,16 @@ export const HelpMenu = () => {
7375
Data Publisher Guide
7476
</MenuItem>
7577
</Section>
76-
{(api.type === StateType.Loaded ||
77-
api.type === StateType.LoadedNoStakeAccount) && (
78-
<>
79-
<Separator />
80-
<Section>
81-
<MenuItem onAction={openParameters}>
82-
Current Program Parameters
83-
</MenuItem>
84-
</Section>
85-
</>
86-
)}
78+
<Separator />
79+
<Section>
80+
{(api.type === StateType.Loaded ||
81+
api.type === StateType.LoadedNoStakeAccount) && (
82+
<MenuItem onAction={openParameters}>
83+
Current Program Parameters
84+
</MenuItem>
85+
)}
86+
<MenuItem onAction={openChangelog}>Changelog</MenuItem>
87+
</Section>
8788
</Menu>
8889
</MenuTrigger>
8990
<GeneralFaq isOpen={faqOpen} onOpenChange={setFaqOpen} />

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"use client";
2+
13
import { XMarkIcon } from "@heroicons/react/24/outline";
24
import clsx from "clsx";
35
import type { ComponentProps, ReactNode } from "react";

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { LoggerProvider } from "../../hooks/use-logger";
2020
import { NetworkProvider } from "../../hooks/use-network";
2121
import { ToastProvider } from "../../hooks/use-toast";
2222
import { Amplitude } from "../Amplitude";
23+
import { Changelog } from "../Changelog";
2324
import { Footer } from "../Footer";
2425
import { Header } from "../Header";
2526
import { MaxWidth } from "../MaxWidth";
@@ -64,6 +65,7 @@ export const Root = ({ children }: Props) => (
6465
</MaxWidth>
6566
<Footer className="z-10" />
6667
<ToastRegion />
68+
<Changelog />
6769
</body>
6870
{GOOGLE_ANALYTICS_ID && <GoogleAnalytics gaId={GOOGLE_ANALYTICS_ID} />}
6971
{AMPLITUDE_API_KEY && <Amplitude apiKey={AMPLITUDE_API_KEY} />}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { useLocalStorageValue } from "@react-hookz/web";
2+
import { useCallback, useMemo } from "react";
3+
4+
import { messages } from "../components/Changelog";
5+
6+
export const useChangelog = () => {
7+
const lastMessageSeen = useLocalStorageValue<number>(
8+
"last-changelog-message-seen",
9+
{
10+
parse: (value) =>
11+
// eslint-disable-next-line unicorn/no-null
12+
value === null || value === "" ? null : Number.parseInt(value, 10),
13+
stringify: (value) => value.toString(),
14+
},
15+
);
16+
17+
const isOpen = useMemo(() => {
18+
const lastClosed = lastMessageSeen.value;
19+
return (
20+
lastClosed === undefined ||
21+
messages.some((message) => message.id > lastClosed)
22+
);
23+
}, [lastMessageSeen.value]);
24+
25+
const toggleOpen = useCallback(
26+
(isOpen: boolean) => {
27+
if (isOpen) {
28+
lastMessageSeen.remove();
29+
} else {
30+
lastMessageSeen.set(Math.max(...messages.map(({ id }) => id)));
31+
}
32+
},
33+
[lastMessageSeen],
34+
);
35+
36+
const open = useCallback(() => {
37+
toggleOpen(true);
38+
}, [toggleOpen]);
39+
40+
return { isOpen, toggleOpen, open };
41+
};

0 commit comments

Comments
 (0)