From d235d0b54200db56af5eb14809349b7642c2c602 Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Fri, 31 Jan 2025 02:50:49 +0000 Subject: [PATCH 1/7] fix: use key with sol for simulations --- apps/staking/src/api.ts | 5 ++++- apps/staking/src/components/Root/index.tsx | 4 +++- apps/staking/src/config/server.ts | 4 +++- apps/staking/src/hooks/use-api.tsx | 12 ++++++++---- .../pyth_staking_sdk/src/pyth-staking-client.ts | 8 +++++--- 5 files changed, 23 insertions(+), 10 deletions(-) diff --git a/apps/staking/src/api.ts b/apps/staking/src/api.ts index 5ba2a9bc25..f9ad5963f6 100644 --- a/apps/staking/src/api.ts +++ b/apps/staking/src/api.ts @@ -106,6 +106,7 @@ export const loadData = async ( pythnetClient: PythnetClient, hermesClient: HermesClient, stakeAccount?: PublicKey | undefined, + simulationPayer?: PublicKey | undefined, ): Promise => stakeAccount === undefined ? loadDataNoStakeAccount(client, pythnetClient, hermesClient) @@ -114,6 +115,7 @@ export const loadData = async ( pythnetClient, hermesClient, stakeAccount, + simulationPayer, ); const loadDataNoStakeAccount = async ( @@ -149,6 +151,7 @@ const loadDataForStakeAccount = async ( pythnetClient: PythnetClient, hermesClient: HermesClient, stakeAccount: PublicKey, + simulationPayer?: PublicKey, ): Promise => { const [ { publishers, ...baseInfo }, @@ -160,7 +163,7 @@ const loadDataForStakeAccount = async ( loadBaseInfo(client, pythnetClient, hermesClient), client.getStakeAccountCustody(stakeAccount), client.getUnlockSchedule(stakeAccount), - client.getClaimableRewards(stakeAccount), + client.getClaimableRewards(stakeAccount, simulationPayer), client.getStakeAccountPositions(stakeAccount), ]); diff --git a/apps/staking/src/components/Root/index.tsx b/apps/staking/src/components/Root/index.tsx index 53f5459d5e..173aadc3c2 100644 --- a/apps/staking/src/components/Root/index.tsx +++ b/apps/staking/src/components/Root/index.tsx @@ -14,6 +14,7 @@ import { MAINNET_RPC, HERMES_URL, PYTHNET_RPC, + SIMULATION_PAYER, } from "../../config/server"; import { ApiProvider } from "../../hooks/use-api"; import { LoggerProvider } from "../../hooks/use-logger"; @@ -27,6 +28,7 @@ import { MaxWidth } from "../MaxWidth"; import { ReportAccessibility } from "../ReportAccessibility"; import { RouterProvider } from "../RouterProvider"; import { WalletProvider } from "../WalletProvider"; +import { PublicKey } from "@solana/web3.js"; const redHatText = Red_Hat_Text({ subsets: ["latin"], @@ -82,7 +84,7 @@ const HtmlWithProviders = ({ lang, ...props }: HTMLProps) => ( walletConnectProjectId={WALLETCONNECT_PROJECT_ID} mainnetRpc={MAINNET_RPC} > - + diff --git a/apps/staking/src/config/server.ts b/apps/staking/src/config/server.ts index 0e4c566cc0..809ba75aee 100644 --- a/apps/staking/src/config/server.ts +++ b/apps/staking/src/config/server.ts @@ -74,7 +74,9 @@ export const GOVERNANCE_ONLY_REGIONS = transformOr( [], ); export const PROXYCHECK_API_KEY = demandInProduction("PROXYCHECK_API_KEY"); - +// This needs to be a public key that has SOL in it all the time, it will be used in the simulation to compute the claimable rewards +// such simulation fails when the payer has no funds +export const SIMULATION_PAYER = process.env.SIMULATION_PAYER class MissingEnvironmentError extends Error { constructor(name: string) { super(`Missing environment variable: ${name}!`); diff --git a/apps/staking/src/hooks/use-api.tsx b/apps/staking/src/hooks/use-api.tsx index 7d9b22f7cf..ad6cdd85cf 100644 --- a/apps/staking/src/hooks/use-api.tsx +++ b/apps/staking/src/hooks/use-api.tsx @@ -4,7 +4,7 @@ import { HermesClient } from "@pythnetwork/hermes-client"; import { PythnetClient, PythStakingClient } from "@pythnetwork/staking-sdk"; import { useLocalStorageValue } from "@react-hookz/web"; import { useConnection, useWallet } from "@solana/wallet-adapter-react"; -import { Connection, type PublicKey } from "@solana/web3.js"; +import { Connection, PublicKey } from "@solana/web3.js"; import { type ComponentProps, createContext, useContext, useMemo } from "react"; import { useSWRConfig } from "swr"; @@ -65,6 +65,7 @@ const State = { pythnetClient: PythnetClient, hermesClient: HermesClient, account: PublicKey, + simulationPayer: string | undefined, allAccounts: [PublicKey, ...PublicKey[]], selectAccount: (account: PublicKey) => void, mutate: ReturnType["mutate"], @@ -95,7 +96,7 @@ const State = { dashboardDataCacheKey, loadData: () => - api.loadData(client, pythnetClient, hermesClient, account), + api.loadData(client, pythnetClient, hermesClient, account, simulationPayer ? new PublicKey(simulationPayer) : undefined), claim: bindApi(api.claim), deposit: bindApi(api.deposit), @@ -131,19 +132,21 @@ type ApiProviderProps = Omit< > & { pythnetRpcUrl: string; hermesUrl: string; + simulationPayer: string | undefined; }; export const ApiProvider = ({ hermesUrl, pythnetRpcUrl, + simulationPayer, ...props }: ApiProviderProps) => { - const state = useApiContext(hermesUrl, pythnetRpcUrl); + const state = useApiContext(hermesUrl, pythnetRpcUrl, simulationPayer); return ; }; -const useApiContext = (hermesUrl: string, pythnetRpcUrl: string) => { +const useApiContext = (hermesUrl: string, pythnetRpcUrl: string, simulationPayer: string | undefined) => { const wallet = useWallet(); const { connection } = useConnection(); const { isMainnet } = useNetwork(); @@ -235,6 +238,7 @@ const useApiContext = (hermesUrl: string, pythnetRpcUrl: string) => { pythnetClient, hermesClient, selectedAccount ?? firstAccount, + simulationPayer, [firstAccount, ...otherAccounts], (account: PublicKey) => { localStorageValue.set(account.toBase58()); diff --git a/governance/pyth_staking_sdk/src/pyth-staking-client.ts b/governance/pyth_staking_sdk/src/pyth-staking-client.ts index fa94f94849..d8fd42aa0e 100644 --- a/governance/pyth_staking_sdk/src/pyth-staking-client.ts +++ b/governance/pyth_staking_sdk/src/pyth-staking-client.ts @@ -688,6 +688,7 @@ export class PythStakingClient { async getAdvanceDelegationRecordInstructions( stakeAccountPositions: PublicKey, + payer?: PublicKey ) { const poolData = await this.getPoolDataAccount(); const stakeAccountPositionsData = await this.getStakeAccountPositions( @@ -745,7 +746,7 @@ export class PythStakingClient { this.integrityPoolProgram.methods .advanceDelegationRecord() .accountsPartial({ - payer: this.wallet.publicKey, + payer: payer ?? this.wallet.publicKey, publisher: pubkey, publisherStakeAccountPositions: stakeAccount, publisherStakeAccountCustody: stakeAccount @@ -795,16 +796,17 @@ export class PythStakingClient { ); } - public async getClaimableRewards(stakeAccountPositions: PublicKey) { + public async getClaimableRewards(stakeAccountPositions: PublicKey, simulationPayer?: PublicKey) { const instructions = await this.getAdvanceDelegationRecordInstructions( stakeAccountPositions, + simulationPayer ); let totalRewards = 0n; for (const instruction of instructions.advanceDelegationRecordInstructions) { const tx = new Transaction().add(instruction); - tx.feePayer = this.wallet.publicKey; + tx.feePayer = simulationPayer ?? this.wallet.publicKey; const res = await this.connection.simulateTransaction(tx); const val = res.value.returnData?.data[0]; if (val === undefined) { From c3de15769eec9cb211a13f5ed4f05b801297d526 Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Fri, 31 Jan 2025 02:57:13 +0000 Subject: [PATCH 2/7] cleanup --- apps/staking/src/components/Root/index.tsx | 1 - apps/staking/src/config/server.ts | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/staking/src/components/Root/index.tsx b/apps/staking/src/components/Root/index.tsx index 173aadc3c2..898c4640b7 100644 --- a/apps/staking/src/components/Root/index.tsx +++ b/apps/staking/src/components/Root/index.tsx @@ -28,7 +28,6 @@ import { MaxWidth } from "../MaxWidth"; import { ReportAccessibility } from "../ReportAccessibility"; import { RouterProvider } from "../RouterProvider"; import { WalletProvider } from "../WalletProvider"; -import { PublicKey } from "@solana/web3.js"; const redHatText = Red_Hat_Text({ subsets: ["latin"], diff --git a/apps/staking/src/config/server.ts b/apps/staking/src/config/server.ts index 809ba75aee..2eb45440bc 100644 --- a/apps/staking/src/config/server.ts +++ b/apps/staking/src/config/server.ts @@ -74,8 +74,8 @@ export const GOVERNANCE_ONLY_REGIONS = transformOr( [], ); export const PROXYCHECK_API_KEY = demandInProduction("PROXYCHECK_API_KEY"); -// This needs to be a public key that has SOL in it all the time, it will be used in the simulation to compute the claimable rewards -// such simulation fails when the payer has no funds +// This needs to be a public key that has SOL in it all the time, it will be used as a payer in the transaction simulation to compute the claimable rewards +// such simulation fails when the payer has no funds. export const SIMULATION_PAYER = process.env.SIMULATION_PAYER class MissingEnvironmentError extends Error { constructor(name: string) { From 4bf0d9c93333bbca06505431c421cf6a1feace8d Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Fri, 31 Jan 2025 03:15:14 +0000 Subject: [PATCH 3/7] fix format --- apps/staking/src/components/Root/index.tsx | 6 +++++- apps/staking/src/config/server.ts | 2 +- apps/staking/src/hooks/use-api.tsx | 14 ++++++++++++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/apps/staking/src/components/Root/index.tsx b/apps/staking/src/components/Root/index.tsx index 898c4640b7..cfae086ad1 100644 --- a/apps/staking/src/components/Root/index.tsx +++ b/apps/staking/src/components/Root/index.tsx @@ -83,7 +83,11 @@ const HtmlWithProviders = ({ lang, ...props }: HTMLProps) => ( walletConnectProjectId={WALLETCONNECT_PROJECT_ID} mainnetRpc={MAINNET_RPC} > - + diff --git a/apps/staking/src/config/server.ts b/apps/staking/src/config/server.ts index 2eb45440bc..d0f8e49f34 100644 --- a/apps/staking/src/config/server.ts +++ b/apps/staking/src/config/server.ts @@ -76,7 +76,7 @@ export const GOVERNANCE_ONLY_REGIONS = transformOr( export const PROXYCHECK_API_KEY = demandInProduction("PROXYCHECK_API_KEY"); // This needs to be a public key that has SOL in it all the time, it will be used as a payer in the transaction simulation to compute the claimable rewards // such simulation fails when the payer has no funds. -export const SIMULATION_PAYER = process.env.SIMULATION_PAYER +export const SIMULATION_PAYER = process.env.SIMULATION_PAYER; class MissingEnvironmentError extends Error { constructor(name: string) { super(`Missing environment variable: ${name}!`); diff --git a/apps/staking/src/hooks/use-api.tsx b/apps/staking/src/hooks/use-api.tsx index ad6cdd85cf..c1dc34ca93 100644 --- a/apps/staking/src/hooks/use-api.tsx +++ b/apps/staking/src/hooks/use-api.tsx @@ -96,7 +96,13 @@ const State = { dashboardDataCacheKey, loadData: () => - api.loadData(client, pythnetClient, hermesClient, account, simulationPayer ? new PublicKey(simulationPayer) : undefined), + api.loadData( + client, + pythnetClient, + hermesClient, + account, + simulationPayer ? new PublicKey(simulationPayer) : undefined, + ), claim: bindApi(api.claim), deposit: bindApi(api.deposit), @@ -146,7 +152,11 @@ export const ApiProvider = ({ return ; }; -const useApiContext = (hermesUrl: string, pythnetRpcUrl: string, simulationPayer: string | undefined) => { +const useApiContext = ( + hermesUrl: string, + pythnetRpcUrl: string, + simulationPayer: string | undefined, +) => { const wallet = useWallet(); const { connection } = useConnection(); const { isMainnet } = useNetwork(); From 65f7e3e3f171ff4aea73c09d773ba54c676ea607 Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Fri, 31 Jan 2025 03:15:46 +0000 Subject: [PATCH 4/7] fix format --- governance/pyth_staking_sdk/src/pyth-staking-client.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/governance/pyth_staking_sdk/src/pyth-staking-client.ts b/governance/pyth_staking_sdk/src/pyth-staking-client.ts index d8fd42aa0e..d56e485604 100644 --- a/governance/pyth_staking_sdk/src/pyth-staking-client.ts +++ b/governance/pyth_staking_sdk/src/pyth-staking-client.ts @@ -688,7 +688,7 @@ export class PythStakingClient { async getAdvanceDelegationRecordInstructions( stakeAccountPositions: PublicKey, - payer?: PublicKey + payer?: PublicKey, ) { const poolData = await this.getPoolDataAccount(); const stakeAccountPositionsData = await this.getStakeAccountPositions( @@ -796,10 +796,13 @@ export class PythStakingClient { ); } - public async getClaimableRewards(stakeAccountPositions: PublicKey, simulationPayer?: PublicKey) { + public async getClaimableRewards( + stakeAccountPositions: PublicKey, + simulationPayer?: PublicKey, + ) { const instructions = await this.getAdvanceDelegationRecordInstructions( stakeAccountPositions, - simulationPayer + simulationPayer, ); let totalRewards = 0n; From 67cc817135419bed49a6eacb25ed07a455294dd1 Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Tue, 4 Feb 2025 23:49:15 +0000 Subject: [PATCH 5/7] add default value --- apps/staking/src/config/server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/staking/src/config/server.ts b/apps/staking/src/config/server.ts index d0f8e49f34..3b999c2da6 100644 --- a/apps/staking/src/config/server.ts +++ b/apps/staking/src/config/server.ts @@ -76,7 +76,7 @@ export const GOVERNANCE_ONLY_REGIONS = transformOr( export const PROXYCHECK_API_KEY = demandInProduction("PROXYCHECK_API_KEY"); // This needs to be a public key that has SOL in it all the time, it will be used as a payer in the transaction simulation to compute the claimable rewards // such simulation fails when the payer has no funds. -export const SIMULATION_PAYER = process.env.SIMULATION_PAYER; +export const SIMULATION_PAYER = getOr("SIMULATION_PAYER", "E5KR7yfb9UyVB6ZhmhQki1rM1eBcxHvyGKFZakAC5uc"); class MissingEnvironmentError extends Error { constructor(name: string) { super(`Missing environment variable: ${name}!`); From c3e877b7714631d2cdc861dec89a3603a7267c21 Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Tue, 4 Feb 2025 23:55:21 +0000 Subject: [PATCH 6/7] clean up, choose default value --- apps/staking/src/api.ts | 2 +- apps/staking/src/components/Root/index.tsx | 4 ++-- apps/staking/src/config/server.ts | 2 +- apps/staking/src/hooks/use-api.tsx | 16 ++++++++++------ 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/apps/staking/src/api.ts b/apps/staking/src/api.ts index f9ad5963f6..62682ae380 100644 --- a/apps/staking/src/api.ts +++ b/apps/staking/src/api.ts @@ -106,7 +106,7 @@ export const loadData = async ( pythnetClient: PythnetClient, hermesClient: HermesClient, stakeAccount?: PublicKey | undefined, - simulationPayer?: PublicKey | undefined, + simulationPayer?: PublicKey, ): Promise => stakeAccount === undefined ? loadDataNoStakeAccount(client, pythnetClient, hermesClient) diff --git a/apps/staking/src/components/Root/index.tsx b/apps/staking/src/components/Root/index.tsx index cfae086ad1..ae1b9d9f72 100644 --- a/apps/staking/src/components/Root/index.tsx +++ b/apps/staking/src/components/Root/index.tsx @@ -14,7 +14,7 @@ import { MAINNET_RPC, HERMES_URL, PYTHNET_RPC, - SIMULATION_PAYER, + SIMULATION_PAYER_ADDRESS, } from "../../config/server"; import { ApiProvider } from "../../hooks/use-api"; import { LoggerProvider } from "../../hooks/use-logger"; @@ -86,7 +86,7 @@ const HtmlWithProviders = ({ lang, ...props }: HTMLProps) => ( diff --git a/apps/staking/src/config/server.ts b/apps/staking/src/config/server.ts index 3b999c2da6..06b27c89ae 100644 --- a/apps/staking/src/config/server.ts +++ b/apps/staking/src/config/server.ts @@ -76,7 +76,7 @@ export const GOVERNANCE_ONLY_REGIONS = transformOr( export const PROXYCHECK_API_KEY = demandInProduction("PROXYCHECK_API_KEY"); // This needs to be a public key that has SOL in it all the time, it will be used as a payer in the transaction simulation to compute the claimable rewards // such simulation fails when the payer has no funds. -export const SIMULATION_PAYER = getOr("SIMULATION_PAYER", "E5KR7yfb9UyVB6ZhmhQki1rM1eBcxHvyGKFZakAC5uc"); +export const SIMULATION_PAYER_ADDRESS = getOr("SIMULATION_PAYER_ADDRESS", "E5KR7yfb9UyVB6ZhmhQki1rM1eBcxHvyGKFZakAC5uc"); class MissingEnvironmentError extends Error { constructor(name: string) { super(`Missing environment variable: ${name}!`); diff --git a/apps/staking/src/hooks/use-api.tsx b/apps/staking/src/hooks/use-api.tsx index c1dc34ca93..d66451b69f 100644 --- a/apps/staking/src/hooks/use-api.tsx +++ b/apps/staking/src/hooks/use-api.tsx @@ -65,7 +65,7 @@ const State = { pythnetClient: PythnetClient, hermesClient: HermesClient, account: PublicKey, - simulationPayer: string | undefined, + simulationPayer: PublicKey, allAccounts: [PublicKey, ...PublicKey[]], selectAccount: (account: PublicKey) => void, mutate: ReturnType["mutate"], @@ -101,7 +101,7 @@ const State = { pythnetClient, hermesClient, account, - simulationPayer ? new PublicKey(simulationPayer) : undefined, + simulationPayer, ), claim: bindApi(api.claim), @@ -138,16 +138,16 @@ type ApiProviderProps = Omit< > & { pythnetRpcUrl: string; hermesUrl: string; - simulationPayer: string | undefined; + simulationPayerAddress: string; }; export const ApiProvider = ({ hermesUrl, pythnetRpcUrl, - simulationPayer, + simulationPayerAddress, ...props }: ApiProviderProps) => { - const state = useApiContext(hermesUrl, pythnetRpcUrl, simulationPayer); + const state = useApiContext(hermesUrl, pythnetRpcUrl, simulationPayerAddress); return ; }; @@ -155,7 +155,7 @@ export const ApiProvider = ({ const useApiContext = ( hermesUrl: string, pythnetRpcUrl: string, - simulationPayer: string | undefined, + simulationPayerAddress: string, ) => { const wallet = useWallet(); const { connection } = useConnection(); @@ -166,6 +166,10 @@ const useApiContext = ( () => new PythnetClient(new Connection(pythnetRpcUrl)), [pythnetRpcUrl], ); + const simulationPayer = useMemo( + () => new PublicKey(simulationPayerAddress), + [simulationPayerAddress], + ); const pythStakingClient = useMemo( () => wallet.publicKey && wallet.signAllTransactions && wallet.signTransaction From c64e13ceb44fe3ba3c05416cd015dfbed6f2d886 Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Tue, 4 Feb 2025 23:59:52 +0000 Subject: [PATCH 7/7] format --- apps/staking/src/config/server.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/staking/src/config/server.ts b/apps/staking/src/config/server.ts index 06b27c89ae..25846b4016 100644 --- a/apps/staking/src/config/server.ts +++ b/apps/staking/src/config/server.ts @@ -76,7 +76,10 @@ export const GOVERNANCE_ONLY_REGIONS = transformOr( export const PROXYCHECK_API_KEY = demandInProduction("PROXYCHECK_API_KEY"); // This needs to be a public key that has SOL in it all the time, it will be used as a payer in the transaction simulation to compute the claimable rewards // such simulation fails when the payer has no funds. -export const SIMULATION_PAYER_ADDRESS = getOr("SIMULATION_PAYER_ADDRESS", "E5KR7yfb9UyVB6ZhmhQki1rM1eBcxHvyGKFZakAC5uc"); +export const SIMULATION_PAYER_ADDRESS = getOr( + "SIMULATION_PAYER_ADDRESS", + "E5KR7yfb9UyVB6ZhmhQki1rM1eBcxHvyGKFZakAC5uc", +); class MissingEnvironmentError extends Error { constructor(name: string) { super(`Missing environment variable: ${name}!`);