@wireio/stake 0.1.0 → 0.1.1
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.
- package/README.md +57 -0
- package/lib/stake.browser.js +4623 -3451
- package/lib/stake.browser.js.map +1 -1
- package/lib/stake.d.ts +372 -537
- package/lib/stake.js +4801 -3574
- package/lib/stake.js.map +1 -1
- package/lib/stake.m.js +4623 -3451
- package/lib/stake.m.js.map +1 -1
- package/package.json +1 -1
- package/src/assets/solana/idl/liqsol_core.json +4239 -0
- package/src/assets/solana/idl/liqsol_token.json +183 -0
- package/src/assets/solana/idl/validator_leaderboard.json +270 -265
- package/src/assets/solana/types/liqsol_core.ts +4245 -0
- package/src/assets/solana/types/liqsol_token.ts +189 -0
- package/src/assets/solana/types/validator_leaderboard.ts +270 -265
- package/src/index.ts +1 -3
- package/src/networks/ethereum/contract.ts +138 -36
- package/src/networks/ethereum/ethereum.ts +167 -38
- package/src/networks/ethereum/types.ts +32 -1
- package/src/networks/solana/clients/deposit.client.ts +71 -109
- package/src/networks/solana/clients/distribution.client.ts +256 -383
- package/src/networks/solana/clients/leaderboard.client.ts +38 -133
- package/src/networks/solana/constants.ts +214 -130
- package/src/networks/solana/program.ts +25 -38
- package/src/networks/solana/solana.ts +100 -89
- package/src/networks/solana/types.ts +37 -47
- package/src/networks/solana/utils.ts +551 -0
- package/src/scripts/tsconfig.json +17 -0
- package/src/staker/staker.ts +5 -4
- package/src/staker/types.ts +2 -2
- package/src/assets/solana/idl/deposit.json +0 -296
- package/src/assets/solana/idl/distribution.json +0 -768
- package/src/assets/solana/idl/liq_sol_token.json +0 -298
- package/src/assets/solana/idl/mint_helper.json +0 -110
- package/src/assets/solana/idl/read_tracked_balance.json +0 -140
- package/src/assets/solana/idl/stake_controller.json +0 -2149
- package/src/assets/solana/idl/treasury.json +0 -110
- package/src/assets/solana/idl/validator_registry.json +0 -487
- package/src/assets/solana/idl/yield_oracle.json +0 -32
- package/src/assets/solana/types/deposit.ts +0 -302
- package/src/assets/solana/types/distribution.ts +0 -774
- package/src/assets/solana/types/liq_sol_token.ts +0 -304
- package/src/assets/solana/types/mint_helper.ts +0 -116
- package/src/assets/solana/types/read_tracked_balance.ts +0 -146
- package/src/assets/solana/types/stake_controller.ts +0 -2155
- package/src/assets/solana/types/stake_registry.ts +0 -441
- package/src/assets/solana/types/treasury.ts +0 -116
- package/src/assets/solana/types/validator_registry.ts +0 -493
- package/src/assets/solana/types/yield_oracle.ts +0 -38
- package/src/common/utils.ts +0 -9
|
@@ -1,154 +1,59 @@
|
|
|
1
|
-
import { AnchorProvider, Program
|
|
2
|
-
import { PublicKey
|
|
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
|
-
|
|
7
|
-
|
|
8
|
-
deriveTop10CachePDA,
|
|
7
|
+
deriveLeaderboardStatePda,
|
|
8
|
+
deriveValidatorRecordPda,
|
|
9
9
|
} from '../constants';
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
35
|
+
const pda = deriveValidatorRecordPda(voteAccount);
|
|
148
36
|
try {
|
|
149
|
-
|
|
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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
export const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
//
|
|
54
|
-
|
|
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(
|
|
57
|
-
|
|
58
|
-
);
|
|
72
|
+
[Buffer.from(PDA_SEEDS.LIQSOL_MINT)],
|
|
73
|
+
PROGRAM_IDS.LIQSOL_TOKEN,
|
|
74
|
+
)[0];
|
|
59
75
|
|
|
60
|
-
|
|
61
|
-
export const deriveLiqsolMintPDA = (): [PublicKey, number] =>
|
|
76
|
+
export const deriveLiqsolMintAuthorityPda = () =>
|
|
62
77
|
PublicKey.findProgramAddressSync(
|
|
63
|
-
[Buffer.from(
|
|
64
|
-
|
|
65
|
-
);
|
|
78
|
+
[Buffer.from(PDA_SEEDS.LIQSOL_MINT_AUTHORITY)],
|
|
79
|
+
PROGRAM_IDS.LIQSOL_TOKEN,
|
|
80
|
+
)[0];
|
|
66
81
|
|
|
67
|
-
|
|
68
|
-
export const deriveLiqsolMintAuthorityPDA = (): [PublicKey, number] =>
|
|
82
|
+
export const deriveDepositAuthorityPda = () =>
|
|
69
83
|
PublicKey.findProgramAddressSync(
|
|
70
|
-
[Buffer.from(
|
|
71
|
-
|
|
72
|
-
);
|
|
84
|
+
[Buffer.from(PDA_SEEDS.DEPOSIT_AUTHORITY)],
|
|
85
|
+
PROGRAM_IDS.LIQSOL_CORE,
|
|
86
|
+
)[0];
|
|
73
87
|
|
|
74
|
-
|
|
75
|
-
export const deriveStakeControllerVaultPDA = (): [PublicKey, number] =>
|
|
88
|
+
export const deriveVaultPda = () =>
|
|
76
89
|
PublicKey.findProgramAddressSync(
|
|
77
|
-
[Buffer.from(
|
|
78
|
-
|
|
79
|
-
);
|
|
90
|
+
[Buffer.from(PDA_SEEDS.VAULT)],
|
|
91
|
+
PROGRAM_IDS.LIQSOL_CORE,
|
|
92
|
+
)[0];
|
|
80
93
|
|
|
81
|
-
export const
|
|
94
|
+
export const deriveReservePoolPda = () =>
|
|
82
95
|
PublicKey.findProgramAddressSync(
|
|
83
|
-
[Buffer.from(
|
|
84
|
-
|
|
85
|
-
);
|
|
96
|
+
[Buffer.from(PDA_SEEDS.RESERVE_POOL)],
|
|
97
|
+
PROGRAM_IDS.LIQSOL_CORE,
|
|
98
|
+
)[0];
|
|
86
99
|
|
|
87
|
-
export const
|
|
100
|
+
export const deriveStakeControllerStatePda = () =>
|
|
88
101
|
PublicKey.findProgramAddressSync(
|
|
89
|
-
[Buffer.from(
|
|
90
|
-
|
|
91
|
-
);
|
|
102
|
+
[Buffer.from(PDA_SEEDS.STAKE_CONTROLLER_STATE)],
|
|
103
|
+
PROGRAM_IDS.LIQSOL_CORE,
|
|
104
|
+
)[0];
|
|
92
105
|
|
|
93
|
-
export const
|
|
106
|
+
export const derivePayoutStatePda = () =>
|
|
94
107
|
PublicKey.findProgramAddressSync(
|
|
95
|
-
[Buffer.from(
|
|
96
|
-
|
|
97
|
-
);
|
|
108
|
+
[Buffer.from(PDA_SEEDS.PAYOUT_STATE)],
|
|
109
|
+
PROGRAM_IDS.LIQSOL_CORE,
|
|
110
|
+
)[0];
|
|
98
111
|
|
|
99
|
-
export const
|
|
112
|
+
export const deriveBucketAuthorityPda = () =>
|
|
100
113
|
PublicKey.findProgramAddressSync(
|
|
101
|
-
[Buffer.from(
|
|
102
|
-
|
|
103
|
-
);
|
|
114
|
+
[Buffer.from(PDA_SEEDS.BUCKET_AUTHORITY)],
|
|
115
|
+
PROGRAM_IDS.LIQSOL_CORE,
|
|
116
|
+
)[0];
|
|
104
117
|
|
|
105
|
-
export const
|
|
118
|
+
export const deriveDistributionStatePda = () =>
|
|
106
119
|
PublicKey.findProgramAddressSync(
|
|
107
|
-
[Buffer.from(
|
|
108
|
-
|
|
109
|
-
);
|
|
120
|
+
[Buffer.from(PDA_SEEDS.DISTRIBUTION_STATE)],
|
|
121
|
+
PROGRAM_IDS.LIQSOL_CORE,
|
|
122
|
+
)[0];
|
|
110
123
|
|
|
111
|
-
|
|
112
|
-
export const deriveDistributionStatePDA = (): [PublicKey, number] =>
|
|
124
|
+
export const deriveUserRecordPda = (user: PublicKey) =>
|
|
113
125
|
PublicKey.findProgramAddressSync(
|
|
114
|
-
[Buffer.from(
|
|
115
|
-
|
|
116
|
-
);
|
|
126
|
+
[Buffer.from(PDA_SEEDS.USER_RECORD), user.toBuffer()],
|
|
127
|
+
PROGRAM_IDS.LIQSOL_CORE,
|
|
128
|
+
)[0];
|
|
117
129
|
|
|
118
|
-
export const
|
|
130
|
+
export const derivePayRateHistoryPda = () =>
|
|
119
131
|
PublicKey.findProgramAddressSync(
|
|
120
|
-
[Buffer.from(
|
|
121
|
-
|
|
122
|
-
);
|
|
132
|
+
[Buffer.from(PDA_SEEDS.PAY_RATE_HISTORY)],
|
|
133
|
+
PROGRAM_IDS.LIQSOL_CORE,
|
|
134
|
+
)[0];
|
|
123
135
|
|
|
124
|
-
//
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
|
142
|
+
export const deriveLeaderboardStatePda = () =>
|
|
132
143
|
PublicKey.findProgramAddressSync(
|
|
133
|
-
[Buffer.from(
|
|
134
|
-
|
|
135
|
-
);
|
|
144
|
+
[Buffer.from(PDA_SEEDS.LEADERBOARD_STATE)],
|
|
145
|
+
PROGRAM_IDS.VALIDATOR_LEADERBOARD,
|
|
146
|
+
)[0];
|
|
136
147
|
|
|
137
|
-
export const
|
|
148
|
+
export const deriveValidatorRecordPda = (voteAccount: PublicKey) =>
|
|
138
149
|
PublicKey.findProgramAddressSync(
|
|
139
|
-
[Buffer.from(
|
|
140
|
-
|
|
141
|
-
);
|
|
142
|
-
|
|
143
|
-
|
|
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(
|
|
146
|
-
|
|
147
|
-
);
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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
|
-
|
|
3
|
-
import
|
|
4
|
-
import
|
|
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 {
|
|
9
|
-
import type {
|
|
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> = {
|
|
13
|
+
type Entry<IDL> = {
|
|
14
|
+
idl: IDL & { address: string };
|
|
15
|
+
address: string;
|
|
16
|
+
};
|
|
23
17
|
|
|
24
18
|
const PROGRAMS = {
|
|
25
|
-
|
|
26
|
-
idl:
|
|
27
|
-
address:
|
|
28
|
-
} as Entry<
|
|
29
|
-
|
|
30
|
-
idl:
|
|
31
|
-
address:
|
|
32
|
-
} as Entry<
|
|
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:
|
|
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
|
|
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
|
|
41
|
+
return new Program(idlWithAddr, this.provider) as Program<(typeof PROGRAMS)[K]['idl']>;
|
|
55
42
|
}
|
|
56
43
|
|
|
57
|
-
listProgramNames():
|
|
58
|
-
return Object.keys(PROGRAMS) as
|
|
44
|
+
listProgramNames(): SolanaProgramName[] {
|
|
45
|
+
return Object.keys(PROGRAMS) as SolanaProgramName[];
|
|
59
46
|
}
|
|
60
47
|
}
|