Skip to content

Commit da1f031

Browse files
committed
Merge branch 'main' of github.com:pyth-network/pyth-crosschain into scaling
2 parents 0c2c569 + 9a6e7d1 commit da1f031

File tree

48 files changed

+2241
-639
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+2241
-639
lines changed

apps/staking/src/api.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ const loadDataForStakeAccount = async (
194194
client: PythStakingClient,
195195
hermesClient: HermesClient,
196196
stakeAccount: PublicKey,
197-
) => {
197+
): Promise<Data> => {
198198
const [
199199
{ publishers, ...baseInfo },
200200
stakeAccountCustody,
@@ -240,7 +240,7 @@ const loadDataForStakeAccount = async (
240240
cooldown: filterGovernancePositions(PositionState.PREUNLOCKING),
241241
cooldown2: filterGovernancePositions(PositionState.UNLOCKING),
242242
},
243-
unlockSchedule,
243+
unlockSchedule: unlockSchedule.schedule,
244244
integrityStakingPublishers: publishers.map((publisher) => ({
245245
...publisher,
246246
positions: {
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { PythStakingClient } from "@pythnetwork/staking-sdk";
2+
import { WalletAdapterNetwork } from "@solana/wallet-adapter-base";
3+
import { clusterApiUrl, Connection, PublicKey } from "@solana/web3.js";
4+
import type { NextRequest } from "next/server";
5+
import { z } from "zod";
6+
7+
import { IS_MAINNET, RPC } from "../../../config/server";
8+
9+
const UnlockScheduleSchema = z.object({
10+
date: z.date(),
11+
amount: z.number(),
12+
});
13+
14+
const LockSchema = z.object({
15+
type: z.string(),
16+
schedule: z.array(UnlockScheduleSchema),
17+
});
18+
19+
const ResponseSchema = z.array(
20+
z.object({
21+
custodyAccount: z.string(),
22+
actualAmount: z.number(),
23+
lock: LockSchema,
24+
}),
25+
);
26+
27+
const stakingClient = new PythStakingClient({
28+
connection: new Connection(
29+
RPC ??
30+
clusterApiUrl(
31+
IS_MAINNET ? WalletAdapterNetwork.Mainnet : WalletAdapterNetwork.Devnet,
32+
),
33+
),
34+
});
35+
36+
const isValidPublicKey = (publicKey: string) => {
37+
try {
38+
new PublicKey(publicKey);
39+
return true;
40+
} catch {
41+
return false;
42+
}
43+
};
44+
45+
export async function GET(req: NextRequest) {
46+
const owner = req.nextUrl.searchParams.get("owner");
47+
48+
if (owner === null || !isValidPublicKey(owner)) {
49+
return Response.json(
50+
{
51+
error:
52+
"Must provide the 'owner' query parameters as a valid base58 public key",
53+
},
54+
{
55+
status: 400,
56+
},
57+
);
58+
}
59+
60+
const positions = await stakingClient.getAllStakeAccountPositions(
61+
new PublicKey(owner),
62+
);
63+
64+
const responseRaw = await Promise.all(
65+
positions.map(async (position) => {
66+
const custodyAccount =
67+
await stakingClient.getStakeAccountCustody(position);
68+
const lock = await stakingClient.getUnlockSchedule(position, true);
69+
return {
70+
custodyAccount: custodyAccount.address.toBase58(),
71+
actualAmount: Number(custodyAccount.amount),
72+
lock: {
73+
type: lock.type,
74+
schedule: lock.schedule.map((unlock) => ({
75+
date: unlock.date,
76+
amount: Number(unlock.amount),
77+
})),
78+
},
79+
};
80+
}),
81+
);
82+
83+
const response = ResponseSchema.safeParse(responseRaw);
84+
85+
return response.success
86+
? Response.json(response.data)
87+
: Response.json(
88+
{
89+
error: "Internal server error",
90+
},
91+
{
92+
status: 500,
93+
},
94+
);
95+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { PythStakingClient } from "@pythnetwork/staking-sdk";
2+
import { WalletAdapterNetwork } from "@solana/wallet-adapter-base";
3+
import { clusterApiUrl, Connection } from "@solana/web3.js";
4+
import type { NextRequest } from "next/server";
5+
import { z } from "zod";
6+
7+
import { IS_MAINNET, RPC } from "../../../config/server";
8+
9+
const stakingClient = new PythStakingClient({
10+
connection: new Connection(
11+
RPC ??
12+
clusterApiUrl(
13+
IS_MAINNET ? WalletAdapterNetwork.Mainnet : WalletAdapterNetwork.Devnet,
14+
),
15+
),
16+
});
17+
18+
const querySchema = z.enum(["totalSupply", "circulatingSupply"]);
19+
20+
export async function GET(req: NextRequest) {
21+
const query = querySchema.safeParse(req.nextUrl.searchParams.get("q"));
22+
if (!query.success) {
23+
return Response.json(
24+
{
25+
error:
26+
"The 'q' query parameter must be one of 'totalSupply' or 'circulatingSupply'.",
27+
},
28+
{
29+
status: 400,
30+
},
31+
);
32+
}
33+
const q = query.data;
34+
35+
if (q === "circulatingSupply") {
36+
const circulatingSupply = await stakingClient.getCirculatingSupply();
37+
return Response.json(Number(circulatingSupply));
38+
} else {
39+
const pythMint = await stakingClient.getPythTokenMint();
40+
return Response.json(Number(pythMint.supply));
41+
}
42+
}
1.08 MB
Loading
-293 KB
Binary file not shown.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { TermsOfService as default } from "../../components/TermsOfService";

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const Blocked = ({ reason }: Props) => (
1919
</h1>
2020
<p className="mb-20 text-lg">{reason}</p>
2121
<LinkButton
22-
className="place-self-center px-24 py-3"
22+
className="w-full max-w-96 place-self-center px-8 py-3"
2323
href="https://www.pyth.network"
2424
target="_blank"
2525
>

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,10 @@ export const Dashboard = ({
144144
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"
145145
{...(tab === TabIds.Empty && { "data-empty": true })}
146146
>
147-
<h1 className="my-4 hidden text-center text-xl/tight font-light group-data-[empty]:block sm:mb-6 sm:text-3xl lg:my-14 lg:text-5xl">
147+
<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">
148148
Choose Your Journey
149149
</h1>
150-
<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-2 group-data-[empty]:sm:flex-row">
150+
<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">
151151
<Tab id={TabIds.Empty} className="hidden" />
152152
<Journey
153153
longText="Oracle Integrity Staking (OIS)"
@@ -241,13 +241,13 @@ const Journey = ({
241241
)}
242242
{...props}
243243
>
244-
<div className="grid size-full flex-none basis-0 place-content-center border border-neutral-600/50 bg-pythpurple-800 p-2 text-center font-semibold transition group-hover/tab:bg-pythpurple-600/30 group-selected/tab:border-pythpurple-400/60 group-selected/tab:bg-pythpurple-600/60 group-hover/tab:group-selected/tab:bg-pythpurple-600/60 sm:py-4 sm:text-lg">
244+
<div className="grid size-full flex-none basis-0 place-content-center border border-neutral-600/50 bg-pythpurple-800 p-2 text-center font-semibold transition group-data-[empty]:py-8 group-hover/tab:bg-pythpurple-600/30 group-selected/tab:border-pythpurple-400/60 group-selected/tab:bg-pythpurple-600/60 group-hover/tab:group-selected/tab:bg-pythpurple-600/60 sm:py-4 sm:text-lg group-data-[empty]:sm:py-2">
245245
<span className="hidden group-data-[empty]:inline sm:inline">
246246
{longText}
247247
</span>
248248
<span className="group-data-[empty]:hidden sm:hidden">{shortText}</span>
249249
</div>
250-
<div className="relative hidden max-h-[40dvh] w-4/5 flex-none overflow-hidden opacity-30 transition group-hover/tab:opacity-100 group-data-[empty]:sm:block">
250+
<div className="relative hidden w-4/5 flex-none overflow-hidden opacity-30 transition group-hover/tab:opacity-100 group-data-[empty]:sm:block">
251251
<div className="absolute inset-0 bg-[#E6DAFE] mix-blend-color" />
252252
<Image src={image} alt="" className="size-full object-cover object-top" />
253253
<div className="absolute inset-0 top-16 text-center text-xl text-pythpurple-800 md:text-2xl lg:text-3xl">

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

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,33 +38,61 @@ export const Footer = ({
3838
}: Omit<HTMLAttributes<HTMLElement>, "children">) => (
3939
<footer
4040
className={clsx(
41-
"text-xs font-light sm:sticky sm:bottom-0 lg:px-4",
41+
"text-xs font-light lg:sticky lg:bottom-0 lg:px-4",
4242
className,
4343
)}
4444
{...props}
4545
>
4646
<div className="border-t border-neutral-600/50 bg-pythpurple-800 lg:border-x">
47-
<MaxWidth className="flex h-48 flex-col items-center justify-between overflow-hidden py-8 sm:h-16 sm:flex-row sm:gap-10 lg:-mx-4">
48-
<div className="flex flex-col items-center gap-2 sm:flex-row sm:gap-4 md:gap-8">
49-
<Link href="https://www.pyth.network" target="_blank">
50-
<Logo className="h-10 sm:h-8" />
47+
<MaxWidth className="flex h-48 flex-col items-center justify-between overflow-hidden pb-4 pt-8 text-center lg:-mx-4 lg:h-16 lg:flex-row lg:gap-10 lg:py-0">
48+
<div className="flex flex-col items-center gap-2 lg:flex-row lg:gap-8">
49+
<Link
50+
href="https://www.pyth.network"
51+
target="_blank"
52+
className="focus:outline-none focus-visible:ring-1 focus-visible:ring-pythpurple-400"
53+
>
54+
<Logo className="h-10 lg:h-8" />
5155
<span className="sr-only">Pyth homepage</span>
5256
</Link>
5357
<div>© 2024 Pyth Data Association</div>
5458
</div>
55-
<div className="relative flex h-full items-center sm:-right-3">
56-
{SOCIAL_LINKS.map(({ name, icon: Icon, href }) => (
59+
<div className="flex flex-col items-center gap-6 lg:flex-row-reverse lg:gap-8 xl:gap-16">
60+
<div className="relative flex h-full items-center lg:-right-3">
61+
{SOCIAL_LINKS.map(({ name, icon: Icon, href }) => (
62+
<Link
63+
target="_blank"
64+
href={href}
65+
key={name}
66+
className="grid h-full place-content-center px-3 transition hover:text-pythpurple-400 focus:outline-none focus-visible:ring-1 focus-visible:ring-pythpurple-400"
67+
rel="noreferrer"
68+
>
69+
<Icon className="size-4" />
70+
<span className="sr-only">{name}</span>
71+
</Link>
72+
))}
73+
</div>
74+
<div className="flex flex-row gap-1 xl:gap-4">
5775
<Link
76+
className="-my-1 px-2 py-1 focus:outline-none focus-visible:ring-1 focus-visible:ring-pythpurple-400"
5877
target="_blank"
59-
href={href}
60-
key={name}
61-
className="grid h-full place-content-center px-3 hover:text-pythpurple-400"
62-
rel="noreferrer"
78+
href="https://pythdataassociation.com/privacy-policy"
6379
>
64-
<Icon className="size-4" />
65-
<span className="sr-only">{name}</span>
80+
Privacy Policy
6681
</Link>
67-
))}
82+
<Link
83+
className="-my-1 px-2 py-1 focus:outline-none focus-visible:ring-1 focus-visible:ring-pythpurple-400"
84+
target="_blank"
85+
href="https://pythdataassociation.com/terms-of-use"
86+
>
87+
Terms of Use
88+
</Link>
89+
<Link
90+
className="-my-1 px-2 py-1 focus:outline-none focus-visible:ring-1 focus-visible:ring-pythpurple-400"
91+
href="/terms-of-service"
92+
>
93+
Terms of Service
94+
</Link>
95+
</div>
6896
</div>
6997
</MaxWidth>
7098
</div>

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ export const GeneralFaq = (
105105
{
106106
question: "Does participating in OIS affect my participation in PG?",
107107
answer:
108-
"No. The two programs are separate. Staking in OIS does not affect your participation in PG. For example, staking in OIs does not increase your voting power in PG. Staking to a publisher’s stake pool does not give that publisher additional voting power in PG.",
108+
"No. The two programs are separate. Staking in OIS does not affect your participation in PG. For example, staking in OIS does not increase your voting power in PG. Staking to a publisher’s stake pool does not give that publisher additional voting power in PG.",
109109
},
110110
{
111111
question: "Does slashing reduce voting weights?",
@@ -171,8 +171,10 @@ export const GeneralFaq = (
171171
<p>
172172
The Cooldown Period has two phases: from the time you click{" "}
173173
<strong>Unstake</strong> until the end of the current epoch,
174-
followed by a full epoch. Tokens in the first phase are subject
175-
to rewards and slashing. Tokens in the second phase are not.
174+
followed by a full epoch. Tokens in the first phase are eligible
175+
for rewards. Tokens in both phases are subject to slashing if an
176+
issue is identified in an epoch in which they were eligible for
177+
rewards.
176178
</p>
177179
</>
178180
),

0 commit comments

Comments
 (0)