Skip to content

feat: fetch data from pythnet #2005

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 43 additions & 15 deletions apps/staking/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
getAmountByTargetAndState,
getCurrentEpoch,
PositionState,
PythnetClient,
PythStakingClient,
type StakeAccountPositions,
} from "@pythnetwork/staking-sdk";
Expand Down Expand Up @@ -43,6 +44,8 @@ type Data = {
cooldown2: bigint;
};
yieldRate: bigint;
m: bigint;
z: bigint;
integrityStakingPublishers: {
name: string | undefined;
publicKey: PublicKey;
Expand Down Expand Up @@ -95,18 +98,29 @@ export const getStakeAccount = async (

export const loadData = async (
client: PythStakingClient,
pythnetClient: PythnetClient,
hermesClient: HermesClient,
stakeAccount?: PublicKey | undefined,
): Promise<Data> =>
stakeAccount === undefined
? loadDataNoStakeAccount(client, hermesClient)
: loadDataForStakeAccount(client, hermesClient, stakeAccount);
? loadDataNoStakeAccount(client, pythnetClient, hermesClient)
: loadDataForStakeAccount(
client,
pythnetClient,
hermesClient,
stakeAccount,
);

const loadDataNoStakeAccount = async (
client: PythStakingClient,
pythnetClient: PythnetClient,
hermesClient: HermesClient,
): Promise<Data> => {
const { publishers, ...baseInfo } = await loadBaseInfo(client, hermesClient);
const { publishers, ...baseInfo } = await loadBaseInfo(
client,
pythnetClient,
hermesClient,
);

return {
...baseInfo,
Expand All @@ -127,6 +141,7 @@ const loadDataNoStakeAccount = async (

const loadDataForStakeAccount = async (
client: PythStakingClient,
pythnetClient: PythnetClient,
hermesClient: HermesClient,
stakeAccount: PublicKey,
): Promise<Data> => {
Expand All @@ -137,7 +152,7 @@ const loadDataForStakeAccount = async (
claimableRewards,
stakeAccountPositions,
] = await Promise.all([
loadBaseInfo(client, hermesClient),
loadBaseInfo(client, pythnetClient, hermesClient),
client.getStakeAccountCustody(stakeAccount),
client.getUnlockSchedule(stakeAccount),
client.getClaimableRewards(stakeAccount),
Expand Down Expand Up @@ -196,36 +211,49 @@ const loadDataForStakeAccount = async (

const loadBaseInfo = async (
client: PythStakingClient,
pythnetClient: PythnetClient,
hermesClient: HermesClient,
) => {
const [publishers, walletAmount, poolConfig, currentEpoch] =
const [publishers, walletAmount, poolConfig, currentEpoch, parameters] =
await Promise.all([
loadPublisherData(client, hermesClient),
loadPublisherData(client, pythnetClient, hermesClient),
client.getOwnerPythBalance(),
client.getPoolConfigAccount(),
getCurrentEpoch(client.connection),
pythnetClient.getStakeCapParameters(),
]);

return { yieldRate: poolConfig.y, walletAmount, publishers, currentEpoch };
return {
yieldRate: poolConfig.y,
walletAmount,
publishers,
currentEpoch,
m: parameters.m,
z: parameters.z,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nit but I'd love to have more useful names for these if possible

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't find a name for z as much as I try

};
};

const loadPublisherData = async (
client: PythStakingClient,
pythnetClient: PythnetClient,
hermesClient: HermesClient,
) => {
const [poolData, publisherRankings, publisherCaps] = await Promise.all([
client.getPoolDataAccount(),
getPublisherRankings(),
hermesClient.getLatestPublisherCaps({
parsed: true,
}),
]);
const [poolData, publisherRankings, publisherCaps, publisherNumberOfSymbols] =
await Promise.all([
client.getPoolDataAccount(),
getPublisherRankings(),
hermesClient.getLatestPublisherCaps({
parsed: true,
}),
pythnetClient.getPublisherNumberOfSymbols(),
]);

return extractPublisherData(poolData).map((publisher) => {
const publisherPubkeyString = publisher.pubkey.toBase58();
const publisherRanking = publisherRankings.find(
(ranking) => ranking.publisher === publisherPubkeyString,
);
const numberOfSymbols = publisherNumberOfSymbols[publisherPubkeyString];
const apyHistory = publisher.apyHistory.map(({ epoch, apy }) => ({
date: epochToDate(epoch + 1n),
apy,
Expand All @@ -234,7 +262,7 @@ const loadPublisherData = async (
return {
apyHistory,
name: undefined, // TODO
numFeeds: publisherRanking?.numSymbols ?? 0,
numFeeds: numberOfSymbols ?? 0,
poolCapacity: getPublisherCap(publisherCaps, publisher.pubkey),
poolUtilization: publisher.totalDelegation,
poolUtilizationDelta: publisher.totalDelegationDelta,
Expand Down
3 changes: 2 additions & 1 deletion apps/staking/src/components/Root/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
WALLETCONNECT_PROJECT_ID,
MAINNET_RPC,
HERMES_URL,
PYTHNET_RPC,
} from "../../config/server";
import { ApiProvider } from "../../hooks/use-api";
import { LoggerProvider } from "../../hooks/use-logger";
Expand Down Expand Up @@ -79,7 +80,7 @@ const HtmlWithProviders = ({ lang, ...props }: HTMLProps<HTMLHtmlElement>) => (
walletConnectProjectId={WALLETCONNECT_PROJECT_ID}
mainnetRpc={MAINNET_RPC}
>
<ApiProvider hermesUrl={HERMES_URL}>
<ApiProvider hermesUrl={HERMES_URL} pythnetRpcUrl={PYTHNET_RPC}>
<ToastProvider>
<html lang={lang} {...props} />
</ToastProvider>
Expand Down
1 change: 1 addition & 0 deletions apps/staking/src/config/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export const WALLETCONNECT_PROJECT_ID = demandInProduction(
"WALLETCONNECT_PROJECT_ID",
);
export const MAINNET_RPC = process.env.MAINNET_RPC;
export const PYTHNET_RPC = getOr("PYTHNET_RPC", "https://pythnet.rpcpool.com");
export const HERMES_URL = getOr("HERMES_URL", "https://hermes.pyth.network");
export const BLOCKED_REGIONS = transformOr("BLOCKED_REGIONS", fromCsv, []);
export const IP_ALLOWLIST = transformOr("IP_ALLOWLIST", fromCsv, []);
Expand Down
29 changes: 22 additions & 7 deletions apps/staking/src/hooks/use-api.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"use client";

import { HermesClient } from "@pythnetwork/hermes-client";
import { PythStakingClient } from "@pythnetwork/staking-sdk";
import { PythnetClient, PythStakingClient } from "@pythnetwork/staking-sdk";
import { useLocalStorageValue } from "@react-hookz/web";
import { useConnection, useWallet } from "@solana/wallet-adapter-react";
import type { PublicKey } from "@solana/web3.js";
import { Connection, type PublicKey } from "@solana/web3.js";
import { type ComponentProps, createContext, useContext, useMemo } from "react";
import { useSWRConfig } from "swr";

Expand Down Expand Up @@ -43,6 +43,7 @@ const State = {
[StateType.LoadedNoStakeAccount]: (
isMainnet: boolean,
client: PythStakingClient,
pythnetClient: PythnetClient,
hermesClient: HermesClient,
onCreateAccount: (newAccount: PublicKey) => Promise<void>,
) => ({
Expand All @@ -51,7 +52,7 @@ const State = {
isMainnet ? "mainnet" : "devnet",
client.wallet.publicKey.toBase58(),
],
loadData: () => api.loadData(client, hermesClient),
loadData: () => api.loadData(client, pythnetClient, hermesClient),
deposit: async (amount: bigint) => {
const account = await api.createStakeAccountAndDeposit(client, amount);
return onCreateAccount(account);
Expand All @@ -61,6 +62,7 @@ const State = {
[StateType.Loaded]: (
isMainnet: boolean,
client: PythStakingClient,
pythnetClient: PythnetClient,
hermesClient: HermesClient,
account: PublicKey,
allAccounts: [PublicKey, ...PublicKey[]],
Expand Down Expand Up @@ -92,7 +94,8 @@ const State = {
selectAccount,
dashboardDataCacheKey,

loadData: () => api.loadData(client, hermesClient, account),
loadData: () =>
api.loadData(client, pythnetClient, hermesClient, account),

claim: bindApi(api.claim),
deposit: bindApi(api.deposit),
Expand Down Expand Up @@ -126,21 +129,30 @@ type ApiProviderProps = Omit<
ComponentProps<typeof ApiContext.Provider>,
"value"
> & {
pythnetRpcUrl: string;
hermesUrl: string;
};

export const ApiProvider = ({ hermesUrl, ...props }: ApiProviderProps) => {
const state = useApiContext(hermesUrl);
export const ApiProvider = ({
hermesUrl,
pythnetRpcUrl,
...props
}: ApiProviderProps) => {
const state = useApiContext(hermesUrl, pythnetRpcUrl);

return <ApiContext.Provider value={state} {...props} />;
};

const useApiContext = (hermesUrl: string) => {
const useApiContext = (hermesUrl: string, pythnetRpcUrl: string) => {
const wallet = useWallet();
const { connection } = useConnection();
const { isMainnet } = useNetwork();
const { mutate } = useSWRConfig();
const hermesClient = useMemo(() => new HermesClient(hermesUrl), [hermesUrl]);
const pythnetClient = useMemo(
() => new PythnetClient(new Connection(pythnetRpcUrl)),
[pythnetRpcUrl],
);
const pythStakingClient = useMemo(
() =>
wallet.publicKey && wallet.signAllTransactions && wallet.signTransaction
Expand Down Expand Up @@ -209,6 +221,7 @@ const useApiContext = (hermesUrl: string) => {
return State[StateType.Loaded](
isMainnet,
pythStakingClient,
pythnetClient,
hermesClient,
selectedAccount ?? firstAccount,
[firstAccount, ...otherAccounts],
Expand All @@ -221,6 +234,7 @@ const useApiContext = (hermesUrl: string) => {
return State[StateType.LoadedNoStakeAccount](
isMainnet,
pythStakingClient,
pythnetClient,
hermesClient,
async (newAccount) => {
await stakeAccounts.mutate([newAccount]);
Expand All @@ -239,6 +253,7 @@ const useApiContext = (hermesUrl: string) => {
wallet.disconnecting,
wallet.connected,
pythStakingClient,
pythnetClient,
stakeAccounts,
hermesClient,
lastStakeAccount,
Expand Down
76 changes: 76 additions & 0 deletions governance/pyth_staking_sdk/idl/stake-caps-parameters.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
{
"address": "ujSFv8q8woXW5PUnby52PQyxYGUudxkrvgN6A631Qmm",
"metadata": {
"name": "stake_caps_parameters",
"version": "0.1.0",
"spec": "0.1.0",
"description": "Created with Anchor"
},
"instructions": [
{
"name": "set_parameters",
"discriminator": [218, 114, 41, 75, 208, 237, 97, 28],
"accounts": [
{
"name": "signer",
"writable": true,
"signer": true
},
{
"name": "parameters",
"writable": true,
"pda": {
"seeds": [
{
"kind": "const",
"value": [112, 97, 114, 97, 109, 101, 116, 101, 114, 115]
}
]
}
},
{
"name": "system_program",
"address": "11111111111111111111111111111111"
}
],
"args": [
{
"name": "parameters",
"type": {
"defined": {
"name": "Parameters"
}
}
}
]
}
],
"accounts": [
{
"name": "Parameters",
"discriminator": [233, 2, 25, 109, 70, 228, 206, 228]
}
],
"types": [
{
"name": "Parameters",
"type": {
"kind": "struct",
"fields": [
{
"name": "current_authority",
"type": "pubkey"
},
{
"name": "m",
"type": "u64"
},
{
"name": "z",
"type": "u64"
}
]
}
}
]
}
1 change: 1 addition & 0 deletions governance/pyth_staking_sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
},
"dependencies": {
"@coral-xyz/anchor": "^0.30.1",
"@pythnetwork/client": "^2.22.0",
"@pythnetwork/solana-utils": "workspace:*",
"@solana/spl-governance": "^0.3.28",
"@solana/spl-token": "^0.3.7",
Expand Down
4 changes: 4 additions & 0 deletions governance/pyth_staking_sdk/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,7 @@ export const PUBLISHER_CAPS_PROGRAM_ADDRESS = new PublicKey(
export const GOVERNANCE_ADDRESS = new PublicKey(
"pytGY6tWRgGinSCvRLnSv4fHfBTMoiDGiCsesmHWM6U",
);

export const STAKE_CAPS_PARAMETERS_PROGRAM_ADDRESS = new PublicKey(
"ujSFv8q8woXW5PUnby52PQyxYGUudxkrvgN6A631Qmm",
);
1 change: 1 addition & 0 deletions governance/pyth_staking_sdk/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from "./pdas";
export * from "./pyth-staking-client";
export * from "./pythnet-client";
export * from "./types";
export * from "./utils/apy";
export * from "./utils/clock";
Expand Down
8 changes: 8 additions & 0 deletions governance/pyth_staking_sdk/src/pdas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { PublicKey } from "@solana/web3.js";

import {
INTEGRITY_POOL_PROGRAM_ADDRESS,
STAKE_CAPS_PARAMETERS_PROGRAM_ADDRESS,
STAKING_PROGRAM_ADDRESS,
} from "./constants";

Expand Down Expand Up @@ -73,3 +74,10 @@ export const getMaxVoterWeightRecordAddress = () => {
STAKING_PROGRAM_ADDRESS,
);
};

export const getStakeCapsParametersAddress = () => {
return PublicKey.findProgramAddressSync(
[Buffer.from("parameters")],
STAKE_CAPS_PARAMETERS_PROGRAM_ADDRESS,
);
};
Loading
Loading