From d235d0b54200db56af5eb14809349b7642c2c602 Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Fri, 31 Jan 2025 02:50:49 +0000 Subject: [PATCH] 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) {