Skip to content
2 changes: 2 additions & 0 deletions governance/pyth_staking_sdk/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ const ONE_WEEK_IN_SECONDS = 7n * ONE_DAY_IN_SECONDS;

export const EPOCH_DURATION = ONE_WEEK_IN_SECONDS;

export const MAX_VOTER_WEIGHT = 10_000_000_000_000_000; // 10 Billion with 6 decimals

export const FRACTION_PRECISION = 1_000_000;
export const FRACTION_PRECISION_N = 1_000_000n;

Expand Down
7 changes: 7 additions & 0 deletions governance/pyth_staking_sdk/src/pdas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,10 @@ export const getDelegationRecordAddress = (
INTEGRITY_POOL_PROGRAM_ADDRESS,
)[0];
};

export const getTargetAccountAddress = () => {
return PublicKey.findProgramAddressSync(
[Buffer.from("target"), Buffer.from("voting")],
STAKING_PROGRAM_ADDRESS,
)[0];
};
48 changes: 47 additions & 1 deletion governance/pyth_staking_sdk/src/pyth-staking-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,26 @@ import {
TransactionInstruction,
} from "@solana/web3.js";

import { GOVERNANCE_ADDRESS, POSITIONS_ACCOUNT_SIZE } from "./constants";
import {
GOVERNANCE_ADDRESS,
MAX_VOTER_WEIGHT,
POSITIONS_ACCOUNT_SIZE,
} from "./constants";
import {
getConfigAddress,
getDelegationRecordAddress,
getPoolConfigAddress,
getStakeAccountCustodyAddress,
getStakeAccountMetadataAddress,
getTargetAccountAddress,
} from "./pdas";
import {
PositionState,
type GlobalConfig,
type PoolConfig,
type PoolDataAccount,
type StakeAccountPositions,
type TargetAccount,
} from "./types";
import { convertBigIntToBN, convertBNToBigInt } from "./utils/bn";
import { epochToDate, getCurrentEpoch } from "./utils/clock";
Expand Down Expand Up @@ -710,4 +716,44 @@ export class PythStakingClient {
undefined,
);
}

public async getTargetAccount(): Promise<TargetAccount> {
const targetAccount =
await this.stakingProgram.account.targetMetadata.fetch(
getTargetAccountAddress(),
);
return convertBNToBigInt(targetAccount);
}

/**
* This returns the current scaling factor between staked tokens and realms voter weight.
* The formula is n_staked_tokens = scaling_factor * n_voter_weight
*/
public async getScalingFactor(): Promise<number> {
const targetAccount = await this.getTargetAccount();
Copy link
Contributor

@guibescos guibescos Sep 19, 2024

Choose a reason for hiding this comment

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

Note: this is only valid if someone has cranked the target account (happens whenever someone stakes to unstakes, or whenever someome slashes). I generally think this approach seems fine

return Number(targetAccount.locked) / MAX_VOTER_WEIGHT;
}

public async getRecoverAccountInstruction(
stakeAccountPositions: PublicKey,
): Promise<TransactionInstruction> {
return this.stakingProgram.methods
.recoverAccount()
.accounts({
stakeAccountPositions,
})
.instruction();
}

public async getUpdatePoolAuthorityInstruction(
governanceAuthority: PublicKey,
poolAuthority: PublicKey,
): Promise<TransactionInstruction> {
return this.stakingProgram.methods
.updatePoolAuthority(poolAuthority)
.accounts({
governanceAuthority,
})
.instruction();
}
}
3 changes: 3 additions & 0 deletions governance/pyth_staking_sdk/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ export type TargetWithParameters = IdlTypes<Staking>["targetWithParameters"];
export type VestingScheduleAnchor = IdlTypes<Staking>["vestingSchedule"];
export type VestingSchedule = ConvertBNToBigInt<VestingScheduleAnchor>;

export type TargetAccountAnchor = IdlAccounts<Staking>["targetMetadata"];
export type TargetAccount = ConvertBNToBigInt<TargetAccountAnchor>;

export type UnlockSchedule = {
date: Date;
amount: bigint;
Expand Down
Loading