@wireio/stake 0.0.5 → 0.1.0
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 +203 -13
- package/lib/stake.browser.js +2803 -3331
- package/lib/stake.browser.js.map +1 -1
- package/lib/stake.d.ts +377 -6260
- package/lib/stake.js +2940 -3478
- package/lib/stake.js.map +1 -1
- package/lib/stake.m.js +2803 -3331
- package/lib/stake.m.js.map +1 -1
- package/package.json +2 -2
- package/src/assets/solana/idl/deposit.json +46 -10
- package/src/assets/solana/idl/distribution.json +40 -8
- package/src/assets/solana/idl/liq_sol_token.json +25 -2
- package/src/assets/solana/idl/mint_helper.json +110 -0
- package/src/assets/solana/idl/read_tracked_balance.json +140 -0
- package/src/assets/solana/idl/stake_controller.json +1141 -780
- package/src/assets/solana/idl/treasury.json +1 -227
- package/src/assets/solana/idl/validator_leaderboard.json +88 -47
- package/src/assets/solana/idl/validator_registry.json +115 -46
- package/src/assets/solana/idl/yield_oracle.json +1 -1
- package/src/assets/solana/types/deposit.ts +46 -10
- package/src/assets/solana/types/distribution.ts +40 -8
- package/src/assets/solana/types/liq_sol_token.ts +25 -2
- package/src/assets/solana/types/mint_helper.ts +116 -0
- package/src/assets/solana/types/read_tracked_balance.ts +146 -0
- package/src/assets/solana/types/stake_controller.ts +1141 -780
- package/src/assets/solana/types/treasury.ts +1 -227
- package/src/assets/solana/types/validator_leaderboard.ts +88 -47
- package/src/assets/solana/types/validator_registry.ts +115 -46
- package/src/assets/solana/types/yield_oracle.ts +1 -1
- package/src/index.ts +3 -4
- package/src/networks/ethereum/ethereum.ts +2 -2
- package/src/networks/solana/clients/deposit.client.ts +71 -80
- package/src/networks/solana/clients/distribution.client.ts +392 -141
- package/src/networks/solana/clients/leaderboard.client.ts +82 -107
- package/src/networks/solana/constants.ts +141 -56
- package/src/networks/solana/program.ts +36 -89
- package/src/networks/solana/solana.ts +173 -36
- package/src/networks/solana/types.ts +57 -0
- package/src/scripts/fetch-artifacts.sh +24 -0
- package/src/staker/staker.ts +32 -28
- package/src/staker/types.ts +25 -21
- package/src/assets/solana/idl/stake_registry.json +0 -435
- package/src/networks/solana/utils.ts +0 -122
- /package/src/{utils.ts → common/utils.ts} +0 -0
|
@@ -1,76 +1,66 @@
|
|
|
1
|
-
// src/solana/clients/ValidatorLeaderboardClient.ts
|
|
2
1
|
import { AnchorProvider, Program, BN } from '@coral-xyz/anchor';
|
|
3
|
-
import { PublicKey, Transaction, TransactionInstruction
|
|
2
|
+
import { PublicKey, SystemProgram, Transaction, TransactionInstruction } from '@solana/web3.js';
|
|
3
|
+
import { SolanaProgramService } from '../program';
|
|
4
|
+
import type { ValidatorLeaderboard } from '../../../assets/solana/types/validator_leaderboard';
|
|
4
5
|
import {
|
|
5
6
|
deriveLeaderboardHeadPDA,
|
|
6
7
|
deriveValidatorRecordPDA,
|
|
7
8
|
deriveTop10CachePDA,
|
|
8
|
-
} from '../
|
|
9
|
-
import { VALIDATOR_LEADERBOARD_PROGRAM_ID, ValidatorLeaderboard, ValidatorLeaderboardIDL } from '../constants';
|
|
9
|
+
} from '../constants';
|
|
10
10
|
|
|
11
11
|
export class ValidatorLeaderboardClient {
|
|
12
|
-
|
|
12
|
+
private programs: SolanaProgramService;
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
*/
|
|
17
|
-
private get program(): Program<ValidatorLeaderboard> {
|
|
18
|
-
const idlWithAddress = {
|
|
19
|
-
...JSON.parse(JSON.stringify(ValidatorLeaderboardIDL)),
|
|
20
|
-
address: VALIDATOR_LEADERBOARD_PROGRAM_ID.toString(),
|
|
21
|
-
};
|
|
22
|
-
return new Program(idlWithAddress as any, this.provider) as Program<ValidatorLeaderboard>;
|
|
14
|
+
constructor(private provider: AnchorProvider) {
|
|
15
|
+
this.programs = new SolanaProgramService(provider);
|
|
23
16
|
}
|
|
24
17
|
|
|
25
|
-
/**
|
|
26
|
-
|
|
27
|
-
return
|
|
18
|
+
/** Anchor Program<ValidatorLeaderboard> via ProgramService */
|
|
19
|
+
private get program(): Program<ValidatorLeaderboard> {
|
|
20
|
+
return this.programs.getProgram('validatorLeaderboard') as Program<ValidatorLeaderboard>;
|
|
28
21
|
}
|
|
29
22
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
23
|
+
// ───────────────────────────────────────────────────────────────────────────────
|
|
24
|
+
// BUILDERS (return Ixs so you can batch)
|
|
25
|
+
// ───────────────────────────────────────────────────────────────────────────────
|
|
34
26
|
|
|
35
|
-
/**
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const [headPda] = deriveLeaderboardHeadPDA();
|
|
40
|
-
const ix = await this.program.methods
|
|
27
|
+
/** Initialize the leaderboard head account. */
|
|
28
|
+
async buildInitializeIx(authority: PublicKey): Promise<TransactionInstruction> {
|
|
29
|
+
const [leaderboardHead] = deriveLeaderboardHeadPDA();
|
|
30
|
+
return this.program.methods
|
|
41
31
|
.initialize()
|
|
42
32
|
.accounts({
|
|
43
33
|
authority,
|
|
44
|
-
|
|
34
|
+
// @ts-ignore
|
|
35
|
+
leaderboardHead,
|
|
45
36
|
systemProgram: SystemProgram.programId,
|
|
46
|
-
}
|
|
37
|
+
})
|
|
47
38
|
.instruction();
|
|
48
|
-
|
|
49
|
-
return new Transaction().add(ix);
|
|
50
39
|
}
|
|
51
40
|
|
|
52
41
|
/**
|
|
53
|
-
*
|
|
42
|
+
* Upsert/update a validator record and (optionally) reposition it in the linked list.
|
|
43
|
+
* Any of insertAfter/insertBefore/currentPrev/currentNext can be omitted.
|
|
54
44
|
*/
|
|
55
|
-
async
|
|
56
|
-
authority: PublicKey;
|
|
45
|
+
async buildUpdateValidatorIx(params: {
|
|
57
46
|
registrant: PublicKey;
|
|
58
47
|
voteAccount: PublicKey;
|
|
59
|
-
vpp: number;
|
|
48
|
+
vpp: number; // Validator Performance Points
|
|
60
49
|
insertAfter?: PublicKey;
|
|
61
50
|
insertBefore?: PublicKey;
|
|
62
51
|
currentPrev?: PublicKey;
|
|
63
52
|
currentNext?: PublicKey;
|
|
64
|
-
}): Promise<
|
|
65
|
-
const {
|
|
66
|
-
|
|
67
|
-
const [
|
|
53
|
+
}): Promise<TransactionInstruction> {
|
|
54
|
+
const { registrant, voteAccount, vpp, insertAfter, insertBefore, currentPrev, currentNext } = params;
|
|
55
|
+
|
|
56
|
+
const [leaderboardHead] = deriveLeaderboardHeadPDA();
|
|
57
|
+
const [validatorRecord] = deriveValidatorRecordPDA(voteAccount);
|
|
68
58
|
|
|
69
59
|
const accounts: any = {
|
|
70
60
|
registrant,
|
|
71
61
|
voteAccount,
|
|
72
|
-
validatorRecord
|
|
73
|
-
leaderboardHead
|
|
62
|
+
validatorRecord,
|
|
63
|
+
leaderboardHead,
|
|
74
64
|
systemProgram: SystemProgram.programId,
|
|
75
65
|
...(insertAfter && { insertAfter }),
|
|
76
66
|
...(insertBefore && { insertBefore }),
|
|
@@ -78,70 +68,82 @@ export class ValidatorLeaderboardClient {
|
|
|
78
68
|
...(currentNext && { currentNext }),
|
|
79
69
|
};
|
|
80
70
|
|
|
81
|
-
|
|
71
|
+
return this.program.methods
|
|
82
72
|
.updateValidator(new BN(vpp))
|
|
83
73
|
.accounts(accounts)
|
|
84
74
|
.instruction();
|
|
85
|
-
|
|
86
|
-
return new Transaction().add(ix);
|
|
87
75
|
}
|
|
88
76
|
|
|
89
|
-
/**
|
|
90
|
-
|
|
91
|
-
*/
|
|
92
|
-
async buildUpdateTop10CacheTransaction(params: {
|
|
77
|
+
/** Update the Top-10 cache. Requires exactly 10 validator vote accounts. */
|
|
78
|
+
async buildUpdateTop10CacheIx(params: {
|
|
93
79
|
authority: PublicKey;
|
|
94
80
|
top10Validators: PublicKey[];
|
|
95
|
-
}): Promise<
|
|
81
|
+
}): Promise<TransactionInstruction> {
|
|
96
82
|
const { authority, top10Validators } = params;
|
|
97
|
-
if (top10Validators.length !== 10)
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const ix = await this.program.methods
|
|
83
|
+
if (top10Validators.length !== 10) throw new Error('Must provide exactly 10 validators');
|
|
84
|
+
|
|
85
|
+
const [cache] = deriveTop10CachePDA();
|
|
86
|
+
return this.program.methods
|
|
102
87
|
.updateTop10Cache(top10Validators)
|
|
103
|
-
.accounts({
|
|
88
|
+
.accounts({
|
|
89
|
+
// @ts-ignore
|
|
90
|
+
authority,
|
|
91
|
+
cache,
|
|
92
|
+
systemProgram: SystemProgram.programId,
|
|
93
|
+
})
|
|
104
94
|
.instruction();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Convenience wrappers if you want a ready-to-send Transaction
|
|
105
98
|
|
|
106
|
-
|
|
99
|
+
async buildInitializeTx(authority: PublicKey): Promise<Transaction> {
|
|
100
|
+
return new Transaction().add(await this.buildInitializeIx(authority));
|
|
107
101
|
}
|
|
108
102
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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));
|
|
118
113
|
}
|
|
119
114
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
115
|
+
async buildUpdateTop10CacheTx(params: {
|
|
116
|
+
authority: PublicKey;
|
|
117
|
+
top10Validators: PublicKey[];
|
|
118
|
+
}): Promise<Transaction> {
|
|
119
|
+
return new Transaction().add(await this.buildUpdateTop10CacheIx(params));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// ───────────────────────────────────────────────────────────────────────────────
|
|
123
|
+
// READ HELPERS
|
|
124
|
+
// ───────────────────────────────────────────────────────────────────────────────
|
|
125
|
+
|
|
126
|
+
/** Traverse the linked-list leaderboard, returning vote accounts in order. */
|
|
123
127
|
async getLeaderboard(): Promise<PublicKey[]> {
|
|
124
|
-
const [
|
|
125
|
-
let
|
|
128
|
+
const [head] = deriveLeaderboardHeadPDA();
|
|
129
|
+
let headAcc;
|
|
126
130
|
try {
|
|
127
|
-
|
|
131
|
+
headAcc = await this.program.account.leaderboardHead.fetch(head);
|
|
128
132
|
} catch {
|
|
129
133
|
return [];
|
|
130
134
|
}
|
|
131
|
-
const
|
|
132
|
-
let cursor: PublicKey =
|
|
135
|
+
const out: PublicKey[] = [];
|
|
136
|
+
let cursor: PublicKey = headAcc.nextValidator;
|
|
133
137
|
while (cursor && !cursor.equals(PublicKey.default)) {
|
|
134
|
-
|
|
138
|
+
out.push(cursor);
|
|
135
139
|
const rec = await this.program.account.validatorRecord.fetch(cursor);
|
|
136
140
|
cursor = rec.nextValidator;
|
|
137
141
|
}
|
|
138
|
-
return
|
|
142
|
+
return out;
|
|
139
143
|
}
|
|
140
144
|
|
|
141
|
-
/**
|
|
142
|
-
|
|
143
|
-
*/
|
|
144
|
-
async getRecord(voteAccount: PublicKey): Promise<any | null> {
|
|
145
|
+
/** Fetch a single validator record (or null if it doesn't exist). */
|
|
146
|
+
async getValidatorRecord(voteAccount: PublicKey): Promise<any | null> {
|
|
145
147
|
const [recPda] = deriveValidatorRecordPDA(voteAccount);
|
|
146
148
|
try {
|
|
147
149
|
return await this.program.account.validatorRecord.fetch(recPda);
|
|
@@ -149,31 +151,4 @@ export class ValidatorLeaderboardClient {
|
|
|
149
151
|
return null;
|
|
150
152
|
}
|
|
151
153
|
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Send & confirm a single-IX Transaction; returns the signature
|
|
155
|
-
*/
|
|
156
|
-
async sendTransaction(
|
|
157
|
-
tx: Transaction,
|
|
158
|
-
signers: import('@solana/web3.js').Signer[] = []
|
|
159
|
-
): Promise<string> {
|
|
160
|
-
tx.feePayer = this.provider.wallet.publicKey;
|
|
161
|
-
const { blockhash } = await this.provider.connection.getLatestBlockhash();
|
|
162
|
-
tx.recentBlockhash = blockhash;
|
|
163
|
-
return this.provider.sendAndConfirm(tx, signers);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Simulate a single-IX Transaction; returns any err + compute units consumed
|
|
168
|
-
*/
|
|
169
|
-
async simulateTransaction(
|
|
170
|
-
tx: Transaction
|
|
171
|
-
): Promise<{ err: any; unitsConsumed: number }> {
|
|
172
|
-
tx.feePayer = this.provider.wallet.publicKey;
|
|
173
|
-
const { blockhash } = await this.provider.connection.getLatestBlockhash();
|
|
174
|
-
tx.recentBlockhash = blockhash;
|
|
175
|
-
const versioned = new VersionedTransaction(tx.compileMessage());
|
|
176
|
-
const sim = await this.provider.connection.simulateTransaction(versioned, { sigVerify: false });
|
|
177
|
-
return { err: sim.value.err, unitsConsumed: sim.value.unitsConsumed! };
|
|
178
|
-
}
|
|
179
|
-
}
|
|
154
|
+
}
|
|
@@ -1,73 +1,158 @@
|
|
|
1
1
|
// src/networks/solana/constants.ts
|
|
2
|
-
|
|
3
2
|
import { PublicKey } from '@solana/web3.js';
|
|
4
|
-
import {
|
|
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';
|
|
5
9
|
|
|
6
|
-
//
|
|
10
|
+
// IDLs (as generated artifacts)
|
|
7
11
|
import DepositIDL from '../../assets/solana/idl/deposit.json';
|
|
8
|
-
import DistributionIDL from '../../assets/solana/idl/distribution.json';
|
|
9
|
-
import LiqSolTokenIDL from '../../assets/solana/idl/liq_sol_token.json';
|
|
10
12
|
import StakeControllerIDL from '../../assets/solana/idl/stake_controller.json';
|
|
11
|
-
import StakeRegistryIDL from '../../assets/solana/idl/stake_registry.json';
|
|
12
|
-
import TreasuryIDL from '../../assets/solana/idl/treasury.json';
|
|
13
13
|
import ValidatorLeaderboardIDL from '../../assets/solana/idl/validator_leaderboard.json';
|
|
14
|
-
import
|
|
14
|
+
import LiqSolTokenIDL from '../../assets/solana/idl/liq_sol_token.json';
|
|
15
|
+
import DistributionIDL from '../../assets/solana/idl/distribution.json';
|
|
15
16
|
import YieldOracleIDL from '../../assets/solana/idl/yield_oracle.json';
|
|
16
17
|
|
|
17
|
-
//
|
|
18
|
+
// Types (optional; keep the ones you use)
|
|
18
19
|
import type { Deposit } from '../../assets/solana/types/deposit';
|
|
19
|
-
import type { Distribution } from '../../assets/solana/types/distribution';
|
|
20
|
-
import type { ValidatorLeaderboard } from '../../assets/solana/types/validator_leaderboard';
|
|
21
|
-
import type { LiqSolToken } from '../../assets/solana/types/liq_sol_token';
|
|
22
|
-
import type { StakeController } from '../../assets/solana/types/stake_controller';
|
|
23
|
-
import type { StakeRegistry } from '../../assets/solana/types/stake_registry';
|
|
24
|
-
import type { Treasury } from '../../assets/solana/types/treasury';
|
|
25
|
-
import type { ValidatorRegistry } from '../../assets/solana/types/validator_registry';
|
|
26
|
-
import type { YieldOracle } from '../../assets/solana/types/yield_oracle';
|
|
27
|
-
|
|
28
|
-
// Re-export for easy import elsewhere:
|
|
29
|
-
export {
|
|
30
|
-
Deposit,
|
|
31
|
-
DepositIDL,
|
|
32
|
-
Distribution,
|
|
33
|
-
DistributionIDL,
|
|
34
|
-
LiqSolToken,
|
|
35
|
-
LiqSolTokenIDL,
|
|
36
|
-
StakeController,
|
|
37
|
-
StakeControllerIDL,
|
|
38
|
-
StakeRegistry,
|
|
39
|
-
StakeRegistryIDL,
|
|
40
|
-
Treasury,
|
|
41
|
-
TreasuryIDL,
|
|
42
|
-
ValidatorLeaderboard,
|
|
43
|
-
ValidatorLeaderboardIDL,
|
|
44
|
-
ValidatorRegistry,
|
|
45
|
-
ValidatorRegistryIDL,
|
|
46
|
-
YieldOracle,
|
|
47
|
-
YieldOracleIDL,
|
|
48
|
-
};
|
|
49
20
|
|
|
50
|
-
//
|
|
21
|
+
// ---------- Program IDs (from IDL.address) ----------
|
|
51
22
|
export const DEPOSIT_PROGRAM_ID = new PublicKey(DepositIDL.address);
|
|
52
|
-
export const DISTRIBUTION_PROGRAM_ID = new PublicKey(DistributionIDL.address);
|
|
53
|
-
export const LIQSOL_TOKEN_PROGRAM_ID = new PublicKey(LiqSolTokenIDL.address);
|
|
54
23
|
export const STAKE_CONTROLLER_PROGRAM_ID = new PublicKey(StakeControllerIDL.address);
|
|
55
|
-
export const STAKE_REGISTRY_PROGRAM_ID = new PublicKey(StakeRegistryIDL.address);
|
|
56
|
-
export const TREASURY_PROGRAM_ID = new PublicKey(TreasuryIDL.address);
|
|
57
24
|
export const VALIDATOR_LEADERBOARD_PROGRAM_ID = new PublicKey(ValidatorLeaderboardIDL.address);
|
|
58
|
-
export const
|
|
25
|
+
export const LIQSOL_TOKEN_PROGRAM_ID = new PublicKey(LiqSolTokenIDL.address);
|
|
26
|
+
export const DISTRIBUTION_PROGRAM_ID = new PublicKey(DistributionIDL.address);
|
|
59
27
|
export const YIELD_ORACLE_PROGRAM_ID = new PublicKey(YieldOracleIDL.address);
|
|
60
28
|
|
|
61
|
-
//
|
|
62
|
-
export const MIN_SOL_TO_PARTICIPATE = 1_000_000_000;
|
|
63
|
-
|
|
64
|
-
|
|
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] =>
|
|
55
|
+
PublicKey.findProgramAddressSync(
|
|
56
|
+
[Buffer.from('program_authority')],
|
|
57
|
+
DEPOSIT_PROGRAM_ID
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
// LiqSOL Token program
|
|
61
|
+
export const deriveLiqsolMintPDA = (): [PublicKey, number] =>
|
|
62
|
+
PublicKey.findProgramAddressSync(
|
|
63
|
+
[Buffer.from('liq_sol_mint')],
|
|
64
|
+
LIQSOL_TOKEN_PROGRAM_ID
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
/** ✅ FIXED: this must be derived with the LiqSOL token **program id**, not the mint address */
|
|
68
|
+
export const deriveLiqsolMintAuthorityPDA = (): [PublicKey, number] =>
|
|
69
|
+
PublicKey.findProgramAddressSync(
|
|
70
|
+
[Buffer.from('mint_authority')],
|
|
71
|
+
LIQSOL_TOKEN_PROGRAM_ID
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
// Stake Controller
|
|
75
|
+
export const deriveStakeControllerVaultPDA = (): [PublicKey, number] =>
|
|
76
|
+
PublicKey.findProgramAddressSync(
|
|
77
|
+
[Buffer.from('vault')],
|
|
78
|
+
STAKE_CONTROLLER_PROGRAM_ID
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
export const deriveStakeControllerReservePoolPDA = (): [PublicKey, number] =>
|
|
82
|
+
PublicKey.findProgramAddressSync(
|
|
83
|
+
[Buffer.from('reserve_pool')],
|
|
84
|
+
STAKE_CONTROLLER_PROGRAM_ID
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
export const deriveStakeControllerStatePDA = (): [PublicKey, number] =>
|
|
88
|
+
PublicKey.findProgramAddressSync(
|
|
89
|
+
[Buffer.from('stake_controller')],
|
|
90
|
+
STAKE_CONTROLLER_PROGRAM_ID
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
export const deriveGlobalStakeInfoPDA = (): [PublicKey, number] =>
|
|
94
|
+
PublicKey.findProgramAddressSync(
|
|
95
|
+
[Buffer.from('global_stake_info')],
|
|
96
|
+
STAKE_CONTROLLER_PROGRAM_ID
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
export const deriveBucketAuthorityPDA = (): [PublicKey, number] =>
|
|
100
|
+
PublicKey.findProgramAddressSync(
|
|
101
|
+
[Buffer.from('liqsol_bucket')],
|
|
102
|
+
STAKE_CONTROLLER_PROGRAM_ID
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
export const derivePayRateHistoryPDA = (): [PublicKey, number] =>
|
|
106
|
+
PublicKey.findProgramAddressSync(
|
|
107
|
+
[Buffer.from('pay_rate_history')],
|
|
108
|
+
STAKE_CONTROLLER_PROGRAM_ID
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
// Distribution
|
|
112
|
+
export const deriveDistributionStatePDA = (): [PublicKey, number] =>
|
|
113
|
+
PublicKey.findProgramAddressSync(
|
|
114
|
+
[Buffer.from('distribution_state')],
|
|
115
|
+
DISTRIBUTION_PROGRAM_ID
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
export const deriveUserRecordPDA = (user: PublicKey): [PublicKey, number] =>
|
|
119
|
+
PublicKey.findProgramAddressSync(
|
|
120
|
+
[Buffer.from('user_record'), user.toBuffer()],
|
|
121
|
+
DISTRIBUTION_PROGRAM_ID
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
// Validator Leaderboard
|
|
125
|
+
export const deriveLeaderboardHeadPDA = (): [PublicKey, number] =>
|
|
126
|
+
PublicKey.findProgramAddressSync(
|
|
127
|
+
[Buffer.from('leaderboard_head')],
|
|
128
|
+
VALIDATOR_LEADERBOARD_PROGRAM_ID
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
export const deriveValidatorRecordPDA = (voteAccount: PublicKey): [PublicKey, number] =>
|
|
132
|
+
PublicKey.findProgramAddressSync(
|
|
133
|
+
[Buffer.from('validator_record'), voteAccount.toBuffer()],
|
|
134
|
+
VALIDATOR_LEADERBOARD_PROGRAM_ID
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
export const deriveTop10CachePDA = (): [PublicKey, number] =>
|
|
138
|
+
PublicKey.findProgramAddressSync(
|
|
139
|
+
[Buffer.from('top_10_cache')],
|
|
140
|
+
VALIDATOR_LEADERBOARD_PROGRAM_ID
|
|
141
|
+
);
|
|
65
142
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
143
|
+
export const deriveStakeControllerAuthorityPDA = (): [PublicKey, number] =>
|
|
144
|
+
PublicKey.findProgramAddressSync(
|
|
145
|
+
[Buffer.from('stake_authority')],
|
|
146
|
+
STAKE_CONTROLLER_PROGRAM_ID
|
|
147
|
+
);
|
|
71
148
|
|
|
72
|
-
//
|
|
73
|
-
|
|
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
|
+
);
|
|
@@ -1,113 +1,60 @@
|
|
|
1
|
-
// src/solana/programService.ts
|
|
2
|
-
|
|
3
1
|
import { AnchorProvider, Program } from '@coral-xyz/anchor';
|
|
4
|
-
import { PublicKey } from '@solana/web3.js';
|
|
5
|
-
|
|
6
|
-
// 1) pull in all your on-chain IDLs (must match lowercase `src/assets/solana/idl`)
|
|
7
2
|
import depositJson from '../../assets/solana/idl/deposit.json';
|
|
8
|
-
import distributionJson from '../../assets/solana/idl/distribution.json';
|
|
9
|
-
import liqSolTokenJson from '../../assets/solana/idl/liq_sol_token.json';
|
|
10
3
|
import stakeControllerJson from '../../assets/solana/idl/stake_controller.json';
|
|
11
|
-
import
|
|
12
|
-
import
|
|
4
|
+
import liqSolTokenJson from '../../assets/solana/idl/liq_sol_token.json';
|
|
5
|
+
import distributionJson from '../../assets/solana/idl/distribution.json';
|
|
13
6
|
import validatorLeaderboardJson from '../../assets/solana/idl/validator_leaderboard.json';
|
|
14
|
-
import validatorRegistryJson from '../../assets/solana/idl/validator_registry.json';
|
|
15
|
-
import yieldOracleJson from '../../assets/solana/idl/yield_oracle.json';
|
|
16
7
|
|
|
17
|
-
// 2) import their companion TS types
|
|
18
8
|
import type { Deposit } from '../../assets/solana/types/deposit';
|
|
19
|
-
import type { Distribution } from '../../assets/solana/types/distribution';
|
|
20
|
-
import type { LiqSolToken } from '../../assets/solana/types/liq_sol_token';
|
|
21
9
|
import type { StakeController } from '../../assets/solana/types/stake_controller';
|
|
22
|
-
import type {
|
|
23
|
-
import type {
|
|
10
|
+
import type { LiqSolToken } from '../../assets/solana/types/liq_sol_token';
|
|
11
|
+
import type { Distribution } from '../../assets/solana/types/distribution';
|
|
24
12
|
import type { ValidatorLeaderboard } from '../../assets/solana/types/validator_leaderboard';
|
|
25
|
-
import type { ValidatorRegistry } from '../../assets/solana/types/validator_registry';
|
|
26
|
-
import type { YieldOracle } from '../../assets/solana/types/yield_oracle';
|
|
27
13
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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';
|
|
32
21
|
|
|
33
|
-
|
|
22
|
+
type Entry<IDL> = { idl: IDL & { address: string }, address: string };
|
|
23
|
+
|
|
24
|
+
const PROGRAMS = {
|
|
34
25
|
deposit: {
|
|
35
26
|
idl: depositJson,
|
|
36
|
-
address:
|
|
37
|
-
} as
|
|
38
|
-
|
|
39
|
-
distribution: {
|
|
40
|
-
idl: distributionJson,
|
|
41
|
-
address: new PublicKey(distributionJson.address),
|
|
42
|
-
} as IdlEntry<Distribution>,
|
|
43
|
-
|
|
44
|
-
liqSolToken: {
|
|
45
|
-
idl: liqSolTokenJson,
|
|
46
|
-
address: new PublicKey(liqSolTokenJson.address),
|
|
47
|
-
} as IdlEntry<LiqSolToken>,
|
|
48
|
-
|
|
27
|
+
address: DEPOSIT_PROGRAM_ID.toBase58()
|
|
28
|
+
} as Entry<Deposit>,
|
|
49
29
|
stakeController: {
|
|
50
30
|
idl: stakeControllerJson,
|
|
51
|
-
address:
|
|
52
|
-
} as
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
address: new PublicKey(treasuryJson.address),
|
|
62
|
-
} as IdlEntry<Treasury>,
|
|
63
|
-
|
|
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>,
|
|
64
41
|
validatorLeaderboard: {
|
|
65
42
|
idl: validatorLeaderboardJson,
|
|
66
|
-
address:
|
|
67
|
-
} as
|
|
68
|
-
|
|
69
|
-
validatorRegistry: {
|
|
70
|
-
idl: validatorRegistryJson,
|
|
71
|
-
address: new PublicKey(validatorRegistryJson.address),
|
|
72
|
-
} as IdlEntry<ValidatorRegistry>,
|
|
43
|
+
address:VALIDATOR_LEADERBOARD_PROGRAM_ID.toBase58()
|
|
44
|
+
} as Entry<ValidatorLeaderboard>,
|
|
45
|
+
} as const;
|
|
73
46
|
|
|
74
|
-
yieldOracle: {
|
|
75
|
-
idl: yieldOracleJson,
|
|
76
|
-
address: new PublicKey(yieldOracleJson.address),
|
|
77
|
-
} as IdlEntry<YieldOracle>,
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Factory for Anchor Program clients.
|
|
82
|
-
*
|
|
83
|
-
* Anchor v0.28+ reads the program ID from `idl.address`, so
|
|
84
|
-
* we call the 2-arg constructor: `new Program(idl, provider)`.
|
|
85
|
-
*/
|
|
86
47
|
export class SolanaProgramService {
|
|
87
48
|
constructor(private provider: AnchorProvider) { }
|
|
88
49
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
): Program<(typeof PROGRAM_IDLS)[K]['idl']> {
|
|
95
|
-
const entry = PROGRAM_IDLS[name];
|
|
96
|
-
// stamp the correct address into a fresh copy of the IDL
|
|
97
|
-
const idlWithAddr = { ...entry.idl, address: entry.address.toString() };
|
|
98
|
-
// use the two-arg signature: (idl, provider)
|
|
99
|
-
return new Program(idlWithAddr as any, this.provider) as Program<
|
|
100
|
-
(typeof PROGRAM_IDLS)[K]['idl']
|
|
101
|
-
>;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/** List all program keys */
|
|
105
|
-
listProgramNames(): Array<keyof typeof PROGRAM_IDLS> {
|
|
106
|
-
return Object.keys(PROGRAM_IDLS) as Array<keyof typeof PROGRAM_IDLS>;
|
|
50
|
+
getProgram<K extends keyof typeof PROGRAMS>(name: K): Program<(typeof PROGRAMS)[K]['idl']> {
|
|
51
|
+
const { idl, address } = PROGRAMS[name];
|
|
52
|
+
// Ensure the IDL has the right address (avoid drift)
|
|
53
|
+
const idlWithAddr = { ...idl, address };
|
|
54
|
+
return new Program(idlWithAddr as any, this.provider) as Program<(typeof PROGRAMS)[K]['idl']>;
|
|
107
55
|
}
|
|
108
56
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
return PROGRAM_IDLS[name].address;
|
|
57
|
+
listProgramNames(): Array<keyof typeof PROGRAMS> {
|
|
58
|
+
return Object.keys(PROGRAMS) as Array<keyof typeof PROGRAMS>;
|
|
112
59
|
}
|
|
113
60
|
}
|