@wireio/stake 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/README.md +57 -0
  2. package/lib/stake.browser.js +11836 -4103
  3. package/lib/stake.browser.js.map +1 -1
  4. package/lib/stake.d.ts +374 -556
  5. package/lib/stake.js +12089 -4303
  6. package/lib/stake.js.map +1 -1
  7. package/lib/stake.m.js +11836 -4103
  8. package/lib/stake.m.js.map +1 -1
  9. package/package.json +1 -1
  10. package/src/assets/ethereum/ABI/liqEth/DepositManager.sol/DepositManager.dbg.json +4 -0
  11. package/src/assets/ethereum/ABI/liqEth/DepositManager.sol/DepositManager.json +1153 -0
  12. package/src/assets/ethereum/ABI/liqEth/LiqEthCommon.sol/IAccounting.dbg.json +4 -0
  13. package/src/assets/ethereum/ABI/liqEth/LiqEthCommon.sol/IAccounting.json +172 -0
  14. package/src/assets/ethereum/ABI/liqEth/LiqEthCommon.sol/IDepositContract.dbg.json +4 -0
  15. package/src/assets/ethereum/ABI/liqEth/LiqEthCommon.sol/IDepositContract.json +39 -0
  16. package/src/assets/ethereum/ABI/liqEth/LiqEthCommon.sol/IDepositManager.dbg.json +4 -0
  17. package/src/assets/ethereum/ABI/liqEth/LiqEthCommon.sol/IDepositManager.json +64 -0
  18. package/src/assets/ethereum/ABI/liqEth/LiqEthCommon.sol/ILiqEthBurn.dbg.json +4 -0
  19. package/src/assets/ethereum/ABI/liqEth/LiqEthCommon.sol/ILiqEthBurn.json +24 -0
  20. package/src/assets/ethereum/ABI/liqEth/LiqEthCommon.sol/ILiqEthMint.dbg.json +4 -0
  21. package/src/assets/ethereum/ABI/liqEth/LiqEthCommon.sol/ILiqEthMint.json +35 -0
  22. package/src/assets/ethereum/ABI/liqEth/LiqEthCommon.sol/IRewardsERC20.dbg.json +4 -0
  23. package/src/assets/ethereum/ABI/liqEth/LiqEthCommon.sol/IRewardsERC20.json +213 -0
  24. package/src/assets/ethereum/ABI/liqEth/LiqEthCommon.sol/IStakingModule.dbg.json +4 -0
  25. package/src/assets/ethereum/ABI/liqEth/LiqEthCommon.sol/IStakingModule.json +138 -0
  26. package/src/assets/ethereum/ABI/liqEth/LiqEthCommon.sol/IValidatorBalanceVerifier.dbg.json +4 -0
  27. package/src/assets/ethereum/ABI/liqEth/LiqEthCommon.sol/IValidatorBalanceVerifier.json +70 -0
  28. package/src/assets/ethereum/ABI/liqEth/LiqEthCommon.sol/IWithdrawalRecord.dbg.json +4 -0
  29. package/src/assets/ethereum/ABI/liqEth/LiqEthCommon.sol/IWithdrawalRecord.json +64 -0
  30. package/src/assets/ethereum/ABI/liqEth/LiqEthCommon.sol/LiqEthCommon.dbg.json +4 -0
  31. package/src/assets/ethereum/ABI/liqEth/LiqEthCommon.sol/LiqEthCommon.json +10 -0
  32. package/src/assets/ethereum/ABI/liqEth/RewardsERC20.sol/RewardsERC20.dbg.json +4 -0
  33. package/src/assets/ethereum/ABI/liqEth/RewardsERC20.sol/RewardsERC20.json +749 -0
  34. package/src/assets/ethereum/ABI/liqEth/RewardsERC20Pausable.sol/RewardsERC20Pausable.dbg.json +4 -0
  35. package/src/assets/ethereum/ABI/liqEth/RewardsERC20Pausable.sol/RewardsERC20Pausable.json +812 -0
  36. package/src/assets/ethereum/ABI/liqEth/ValidatorBalanceVerifier.sol/BeaconRoots.dbg.json +4 -0
  37. package/src/assets/ethereum/ABI/liqEth/ValidatorBalanceVerifier.sol/BeaconRoots.json +10 -0
  38. package/src/assets/ethereum/ABI/liqEth/ValidatorBalanceVerifier.sol/SSZ.dbg.json +4 -0
  39. package/src/assets/ethereum/ABI/liqEth/ValidatorBalanceVerifier.sol/SSZ.json +10 -0
  40. package/src/assets/ethereum/ABI/liqEth/ValidatorBalanceVerifier.sol/ValidatorBalanceVerifier.dbg.json +4 -0
  41. package/src/assets/ethereum/ABI/liqEth/ValidatorBalanceVerifier.sol/ValidatorBalanceVerifier.json +225 -0
  42. package/src/assets/ethereum/ABI/liqEth/Yield.sol/BeaconRoots.dbg.json +4 -0
  43. package/src/assets/ethereum/ABI/liqEth/Yield.sol/BeaconRoots.json +10 -0
  44. package/src/assets/ethereum/ABI/liqEth/Yield.sol/SSZ.dbg.json +4 -0
  45. package/src/assets/ethereum/ABI/liqEth/Yield.sol/SSZ.json +10 -0
  46. package/src/assets/ethereum/ABI/liqEth/Yield.sol/YieldOracle.dbg.json +4 -0
  47. package/src/assets/ethereum/ABI/liqEth/Yield.sol/YieldOracle.json +813 -0
  48. package/src/assets/ethereum/ABI/liqEth/accounting.sol/Accounting.dbg.json +4 -0
  49. package/src/assets/ethereum/ABI/liqEth/accounting.sol/Accounting.json +651 -0
  50. package/src/assets/ethereum/ABI/liqEth/liqEth.sol/LiqEthToken.dbg.json +4 -0
  51. package/src/assets/ethereum/ABI/liqEth/liqEth.sol/LiqEthToken.json +1110 -0
  52. package/src/assets/ethereum/ABI/liqEth/liqEthBurn.sol/LiqEthBurn.dbg.json +4 -0
  53. package/src/assets/ethereum/ABI/liqEth/liqEthBurn.sol/LiqEthBurn.json +391 -0
  54. package/src/assets/ethereum/ABI/liqEth/liqEthMint.sol/LiqEthMint.dbg.json +4 -0
  55. package/src/assets/ethereum/ABI/liqEth/liqEthMint.sol/LiqEthMint.json +402 -0
  56. package/src/assets/ethereum/ABI/liqEth/stakingModule.sol/StakingModule.dbg.json +4 -0
  57. package/src/assets/ethereum/ABI/liqEth/stakingModule.sol/StakingModule.json +1225 -0
  58. package/src/assets/ethereum/ABI/liqEth/withdrawalQueue.sol/WithdrawalQueue.dbg.json +4 -0
  59. package/src/assets/ethereum/ABI/liqEth/withdrawalQueue.sol/WithdrawalQueue.json +927 -0
  60. package/src/assets/ethereum/ABI/liqEth/withdrawalVault.sol/Uint64BE.dbg.json +4 -0
  61. package/src/assets/ethereum/ABI/liqEth/withdrawalVault.sol/Uint64BE.json +10 -0
  62. package/src/assets/ethereum/ABI/liqEth/withdrawalVault.sol/WithdrawalVault.dbg.json +4 -0
  63. package/src/assets/ethereum/ABI/liqEth/withdrawalVault.sol/WithdrawalVault.json +447 -0
  64. package/src/assets/solana/idl/liqsol_core.json +4239 -0
  65. package/src/assets/solana/idl/liqsol_token.json +183 -0
  66. package/src/assets/solana/idl/validator_leaderboard.json +270 -265
  67. package/src/assets/solana/types/liqsol_core.ts +4245 -0
  68. package/src/assets/solana/types/liqsol_token.ts +189 -0
  69. package/src/assets/solana/types/validator_leaderboard.ts +270 -265
  70. package/src/index.ts +1 -3
  71. package/src/networks/ethereum/contract.ts +101 -36
  72. package/src/networks/ethereum/ethereum.ts +141 -45
  73. package/src/networks/ethereum/types.ts +30 -2
  74. package/src/networks/solana/clients/deposit.client.ts +71 -109
  75. package/src/networks/solana/clients/distribution.client.ts +256 -383
  76. package/src/networks/solana/clients/leaderboard.client.ts +38 -133
  77. package/src/networks/solana/constants.ts +214 -130
  78. package/src/networks/solana/program.ts +25 -38
  79. package/src/networks/solana/solana.ts +120 -105
  80. package/src/networks/solana/types.ts +37 -47
  81. package/src/networks/solana/utils.ts +551 -0
  82. package/src/scripts/tsconfig.json +17 -0
  83. package/src/staker/staker.ts +10 -6
  84. package/src/staker/types.ts +14 -9
  85. package/src/assets/solana/idl/deposit.json +0 -296
  86. package/src/assets/solana/idl/distribution.json +0 -768
  87. package/src/assets/solana/idl/liq_sol_token.json +0 -298
  88. package/src/assets/solana/idl/mint_helper.json +0 -110
  89. package/src/assets/solana/idl/read_tracked_balance.json +0 -140
  90. package/src/assets/solana/idl/stake_controller.json +0 -2149
  91. package/src/assets/solana/idl/treasury.json +0 -110
  92. package/src/assets/solana/idl/validator_registry.json +0 -487
  93. package/src/assets/solana/idl/yield_oracle.json +0 -32
  94. package/src/assets/solana/types/deposit.ts +0 -302
  95. package/src/assets/solana/types/distribution.ts +0 -774
  96. package/src/assets/solana/types/liq_sol_token.ts +0 -304
  97. package/src/assets/solana/types/mint_helper.ts +0 -116
  98. package/src/assets/solana/types/read_tracked_balance.ts +0 -146
  99. package/src/assets/solana/types/stake_controller.ts +0 -2155
  100. package/src/assets/solana/types/stake_registry.ts +0 -441
  101. package/src/assets/solana/types/treasury.ts +0 -116
  102. package/src/assets/solana/types/validator_registry.ts +0 -493
  103. package/src/assets/solana/types/yield_oracle.ts +0 -38
  104. package/src/common/utils.ts +0 -9
@@ -1,154 +1,59 @@
1
- import { AnchorProvider, Program, BN } from '@coral-xyz/anchor';
2
- import { PublicKey, SystemProgram, Transaction, TransactionInstruction } from '@solana/web3.js';
1
+ import { AnchorProvider, Program } from '@coral-xyz/anchor';
2
+ import { PublicKey } from '@solana/web3.js';
3
+
3
4
  import { SolanaProgramService } from '../program';
4
5
  import type { ValidatorLeaderboard } from '../../../assets/solana/types/validator_leaderboard';
5
6
  import {
6
- deriveLeaderboardHeadPDA,
7
- deriveValidatorRecordPDA,
8
- deriveTop10CachePDA,
7
+ deriveLeaderboardStatePda,
8
+ deriveValidatorRecordPda,
9
9
  } from '../constants';
10
10
 
11
- export class ValidatorLeaderboardClient {
12
- private programs: SolanaProgramService;
11
+ /**
12
+ * Simple read client for the validator_leaderboard program.
13
+ *
14
+ * Adjust account names/fields to match your IDL (state, validatorRecord, etc).
15
+ */
16
+ export class LeaderboardClient {
17
+ private program: Program<ValidatorLeaderboard>;
13
18
 
14
19
  constructor(private provider: AnchorProvider) {
15
- this.programs = new SolanaProgramService(provider);
16
- }
17
-
18
- /** Anchor Program<ValidatorLeaderboard> via ProgramService */
19
- private get program(): Program<ValidatorLeaderboard> {
20
- return this.programs.getProgram('validatorLeaderboard') as Program<ValidatorLeaderboard>;
21
- }
22
-
23
- // ───────────────────────────────────────────────────────────────────────────────
24
- // BUILDERS (return Ixs so you can batch)
25
- // ───────────────────────────────────────────────────────────────────────────────
26
-
27
- /** Initialize the leaderboard head account. */
28
- async buildInitializeIx(authority: PublicKey): Promise<TransactionInstruction> {
29
- const [leaderboardHead] = deriveLeaderboardHeadPDA();
30
- return this.program.methods
31
- .initialize()
32
- .accounts({
33
- authority,
34
- // @ts-ignore
35
- leaderboardHead,
36
- systemProgram: SystemProgram.programId,
37
- })
38
- .instruction();
39
- }
40
-
41
- /**
42
- * Upsert/update a validator record and (optionally) reposition it in the linked list.
43
- * Any of insertAfter/insertBefore/currentPrev/currentNext can be omitted.
44
- */
45
- async buildUpdateValidatorIx(params: {
46
- registrant: PublicKey;
47
- voteAccount: PublicKey;
48
- vpp: number; // Validator Performance Points
49
- insertAfter?: PublicKey;
50
- insertBefore?: PublicKey;
51
- currentPrev?: PublicKey;
52
- currentNext?: PublicKey;
53
- }): Promise<TransactionInstruction> {
54
- const { registrant, voteAccount, vpp, insertAfter, insertBefore, currentPrev, currentNext } = params;
55
-
56
- const [leaderboardHead] = deriveLeaderboardHeadPDA();
57
- const [validatorRecord] = deriveValidatorRecordPDA(voteAccount);
58
-
59
- const accounts: any = {
60
- registrant,
61
- voteAccount,
62
- validatorRecord,
63
- leaderboardHead,
64
- systemProgram: SystemProgram.programId,
65
- ...(insertAfter && { insertAfter }),
66
- ...(insertBefore && { insertBefore }),
67
- ...(currentPrev && { currentPrev }),
68
- ...(currentNext && { currentNext }),
69
- };
70
-
71
- return this.program.methods
72
- .updateValidator(new BN(vpp))
73
- .accounts(accounts)
74
- .instruction();
75
- }
76
-
77
- /** Update the Top-10 cache. Requires exactly 10 validator vote accounts. */
78
- async buildUpdateTop10CacheIx(params: {
79
- authority: PublicKey;
80
- top10Validators: PublicKey[];
81
- }): Promise<TransactionInstruction> {
82
- const { authority, top10Validators } = params;
83
- if (top10Validators.length !== 10) throw new Error('Must provide exactly 10 validators');
84
-
85
- const [cache] = deriveTop10CachePDA();
86
- return this.program.methods
87
- .updateTop10Cache(top10Validators)
88
- .accounts({
89
- // @ts-ignore
90
- authority,
91
- cache,
92
- systemProgram: SystemProgram.programId,
93
- })
94
- .instruction();
95
- }
96
-
97
- // Convenience wrappers if you want a ready-to-send Transaction
98
-
99
- async buildInitializeTx(authority: PublicKey): Promise<Transaction> {
100
- return new Transaction().add(await this.buildInitializeIx(authority));
101
- }
102
-
103
- async buildUpdateValidatorTx(params: {
104
- registrant: PublicKey;
105
- voteAccount: PublicKey;
106
- vpp: number;
107
- insertAfter?: PublicKey;
108
- insertBefore?: PublicKey;
109
- currentPrev?: PublicKey;
110
- currentNext?: PublicKey;
111
- }): Promise<Transaction> {
112
- return new Transaction().add(await this.buildUpdateValidatorIx(params));
113
- }
114
-
115
- async buildUpdateTop10CacheTx(params: {
116
- authority: PublicKey;
117
- top10Validators: PublicKey[];
118
- }): Promise<Transaction> {
119
- return new Transaction().add(await this.buildUpdateTop10CacheIx(params));
20
+ const svc = new SolanaProgramService(provider);
21
+ this.program = svc.getProgram('validatorLeaderboard');
120
22
  }
121
23
 
122
- // ───────────────────────────────────────────────────────────────────────────────
123
- // READ HELPERS
124
- // ───────────────────────────────────────────────────────────────────────────────
125
-
126
- /** Traverse the linked-list leaderboard, returning vote accounts in order. */
127
- async getLeaderboard(): Promise<PublicKey[]> {
128
- const [head] = deriveLeaderboardHeadPDA();
129
- let headAcc;
24
+ async getState(): Promise<any | null> {
25
+ const pda = deriveLeaderboardStatePda();
130
26
  try {
131
- headAcc = await this.program.account.leaderboardHead.fetch(head);
27
+ // Assumes account name "leaderboardState"
28
+ return await this.program.account.leaderboardState.fetch(pda);
132
29
  } catch {
133
- return [];
134
- }
135
- const out: PublicKey[] = [];
136
- let cursor: PublicKey = headAcc.nextValidator;
137
- while (cursor && !cursor.equals(PublicKey.default)) {
138
- out.push(cursor);
139
- const rec = await this.program.account.validatorRecord.fetch(cursor);
140
- cursor = rec.nextValidator;
30
+ return null;
141
31
  }
142
- return out;
143
32
  }
144
33
 
145
- /** Fetch a single validator record (or null if it doesn't exist). */
146
34
  async getValidatorRecord(voteAccount: PublicKey): Promise<any | null> {
147
- const [recPda] = deriveValidatorRecordPDA(voteAccount);
35
+ const pda = deriveValidatorRecordPda(voteAccount);
148
36
  try {
149
- return await this.program.account.validatorRecord.fetch(recPda);
37
+ // Assumes account name "validatorRecord"
38
+ return await this.program.account.validatorRecord.fetchNullable(pda);
150
39
  } catch {
151
40
  return null;
152
41
  }
153
42
  }
43
+
44
+ /**
45
+ * Convenience helper to fetch and sort top validators by score.
46
+ * Assumes `validatorRecord` has a numeric `score` field in the IDL.
47
+ */
48
+ async getTopValidators(limit = 20): Promise<any[]> {
49
+ const records = await (this.program.account as any).validatorRecord.all();
50
+ const sorted = (records as Array<{ publicKey: PublicKey; account: any }>).sort(
51
+ (a, b) => {
52
+ const sa = BigInt(a.account.score?.toString?.() ?? '0');
53
+ const sb = BigInt(b.account.score?.toString?.() ?? '0');
54
+ return sb > sa ? 1 : sb < sa ? -1 : 0;
55
+ },
56
+ );
57
+ return sorted.slice(0, limit);
58
+ }
154
59
  }
@@ -1,158 +1,242 @@
1
1
  // src/networks/solana/constants.ts
2
- import { PublicKey } from '@solana/web3.js';
3
- import {
4
- ASSOCIATED_TOKEN_PROGRAM_ID,
5
- TOKEN_2022_PROGRAM_ID,
6
- getAssociatedTokenAddressSync,
7
- } from '@solana/spl-token';
8
- import { AnchorProvider, Program } from '@coral-xyz/anchor';
9
-
10
- // IDLs (as generated artifacts)
11
- import DepositIDL from '../../assets/solana/idl/deposit.json';
12
- import StakeControllerIDL from '../../assets/solana/idl/stake_controller.json';
13
- import ValidatorLeaderboardIDL from '../../assets/solana/idl/validator_leaderboard.json';
14
- import LiqSolTokenIDL from '../../assets/solana/idl/liq_sol_token.json';
15
- import DistributionIDL from '../../assets/solana/idl/distribution.json';
16
- import YieldOracleIDL from '../../assets/solana/idl/yield_oracle.json';
17
-
18
- // Types (optional; keep the ones you use)
19
- import type { Deposit } from '../../assets/solana/types/deposit';
20
-
21
- // ---------- Program IDs (from IDL.address) ----------
22
- export const DEPOSIT_PROGRAM_ID = new PublicKey(DepositIDL.address);
23
- export const STAKE_CONTROLLER_PROGRAM_ID = new PublicKey(StakeControllerIDL.address);
24
- export const VALIDATOR_LEADERBOARD_PROGRAM_ID = new PublicKey(ValidatorLeaderboardIDL.address);
25
- export const LIQSOL_TOKEN_PROGRAM_ID = new PublicKey(LiqSolTokenIDL.address);
26
- export const DISTRIBUTION_PROGRAM_ID = new PublicKey(DistributionIDL.address);
27
- export const YIELD_ORACLE_PROGRAM_ID = new PublicKey(YieldOracleIDL.address);
28
-
29
- // ---------- Protocol constants ----------
30
- export const MIN_SOL_TO_PARTICIPATE = 1_000_000_000; // 1 SOL (lamports)
31
-
32
- // The liqSOL Mint is a PDA on the LiqSOL token program
33
- export const LIQSOL_MINT_ADDRESS: PublicKey = PublicKey.findProgramAddressSync(
34
- [Buffer.from('liq_sol_mint')],
35
- LIQSOL_TOKEN_PROGRAM_ID
36
- )[0];
37
-
38
- // Re-export SPL ids
39
- export { ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID };
40
-
41
- // ---------- Program factories ----------
42
- /** Create Anchor Program client for the Deposit program (with correct address) */
43
- export const getDepositProgram = (provider: AnchorProvider): Program<Deposit> => {
44
- const idlWithAddress = { ...JSON.parse(JSON.stringify(DepositIDL)), address: DEPOSIT_PROGRAM_ID.toString() };
45
- return new Program(idlWithAddress as any, provider) as Program<Deposit>;
46
- };
47
-
48
- // You can add similar helpers for other programs if you want:
49
- // export const getDistributionProgram = <T>(provider: AnchorProvider) => { ... }
50
-
51
- // ---------- PDA helpers ----------
52
-
53
- // Deposit
54
- export const deriveDepositAuthorityPDA = (): [PublicKey, number] =>
2
+ import { PublicKey, StakeProgram } from '@solana/web3.js';
3
+
4
+ import liqsolCoreIDL from "../../assets/solana/idl/liqsol_core.json";
5
+ import liqSolTokenIDL from "../../assets/solana/idl/liqsol_token.json";
6
+ import validatorLeaderboardIDL from "../../assets/solana/idl/validator_leaderboard.json";
7
+
8
+ /**
9
+ * ---------------------------------------------------------------------------
10
+ * PROGRAM IDS
11
+ * ---------------------------------------------------------------------------
12
+ *
13
+ * These should match:
14
+ * - `metadata.address` in your Anchor IDLs under src/assets/solana/idl/*.json
15
+ * - The program IDs printed by your deploy scripts
16
+ */
17
+ // Extract program IDs from IDL files
18
+ export const PROGRAM_IDS = {
19
+ LIQSOL_CORE: new PublicKey(liqsolCoreIDL.address),
20
+ LIQSOL_TOKEN: new PublicKey(liqSolTokenIDL.address),
21
+ VALIDATOR_LEADERBOARD: new PublicKey(validatorLeaderboardIDL.address),
22
+ } as const;
23
+
24
+ // Export individual program IDs for convenience
25
+ export const {
26
+ LIQSOL_CORE,
27
+ LIQSOL_TOKEN,
28
+ VALIDATOR_LEADERBOARD,
29
+ } = PROGRAM_IDS;
30
+
31
+ /**
32
+ * ---------------------------------------------------------------------------
33
+ * PDA SEEDS (must match on-chain programs)
34
+ * ---------------------------------------------------------------------------
35
+ *
36
+ * These strings are baked into the on-chain programs and are already used in
37
+ * your test utils. We centralize them here so all clients share them.
38
+ */
39
+
40
+ export const PDA_SEEDS = {
41
+ // liqsol_core: deposit / stake controller
42
+ DEPOSIT_AUTHORITY: 'deposit_authority',
43
+ VAULT: 'vault',
44
+ RESERVE_POOL: 'reserve_pool',
45
+ STAKE_CONTROLLER_STATE: 'stake_controller',
46
+ PAYOUT_STATE: 'payout-state',
47
+
48
+ // liqsol_token: mint + bucket
49
+ LIQSOL_MINT: 'liqsol_mint',
50
+ LIQSOL_MINT_AUTHORITY: 'mint_authority',
51
+ BUCKET_AUTHORITY: 'liqsol_bucket',
52
+
53
+ // distribution program (embedded in liqsol_core)
54
+ DISTRIBUTION_STATE: 'distribution_state',
55
+ USER_RECORD: 'user_record',
56
+
57
+ // pay-rate history
58
+ PAY_RATE_HISTORY: 'pay_rate_history',
59
+
60
+ // validator leaderboard (state + records)
61
+ LEADERBOARD_STATE: 'leaderboard_state',
62
+ VALIDATOR_RECORD: 'validator',
63
+ GLOBAL_STAKE_INFO: 'global_stake_info',
64
+ } as const;
65
+
66
+ /**
67
+ * Helpers for PDA derivation so clients don’t duplicate logic.
68
+ */
69
+
70
+ export const deriveLiqsolMintPda = () =>
55
71
  PublicKey.findProgramAddressSync(
56
- [Buffer.from('program_authority')],
57
- DEPOSIT_PROGRAM_ID
58
- );
72
+ [Buffer.from(PDA_SEEDS.LIQSOL_MINT)],
73
+ PROGRAM_IDS.LIQSOL_TOKEN,
74
+ )[0];
59
75
 
60
- // LiqSOL Token program
61
- export const deriveLiqsolMintPDA = (): [PublicKey, number] =>
76
+ export const deriveLiqsolMintAuthorityPda = () =>
62
77
  PublicKey.findProgramAddressSync(
63
- [Buffer.from('liq_sol_mint')],
64
- LIQSOL_TOKEN_PROGRAM_ID
65
- );
78
+ [Buffer.from(PDA_SEEDS.LIQSOL_MINT_AUTHORITY)],
79
+ PROGRAM_IDS.LIQSOL_TOKEN,
80
+ )[0];
66
81
 
67
- /** FIXED: this must be derived with the LiqSOL token **program id**, not the mint address */
68
- export const deriveLiqsolMintAuthorityPDA = (): [PublicKey, number] =>
82
+ export const deriveDepositAuthorityPda = () =>
69
83
  PublicKey.findProgramAddressSync(
70
- [Buffer.from('mint_authority')],
71
- LIQSOL_TOKEN_PROGRAM_ID
72
- );
84
+ [Buffer.from(PDA_SEEDS.DEPOSIT_AUTHORITY)],
85
+ PROGRAM_IDS.LIQSOL_CORE,
86
+ )[0];
73
87
 
74
- // Stake Controller
75
- export const deriveStakeControllerVaultPDA = (): [PublicKey, number] =>
88
+ export const deriveVaultPda = () =>
76
89
  PublicKey.findProgramAddressSync(
77
- [Buffer.from('vault')],
78
- STAKE_CONTROLLER_PROGRAM_ID
79
- );
90
+ [Buffer.from(PDA_SEEDS.VAULT)],
91
+ PROGRAM_IDS.LIQSOL_CORE,
92
+ )[0];
80
93
 
81
- export const deriveStakeControllerReservePoolPDA = (): [PublicKey, number] =>
94
+ export const deriveReservePoolPda = () =>
82
95
  PublicKey.findProgramAddressSync(
83
- [Buffer.from('reserve_pool')],
84
- STAKE_CONTROLLER_PROGRAM_ID
85
- );
96
+ [Buffer.from(PDA_SEEDS.RESERVE_POOL)],
97
+ PROGRAM_IDS.LIQSOL_CORE,
98
+ )[0];
86
99
 
87
- export const deriveStakeControllerStatePDA = (): [PublicKey, number] =>
100
+ export const deriveStakeControllerStatePda = () =>
88
101
  PublicKey.findProgramAddressSync(
89
- [Buffer.from('stake_controller')],
90
- STAKE_CONTROLLER_PROGRAM_ID
91
- );
102
+ [Buffer.from(PDA_SEEDS.STAKE_CONTROLLER_STATE)],
103
+ PROGRAM_IDS.LIQSOL_CORE,
104
+ )[0];
92
105
 
93
- export const deriveGlobalStakeInfoPDA = (): [PublicKey, number] =>
106
+ export const derivePayoutStatePda = () =>
94
107
  PublicKey.findProgramAddressSync(
95
- [Buffer.from('global_stake_info')],
96
- STAKE_CONTROLLER_PROGRAM_ID
97
- );
108
+ [Buffer.from(PDA_SEEDS.PAYOUT_STATE)],
109
+ PROGRAM_IDS.LIQSOL_CORE,
110
+ )[0];
98
111
 
99
- export const deriveBucketAuthorityPDA = (): [PublicKey, number] =>
112
+ export const deriveBucketAuthorityPda = () =>
100
113
  PublicKey.findProgramAddressSync(
101
- [Buffer.from('liqsol_bucket')],
102
- STAKE_CONTROLLER_PROGRAM_ID
103
- );
114
+ [Buffer.from(PDA_SEEDS.BUCKET_AUTHORITY)],
115
+ PROGRAM_IDS.LIQSOL_CORE,
116
+ )[0];
104
117
 
105
- export const derivePayRateHistoryPDA = (): [PublicKey, number] =>
118
+ export const deriveDistributionStatePda = () =>
106
119
  PublicKey.findProgramAddressSync(
107
- [Buffer.from('pay_rate_history')],
108
- STAKE_CONTROLLER_PROGRAM_ID
109
- );
120
+ [Buffer.from(PDA_SEEDS.DISTRIBUTION_STATE)],
121
+ PROGRAM_IDS.LIQSOL_CORE,
122
+ )[0];
110
123
 
111
- // Distribution
112
- export const deriveDistributionStatePDA = (): [PublicKey, number] =>
124
+ export const deriveUserRecordPda = (user: PublicKey) =>
113
125
  PublicKey.findProgramAddressSync(
114
- [Buffer.from('distribution_state')],
115
- DISTRIBUTION_PROGRAM_ID
116
- );
126
+ [Buffer.from(PDA_SEEDS.USER_RECORD), user.toBuffer()],
127
+ PROGRAM_IDS.LIQSOL_CORE,
128
+ )[0];
117
129
 
118
- export const deriveUserRecordPDA = (user: PublicKey): [PublicKey, number] =>
130
+ export const derivePayRateHistoryPda = () =>
119
131
  PublicKey.findProgramAddressSync(
120
- [Buffer.from('user_record'), user.toBuffer()],
121
- DISTRIBUTION_PROGRAM_ID
122
- );
132
+ [Buffer.from(PDA_SEEDS.PAY_RATE_HISTORY)],
133
+ PROGRAM_IDS.LIQSOL_CORE,
134
+ )[0];
123
135
 
124
- // Validator Leaderboard
125
- export const deriveLeaderboardHeadPDA = (): [PublicKey, number] =>
126
- PublicKey.findProgramAddressSync(
127
- [Buffer.from('leaderboard_head')],
128
- VALIDATOR_LEADERBOARD_PROGRAM_ID
129
- );
136
+ // export const deriveGlobalStakeInfoPda = () =>
137
+ // PublicKey.findProgramAddressSync(
138
+ // [Buffer.from(PDA_SEEDS.GLOBAL_STAKE_INFO)],
139
+ // PROGRAM_IDS.LIQSOL_CORE,
140
+ // )[0];
130
141
 
131
- export const deriveValidatorRecordPDA = (voteAccount: PublicKey): [PublicKey, number] =>
142
+ export const deriveLeaderboardStatePda = () =>
132
143
  PublicKey.findProgramAddressSync(
133
- [Buffer.from('validator_record'), voteAccount.toBuffer()],
134
- VALIDATOR_LEADERBOARD_PROGRAM_ID
135
- );
144
+ [Buffer.from(PDA_SEEDS.LEADERBOARD_STATE)],
145
+ PROGRAM_IDS.VALIDATOR_LEADERBOARD,
146
+ )[0];
136
147
 
137
- export const deriveTop10CachePDA = (): [PublicKey, number] =>
148
+ export const deriveValidatorRecordPda = (voteAccount: PublicKey) =>
138
149
  PublicKey.findProgramAddressSync(
139
- [Buffer.from('top_10_cache')],
140
- VALIDATOR_LEADERBOARD_PROGRAM_ID
141
- );
142
-
143
- export const deriveStakeControllerAuthorityPDA = (): [PublicKey, number] =>
150
+ [Buffer.from(PDA_SEEDS.VALIDATOR_RECORD), voteAccount.toBuffer()],
151
+ PROGRAM_IDS.VALIDATOR_LEADERBOARD,
152
+ )[0];
153
+
154
+ /**
155
+ * Stake controller vault PDA (reserve pool SOL vault).
156
+ * This is the same as VAULT, but named more explicitly for SDK callers.
157
+ */
158
+ export const deriveStakeControllerVaultPda = () =>
144
159
  PublicKey.findProgramAddressSync(
145
- [Buffer.from('stake_authority')],
146
- STAKE_CONTROLLER_PROGRAM_ID
147
- );
148
-
149
- // ---------- SPL helper ----------
150
- /** User’s liqSOL ATA (Token-2022) */
151
- export const getUserLiqsolATA = (user: PublicKey): PublicKey =>
152
- getAssociatedTokenAddressSync(
153
- LIQSOL_MINT_ADDRESS,
154
- user,
155
- /* owner is PDA? */ false,
156
- TOKEN_2022_PROGRAM_ID,
157
- ASSOCIATED_TOKEN_PROGRAM_ID
158
- );
160
+ [Buffer.from(PDA_SEEDS.VAULT)],
161
+ PROGRAM_IDS.LIQSOL_CORE,
162
+ )[0];
163
+
164
+ /**
165
+ * Ephemeral stake account address used per-deposit.
166
+ * On-chain convention: seed = `ephemeral_<u32>` under StakeProgram.programId.
167
+ */
168
+ export const deriveEphemeralStakeAddress = async (
169
+ user: PublicKey,
170
+ seed: any,
171
+ ): Promise<PublicKey> => {
172
+ const seedStr = `ephemeral_${seed}`;
173
+ return await PublicKey.createWithSeed(user, seedStr, StakeProgram.programId);
174
+ };
175
+
176
+
177
+
178
+ /**
179
+ * ---------------------------------------------------------------------------
180
+ * ECONOMICS & MATH CONSTANTS
181
+ * ---------------------------------------------------------------------------
182
+ */
183
+
184
+ // Same scale factor used on-chain for pay-rate math
185
+ export const PAY_RATE_SCALE_FACTOR = BigInt(1_000_000_000_000); // 10^12
186
+
187
+ // Default pay rate fallback used in tests & utils
188
+ export const DEFAULT_AVERAGE_PAY_RATE = BigInt(191_780_821);
189
+
190
+ // How many history entries to average when computing expected fee
191
+ export const DEFAULT_PAY_RATE_LOOKBACK = 5;
192
+
193
+ // Rent exemption for ephemeral stake account (lamports)
194
+ // Mirrors EPHEMERAL_RENT_EXEMPTION = 2_282_880 used in tests
195
+ export const EPHEMERAL_RENT_EXEMPTION = 2_282_880;
196
+
197
+ // For convenience: lamports <-> SOL helpers (no RPC dependency)
198
+ export const LAMPORTS_PER_SOL = 1_000_000_000;
199
+
200
+ export const lamportsToSol = (lamports: number | bigint): number =>
201
+ Number(lamports) / LAMPORTS_PER_SOL;
202
+
203
+ export const solToLamports = (sol: number): number =>
204
+ Math.round(sol * LAMPORTS_PER_SOL);
205
+
206
+ /**
207
+ * ---------------------------------------------------------------------------
208
+ * CLUSTER / ENVIRONMENT CONFIG (optional but handy)
209
+ * ---------------------------------------------------------------------------
210
+ */
211
+
212
+ export type SolanaCluster = 'localnet' | 'devnet' | 'mainnet';
213
+
214
+ // export interface SolanaStakeProgramAddresses {
215
+ // liqsolCore: PublicKey;
216
+ // liqsolToken: PublicKey;
217
+ // validatorLeaderboard: PublicKey;
218
+ // }
219
+
220
+ // export const PROGRAMS_BY_CLUSTER: Record<SolanaCluster, SolanaStakeProgramAddresses> = {
221
+ // localnet: {
222
+ // liqsolCore: PROGRAM_IDS.LIQSOL_CORE,
223
+ // liqsolToken: PROGRAM_IDS.LIQSOL_TOKEN,
224
+ // validatorLeaderboard: PROGRAM_IDS.VALIDATOR_LEADERBOARD,
225
+ // },
226
+ // devnet: {
227
+ // liqsolCore: PROGRAM_IDS.LIQSOL_CORE,
228
+ // liqsolToken: PROGRAM_IDS.LIQSOL_TOKEN,
229
+ // validatorLeaderboard: PROGRAM_IDS.VALIDATOR_LEADERBOARD,
230
+ // },
231
+ // mainnet: {
232
+ // liqsolCore: PROGRAM_IDS.LIQSOL_CORE,
233
+ // liqsolToken: PROGRAM_IDS.LIQSOL_TOKEN,
234
+ // validatorLeaderboard: PROGRAM_IDS.VALIDATOR_LEADERBOARD,
235
+ // },
236
+ // };
237
+
238
+ // export const DEFAULT_CLUSTER: SolanaCluster = 'localnet';
239
+
240
+ // export function getProgramIds(cluster: SolanaCluster = DEFAULT_CLUSTER): SolanaStakeProgramAddresses {
241
+ // return PROGRAMS_BY_CLUSTER[cluster];
242
+ // }
@@ -1,60 +1,47 @@
1
1
  import { AnchorProvider, Program } from '@coral-xyz/anchor';
2
- import depositJson from '../../assets/solana/idl/deposit.json';
3
- import stakeControllerJson from '../../assets/solana/idl/stake_controller.json';
4
- import liqSolTokenJson from '../../assets/solana/idl/liq_sol_token.json';
5
- import distributionJson from '../../assets/solana/idl/distribution.json';
2
+
3
+ import liqsolCoreJson from '../../assets/solana/idl/liqsol_core.json';
4
+ import liqsolTokenJson from '../../assets/solana/idl/liqsol_token.json';
6
5
  import validatorLeaderboardJson from '../../assets/solana/idl/validator_leaderboard.json';
7
6
 
8
- import type { Deposit } from '../../assets/solana/types/deposit';
9
- import type { StakeController } from '../../assets/solana/types/stake_controller';
10
- import type { LiqSolToken } from '../../assets/solana/types/liq_sol_token';
11
- import type { Distribution } from '../../assets/solana/types/distribution';
7
+ import type { LiqsolCore } from '../../assets/solana/types/liqsol_core';
8
+ import type { LiqsolToken } from '../../assets/solana/types/liqsol_token';
12
9
  import type { ValidatorLeaderboard } from '../../assets/solana/types/validator_leaderboard';
13
10
 
14
- import {
15
- DEPOSIT_PROGRAM_ID,
16
- STAKE_CONTROLLER_PROGRAM_ID,
17
- LIQSOL_TOKEN_PROGRAM_ID,
18
- DISTRIBUTION_PROGRAM_ID,
19
- VALIDATOR_LEADERBOARD_PROGRAM_ID
20
- } from '../solana/constants';
11
+ import { PROGRAM_IDS } from './constants';
21
12
 
22
- type Entry<IDL> = { idl: IDL & { address: string }, address: string };
13
+ type Entry<IDL> = {
14
+ idl: IDL & { address: string };
15
+ address: string;
16
+ };
23
17
 
24
18
  const PROGRAMS = {
25
- deposit: {
26
- idl: depositJson,
27
- address: DEPOSIT_PROGRAM_ID.toBase58()
28
- } as Entry<Deposit>,
29
- stakeController: {
30
- idl: stakeControllerJson,
31
- address: STAKE_CONTROLLER_PROGRAM_ID.toBase58()
32
- } as Entry<StakeController>,
33
- liqSolToken: {
34
- idl: liqSolTokenJson,
35
- address: LIQSOL_TOKEN_PROGRAM_ID.toBase58()
36
- } as Entry<LiqSolToken>,
37
- distribution: {
38
- idl: distributionJson,
39
- address: DISTRIBUTION_PROGRAM_ID.toBase58()
40
- } as Entry<Distribution>,
19
+ liqsolCore: {
20
+ idl: liqsolCoreJson,
21
+ address: PROGRAM_IDS.LIQSOL_CORE.toBase58(),
22
+ } as Entry<LiqsolCore>,
23
+ liqsolToken: {
24
+ idl: liqsolTokenJson,
25
+ address: PROGRAM_IDS.LIQSOL_TOKEN.toBase58(),
26
+ } as Entry<LiqsolToken>,
41
27
  validatorLeaderboard: {
42
28
  idl: validatorLeaderboardJson,
43
- address:VALIDATOR_LEADERBOARD_PROGRAM_ID.toBase58()
29
+ address: PROGRAM_IDS.VALIDATOR_LEADERBOARD.toBase58(),
44
30
  } as Entry<ValidatorLeaderboard>,
45
31
  } as const;
46
32
 
33
+ export type SolanaProgramName = keyof typeof PROGRAMS;
34
+
47
35
  export class SolanaProgramService {
48
36
  constructor(private provider: AnchorProvider) { }
49
37
 
50
- getProgram<K extends keyof typeof PROGRAMS>(name: K): Program<(typeof PROGRAMS)[K]['idl']> {
38
+ getProgram<K extends SolanaProgramName>(name: K): Program<(typeof PROGRAMS)[K]['idl']> {
51
39
  const { idl, address } = PROGRAMS[name];
52
- // Ensure the IDL has the right address (avoid drift)
53
40
  const idlWithAddr = { ...idl, address };
54
- return new Program(idlWithAddr as any, this.provider) as Program<(typeof PROGRAMS)[K]['idl']>;
41
+ return new Program(idlWithAddr, this.provider) as Program<(typeof PROGRAMS)[K]['idl']>;
55
42
  }
56
43
 
57
- listProgramNames(): Array<keyof typeof PROGRAMS> {
58
- return Object.keys(PROGRAMS) as Array<keyof typeof PROGRAMS>;
44
+ listProgramNames(): SolanaProgramName[] {
45
+ return Object.keys(PROGRAMS) as SolanaProgramName[];
59
46
  }
60
47
  }