Skip to content

Commit 49d3887

Browse files
authored
fix: use key with sol for simulations (#2315)
* fix: use key with sol for simulations * cleanup * fix format * fix format * add default value * clean up, choose default value * format
1 parent 218d780 commit 49d3887

File tree

5 files changed

+46
-10
lines changed

5 files changed

+46
-10
lines changed

apps/staking/src/api.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ export const loadData = async (
106106
pythnetClient: PythnetClient,
107107
hermesClient: HermesClient,
108108
stakeAccount?: PublicKey | undefined,
109+
simulationPayer?: PublicKey,
109110
): Promise<Data> =>
110111
stakeAccount === undefined
111112
? loadDataNoStakeAccount(client, pythnetClient, hermesClient)
@@ -114,6 +115,7 @@ export const loadData = async (
114115
pythnetClient,
115116
hermesClient,
116117
stakeAccount,
118+
simulationPayer,
117119
);
118120

119121
const loadDataNoStakeAccount = async (
@@ -149,6 +151,7 @@ const loadDataForStakeAccount = async (
149151
pythnetClient: PythnetClient,
150152
hermesClient: HermesClient,
151153
stakeAccount: PublicKey,
154+
simulationPayer?: PublicKey,
152155
): Promise<Data> => {
153156
const [
154157
{ publishers, ...baseInfo },
@@ -160,7 +163,7 @@ const loadDataForStakeAccount = async (
160163
loadBaseInfo(client, pythnetClient, hermesClient),
161164
client.getStakeAccountCustody(stakeAccount),
162165
client.getUnlockSchedule(stakeAccount),
163-
client.getClaimableRewards(stakeAccount),
166+
client.getClaimableRewards(stakeAccount, simulationPayer),
164167
client.getStakeAccountPositions(stakeAccount),
165168
]);
166169

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
MAINNET_RPC,
1515
HERMES_URL,
1616
PYTHNET_RPC,
17+
SIMULATION_PAYER_ADDRESS,
1718
} from "../../config/server";
1819
import { ApiProvider } from "../../hooks/use-api";
1920
import { LoggerProvider } from "../../hooks/use-logger";
@@ -82,7 +83,11 @@ const HtmlWithProviders = ({ lang, ...props }: HTMLProps<HTMLHtmlElement>) => (
8283
walletConnectProjectId={WALLETCONNECT_PROJECT_ID}
8384
mainnetRpc={MAINNET_RPC}
8485
>
85-
<ApiProvider hermesUrl={HERMES_URL} pythnetRpcUrl={PYTHNET_RPC}>
86+
<ApiProvider
87+
hermesUrl={HERMES_URL}
88+
pythnetRpcUrl={PYTHNET_RPC}
89+
simulationPayerAddress={SIMULATION_PAYER_ADDRESS}
90+
>
8691
<ToastProvider>
8792
<html lang={lang} {...props} />
8893
</ToastProvider>

apps/staking/src/config/server.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,12 @@ export const GOVERNANCE_ONLY_REGIONS = transformOr(
7474
[],
7575
);
7676
export const PROXYCHECK_API_KEY = demandInProduction("PROXYCHECK_API_KEY");
77-
77+
// 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
78+
// such simulation fails when the payer has no funds.
79+
export const SIMULATION_PAYER_ADDRESS = getOr(
80+
"SIMULATION_PAYER_ADDRESS",
81+
"E5KR7yfb9UyVB6ZhmhQki1rM1eBcxHvyGKFZakAC5uc",
82+
);
7883
class MissingEnvironmentError extends Error {
7984
constructor(name: string) {
8085
super(`Missing environment variable: ${name}!`);

apps/staking/src/hooks/use-api.tsx

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { HermesClient } from "@pythnetwork/hermes-client";
44
import { PythnetClient, PythStakingClient } from "@pythnetwork/staking-sdk";
55
import { useLocalStorageValue } from "@react-hookz/web";
66
import { useConnection, useWallet } from "@solana/wallet-adapter-react";
7-
import { Connection, type PublicKey } from "@solana/web3.js";
7+
import { Connection, PublicKey } from "@solana/web3.js";
88
import { type ComponentProps, createContext, useContext, useMemo } from "react";
99
import { useSWRConfig } from "swr";
1010

@@ -65,6 +65,7 @@ const State = {
6565
pythnetClient: PythnetClient,
6666
hermesClient: HermesClient,
6767
account: PublicKey,
68+
simulationPayer: PublicKey,
6869
allAccounts: [PublicKey, ...PublicKey[]],
6970
selectAccount: (account: PublicKey) => void,
7071
mutate: ReturnType<typeof useSWRConfig>["mutate"],
@@ -95,7 +96,13 @@ const State = {
9596
dashboardDataCacheKey,
9697

9798
loadData: () =>
98-
api.loadData(client, pythnetClient, hermesClient, account),
99+
api.loadData(
100+
client,
101+
pythnetClient,
102+
hermesClient,
103+
account,
104+
simulationPayer,
105+
),
99106

100107
claim: bindApi(api.claim),
101108
deposit: bindApi(api.deposit),
@@ -131,19 +138,25 @@ type ApiProviderProps = Omit<
131138
> & {
132139
pythnetRpcUrl: string;
133140
hermesUrl: string;
141+
simulationPayerAddress: string;
134142
};
135143

136144
export const ApiProvider = ({
137145
hermesUrl,
138146
pythnetRpcUrl,
147+
simulationPayerAddress,
139148
...props
140149
}: ApiProviderProps) => {
141-
const state = useApiContext(hermesUrl, pythnetRpcUrl);
150+
const state = useApiContext(hermesUrl, pythnetRpcUrl, simulationPayerAddress);
142151

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

146-
const useApiContext = (hermesUrl: string, pythnetRpcUrl: string) => {
155+
const useApiContext = (
156+
hermesUrl: string,
157+
pythnetRpcUrl: string,
158+
simulationPayerAddress: string,
159+
) => {
147160
const wallet = useWallet();
148161
const { connection } = useConnection();
149162
const { isMainnet } = useNetwork();
@@ -153,6 +166,10 @@ const useApiContext = (hermesUrl: string, pythnetRpcUrl: string) => {
153166
() => new PythnetClient(new Connection(pythnetRpcUrl)),
154167
[pythnetRpcUrl],
155168
);
169+
const simulationPayer = useMemo(
170+
() => new PublicKey(simulationPayerAddress),
171+
[simulationPayerAddress],
172+
);
156173
const pythStakingClient = useMemo(
157174
() =>
158175
wallet.publicKey && wallet.signAllTransactions && wallet.signTransaction
@@ -235,6 +252,7 @@ const useApiContext = (hermesUrl: string, pythnetRpcUrl: string) => {
235252
pythnetClient,
236253
hermesClient,
237254
selectedAccount ?? firstAccount,
255+
simulationPayer,
238256
[firstAccount, ...otherAccounts],
239257
(account: PublicKey) => {
240258
localStorageValue.set(account.toBase58());

governance/pyth_staking_sdk/src/pyth-staking-client.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,7 @@ export class PythStakingClient {
688688

689689
async getAdvanceDelegationRecordInstructions(
690690
stakeAccountPositions: PublicKey,
691+
payer?: PublicKey,
691692
) {
692693
const poolData = await this.getPoolDataAccount();
693694
const stakeAccountPositionsData = await this.getStakeAccountPositions(
@@ -745,7 +746,7 @@ export class PythStakingClient {
745746
this.integrityPoolProgram.methods
746747
.advanceDelegationRecord()
747748
.accountsPartial({
748-
payer: this.wallet.publicKey,
749+
payer: payer ?? this.wallet.publicKey,
749750
publisher: pubkey,
750751
publisherStakeAccountPositions: stakeAccount,
751752
publisherStakeAccountCustody: stakeAccount
@@ -795,16 +796,20 @@ export class PythStakingClient {
795796
);
796797
}
797798

798-
public async getClaimableRewards(stakeAccountPositions: PublicKey) {
799+
public async getClaimableRewards(
800+
stakeAccountPositions: PublicKey,
801+
simulationPayer?: PublicKey,
802+
) {
799803
const instructions = await this.getAdvanceDelegationRecordInstructions(
800804
stakeAccountPositions,
805+
simulationPayer,
801806
);
802807

803808
let totalRewards = 0n;
804809

805810
for (const instruction of instructions.advanceDelegationRecordInstructions) {
806811
const tx = new Transaction().add(instruction);
807-
tx.feePayer = this.wallet.publicKey;
812+
tx.feePayer = simulationPayer ?? this.wallet.publicKey;
808813
const res = await this.connection.simulateTransaction(tx);
809814
const val = res.value.returnData?.data[0];
810815
if (val === undefined) {

0 commit comments

Comments
 (0)