@@ -25,8 +25,9 @@ import {
25
25
} from "@solana/web3.js" ;
26
26
27
27
import {
28
- FRACTION_PRECISION_N ,
29
28
GOVERNANCE_ADDRESS ,
29
+ MAX_VOTER_WEIGHT ,
30
+ FRACTION_PRECISION_N ,
30
31
ONE_YEAR_IN_SECONDS ,
31
32
POSITIONS_ACCOUNT_SIZE ,
32
33
} from "./constants" ;
@@ -36,13 +37,16 @@ import {
36
37
getPoolConfigAddress ,
37
38
getStakeAccountCustodyAddress ,
38
39
getStakeAccountMetadataAddress ,
40
+ getTargetAccountAddress ,
39
41
} from "./pdas" ;
40
42
import {
41
43
PositionState ,
42
44
type GlobalConfig ,
43
45
type PoolConfig ,
44
46
type PoolDataAccount ,
45
47
type StakeAccountPositions ,
48
+ type TargetAccount ,
49
+ type VoterWeightAction ,
46
50
type VestingSchedule ,
47
51
} from "./types" ;
48
52
import { convertBigIntToBN , convertBNToBigInt } from "./utils/bn" ;
@@ -51,6 +55,7 @@ import { extractPublisherData } from "./utils/pool";
51
55
import {
52
56
deserializeStakeAccountPositions ,
53
57
getPositionState ,
58
+ getVotingTokenAmount ,
54
59
} from "./utils/position" ;
55
60
import { sendTransaction } from "./utils/transaction" ;
56
61
import { getUnlockSchedule } from "./utils/vesting" ;
@@ -750,6 +755,121 @@ export class PythStakingClient {
750
755
) ;
751
756
}
752
757
758
+ public async getTargetAccount ( ) : Promise < TargetAccount > {
759
+ const targetAccount =
760
+ await this . stakingProgram . account . targetMetadata . fetch (
761
+ getTargetAccountAddress ( ) ,
762
+ ) ;
763
+ return convertBNToBigInt ( targetAccount ) ;
764
+ }
765
+
766
+ /**
767
+ * This returns the current scaling factor between staked tokens and realms voter weight.
768
+ * The formula is n_staked_tokens = scaling_factor * n_voter_weight
769
+ */
770
+ public async getScalingFactor ( ) : Promise < number > {
771
+ const targetAccount = await this . getTargetAccount ( ) ;
772
+ return Number ( targetAccount . locked ) / Number ( MAX_VOTER_WEIGHT ) ;
773
+ }
774
+
775
+ public async getRecoverAccountInstruction (
776
+ stakeAccountPositions : PublicKey ,
777
+ governanceAuthority : PublicKey ,
778
+ ) : Promise < TransactionInstruction > {
779
+ return this . stakingProgram . methods
780
+ . recoverAccount ( )
781
+ . accountsPartial ( {
782
+ stakeAccountPositions,
783
+ governanceAuthority,
784
+ } )
785
+ . instruction ( ) ;
786
+ }
787
+
788
+ public async getUpdatePoolAuthorityInstruction (
789
+ governanceAuthority : PublicKey ,
790
+ poolAuthority : PublicKey ,
791
+ ) : Promise < TransactionInstruction > {
792
+ return this . stakingProgram . methods
793
+ . updatePoolAuthority ( poolAuthority )
794
+ . accounts ( {
795
+ governanceAuthority,
796
+ } )
797
+ . instruction ( ) ;
798
+ }
799
+
800
+ public async getUpdateVoterWeightInstruction (
801
+ stakeAccountPositions : PublicKey ,
802
+ action : VoterWeightAction ,
803
+ remainingAccount ?: PublicKey ,
804
+ ) {
805
+ return this . stakingProgram . methods
806
+ . updateVoterWeight ( action )
807
+ . accounts ( {
808
+ stakeAccountPositions,
809
+ } )
810
+ . remainingAccounts (
811
+ remainingAccount
812
+ ? [
813
+ {
814
+ pubkey : remainingAccount ,
815
+ isWritable : false ,
816
+ isSigner : false ,
817
+ } ,
818
+ ]
819
+ : [ ] ,
820
+ )
821
+ . instruction ( ) ;
822
+ }
823
+
824
+ public async getMainStakeAccount ( owner ?: PublicKey ) {
825
+ const stakeAccountPositions = await this . getAllStakeAccountPositions ( owner ) ;
826
+ const currentEpoch = await getCurrentEpoch ( this . connection ) ;
827
+
828
+ const stakeAccountVotingTokens = await Promise . all (
829
+ stakeAccountPositions . map ( async ( position ) => {
830
+ const stakeAccountPositionsData =
831
+ await this . getStakeAccountPositions ( position ) ;
832
+ return {
833
+ stakeAccountPosition : position ,
834
+ votingTokens : getVotingTokenAmount (
835
+ stakeAccountPositionsData ,
836
+ currentEpoch ,
837
+ ) ,
838
+ } ;
839
+ } ) ,
840
+ ) ;
841
+
842
+ let mainAccount = stakeAccountVotingTokens [ 0 ] ;
843
+
844
+ if ( mainAccount === undefined ) {
845
+ return ;
846
+ }
847
+
848
+ for ( let i = 1 ; i < stakeAccountVotingTokens . length ; i ++ ) {
849
+ const currentAccount = stakeAccountVotingTokens [ i ] ;
850
+ if (
851
+ currentAccount !== undefined &&
852
+ currentAccount . votingTokens > mainAccount . votingTokens
853
+ ) {
854
+ mainAccount = currentAccount ;
855
+ }
856
+ }
857
+
858
+ return mainAccount ;
859
+ }
860
+
861
+ public async getVoterWeight ( owner ?: PublicKey ) {
862
+ const mainAccount = await this . getMainStakeAccount ( owner ) ;
863
+
864
+ if ( mainAccount === undefined ) {
865
+ return 0 ;
866
+ }
867
+
868
+ const targetAccount = await this . getTargetAccount ( ) ;
869
+
870
+ return ( mainAccount . votingTokens * MAX_VOTER_WEIGHT ) / targetAccount . locked ;
871
+ }
872
+
753
873
public async getPythTokenMint ( ) : Promise < Mint > {
754
874
const globalConfig = await this . getGlobalConfig ( ) ;
755
875
return getMint ( this . connection , globalConfig . pythTokenMint ) ;
0 commit comments