@wireio/stake 0.1.3 → 0.2.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.
@@ -0,0 +1,474 @@
1
+ import { AnchorProvider, BN, Program } from '@coral-xyz/anchor';
2
+ import {
3
+ Connection,
4
+ PublicKey,
5
+ SystemProgram,
6
+ Transaction,
7
+ TransactionInstruction,
8
+ } from '@solana/web3.js';
9
+ import {
10
+ ASSOCIATED_TOKEN_PROGRAM_ID,
11
+ TOKEN_2022_PROGRAM_ID,
12
+ createAssociatedTokenAccountInstruction,
13
+ } from '@solana/spl-token';
14
+ import {
15
+ buildOutpostAccounts,
16
+ getLiqsolCoreProgram,
17
+ getErrorMessage,
18
+ } from '../utils';
19
+ import { SolanaProgramService } from '../program';
20
+ import { LiqsolCore } from '../../../assets/solana/types/liqsol_core';
21
+ import { WalletLike, OutpostWireStateSnapshot, SharesPreview, UserWarrantRecord, TrancheState, WireReceipt } from '../types';
22
+
23
+ /**
24
+ * Minimal, user-flow focused OutpostClient.
25
+ * - Read state
26
+ * - Build + (optionally) send user instructions
27
+ *
28
+ * No admin/bootstrap/reset helpers by design.
29
+ */
30
+ export class OutpostClient {
31
+ private readonly program: Program<LiqsolCore>;
32
+
33
+ // keep consistent with your tests
34
+ static readonly INDEX_SCALE = new BN('1000000000000');
35
+
36
+ get connection(): Connection { return this.provider.connection; }
37
+ get wallet(): WalletLike { return this.provider.wallet; }
38
+
39
+ constructor(private provider: AnchorProvider) {
40
+ const svc = new SolanaProgramService(provider);
41
+ this.program = svc.getProgram('liqsolCore');
42
+ }
43
+
44
+ /**
45
+ * Read-only Program helper (dummy wallet), useful if you want to do pure reads
46
+ * without requiring a wallet. Kept here as sugar for callers.
47
+ */
48
+ getReadOnlyProgram(): Program<LiqsolCore> {
49
+ return getLiqsolCoreProgram(this.connection);
50
+ }
51
+
52
+ // ---------------------------------------------------------------------------
53
+ // General-purpose formatting + math (SDK sugar)
54
+ // ---------------------------------------------------------------------------
55
+
56
+ /**
57
+ * Same rounding logic from your tests: ceil(amount * INDEX_SCALE / currentIndex)
58
+ */
59
+ static tokensToShares(amount: BN, currentIndex: BN): BN {
60
+ const numerator = amount.mul(OutpostClient.INDEX_SCALE);
61
+ const shares = numerator.div(currentIndex);
62
+ const remainder = numerator.mod(currentIndex);
63
+ return remainder.eqn(0) ? shares : shares.addn(1);
64
+ }
65
+
66
+ /**
67
+ * UI helper: formats a BN assumed to be scale=1e8 into a decimal string.
68
+ * (Matches your test helper; useful for tranche price, USD price, etc.)
69
+ */
70
+ static formatScale8(value: BN): string {
71
+ const decimals = 8;
72
+ const valueStr = value.toString();
73
+ if (valueStr.length <= decimals) {
74
+ const padding = '0'.repeat(decimals - valueStr.length);
75
+ return `0.${padding}${valueStr}`;
76
+ }
77
+ const intPart = valueStr.slice(0, valueStr.length - decimals);
78
+ const decPart = valueStr.slice(valueStr.length - decimals);
79
+ return `${intPart}.${decPart}`;
80
+ }
81
+
82
+ /**
83
+ * Previews expected shares for a purchase/stake flow that mints shares
84
+ * relative to globalState.currentIndex.
85
+ */
86
+ async previewExpectedShares(params: {
87
+ amountLamports: BN;
88
+ user?: PublicKey; // optional; defaults to wallet.publicKey
89
+ }): Promise<SharesPreview> {
90
+ const user = params.user ?? this.wallet.publicKey;
91
+ const accounts = await buildOutpostAccounts(this.connection, user);
92
+ const globalState = await this.program.account.globalState.fetch(accounts.globalState);
93
+ const currentIndex = new BN(globalState.currentIndex.toString());
94
+ const expectedShares = OutpostClient.tokensToShares(
95
+ params.amountLamports,
96
+ currentIndex,
97
+ );
98
+
99
+ return {
100
+ amountLamports: params.amountLamports,
101
+ currentIndex,
102
+ indexScale: OutpostClient.INDEX_SCALE,
103
+ expectedShares,
104
+ };
105
+ }
106
+
107
+ // ---------------------------------------------------------------------------
108
+ // Account helpers (user-facing, not admin bootstrap)
109
+ // ---------------------------------------------------------------------------
110
+
111
+ /**
112
+ * Returns whether the user's liqSOL ATA exists.
113
+ * Useful for UX (show "Create token account" prompt).
114
+ */
115
+ async doesUserAtaExist(user: PublicKey = this.wallet.publicKey): Promise<boolean> {
116
+ const accounts = await buildOutpostAccounts(this.connection, user);
117
+ const info = await this.connection.getAccountInfo(accounts.userAta);
118
+ return !!info;
119
+ }
120
+
121
+ /**
122
+ * Builds an instruction to create the user's liqSOL ATA (Token-2022).
123
+ * This is general-purpose sugar for any flow that needs the ATA.
124
+ */
125
+ async buildCreateUserAtaIx(user: PublicKey = this.wallet.publicKey): Promise<TransactionInstruction> {
126
+ const accounts = await buildOutpostAccounts(this.connection, user);
127
+
128
+ return createAssociatedTokenAccountInstruction(
129
+ this.wallet.publicKey, // payer
130
+ accounts.userAta, // ata
131
+ user, // owner
132
+ accounts.liqsolMint, // mint
133
+ TOKEN_2022_PROGRAM_ID,
134
+ ASSOCIATED_TOKEN_PROGRAM_ID,
135
+ );
136
+ }
137
+
138
+ /**
139
+ * Convenience: ensures ATA exists by returning either [] or [createATAIx].
140
+ * (Does NOT send; caller composes tx)
141
+ */
142
+ async maybeBuildCreateUserAtaIx(user: PublicKey = this.wallet.publicKey): Promise<TransactionInstruction[]> {
143
+ const accounts = await buildOutpostAccounts(this.connection, user);
144
+ const info = await this.connection.getAccountInfo(accounts.userAta);
145
+ if (info) return [];
146
+ return [await this.buildCreateUserAtaIx(user)];
147
+ }
148
+
149
+ // ---------------------------------------------------------------------------
150
+ // Reads (UI-first)
151
+ // ---------------------------------------------------------------------------
152
+
153
+ async getWireStateSnapshot(user: PublicKey = this.wallet.publicKey): Promise<OutpostWireStateSnapshot> {
154
+ const accounts = await buildOutpostAccounts(this.connection, user);
155
+
156
+ const [
157
+ globalState,
158
+ wireReceipt,
159
+ distributionState,
160
+ userWarrantRecord,
161
+ trancheState,
162
+ ] = await Promise.all([
163
+ this.program.account.globalState.fetch(accounts.globalState),
164
+ this.program.account.wireReceipt.fetchNullable(accounts.wireReceipt),
165
+ this.program.account.distributionState.fetch(accounts.distributionState),
166
+ this.program.account.userWarrantRecord.fetchNullable(accounts.userWarrantRecord),
167
+ this.program.account.trancheState.fetchNullable(accounts.trancheState),
168
+ ]);
169
+
170
+ const [
171
+ liqsolPoolBalance,
172
+ solBucketLamports,
173
+ userLiqsolBalance,
174
+ ] = await Promise.all([
175
+ this.getTokenBalanceSafe(accounts.liqsolPoolAta),
176
+ this.connection.getBalance(accounts.solBucket),
177
+ this.getTokenBalanceSafe(accounts.userAta),
178
+ ]);
179
+
180
+ return {
181
+ globalState,
182
+ distributionState,
183
+ wireReceipt,
184
+ trancheState,
185
+ userWarrantRecord,
186
+ liqsolPoolBalance,
187
+ solBucketLamports,
188
+ userLiqsolBalance,
189
+ };
190
+ }
191
+
192
+ async getWireReceipt(user: PublicKey = this.wallet.publicKey): Promise<WireReceipt | null> {
193
+ const accounts = await buildOutpostAccounts(this.connection, user);
194
+ return this.program.account.wireReceipt.fetchNullable(accounts.wireReceipt);
195
+ }
196
+
197
+ async getTrancheState(): Promise<TrancheState | null> {
198
+ const accounts = await buildOutpostAccounts(this.connection, this.wallet.publicKey);
199
+ return this.program.account.trancheState.fetchNullable(accounts.trancheState);
200
+ }
201
+
202
+ async getUserWarrantRecord(user: PublicKey = this.wallet.publicKey): Promise<UserWarrantRecord | null> {
203
+ const accounts = await buildOutpostAccounts(this.connection, user);
204
+ return this.program.account.userWarrantRecord.fetchNullable(accounts.userWarrantRecord);
205
+ }
206
+
207
+ // ---------------------------------------------------------------------------
208
+ // Instruction builders (source of truth: your test utils)
209
+ // ---------------------------------------------------------------------------
210
+
211
+ /**
212
+ * stakeLiqsol(amount)
213
+ * (Outpost staking: liqSOL -> warrant pool)
214
+ */
215
+ async buildStakeLiqsolIx(amountLamports: bigint, userPubKey = this.wallet.publicKey): Promise<TransactionInstruction> {
216
+ const a = await buildOutpostAccounts(this.connection, userPubKey);
217
+ const amount = new BN(amountLamports.toString());
218
+
219
+ return this.program.methods
220
+ .stakeLiqsol(amount)
221
+ .accounts({
222
+ user: a.user,
223
+ liqsolMint: a.liqsolMint,
224
+ globalState: a.globalState,
225
+ userAta: a.userAta,
226
+ poolAuthority: a.poolAuthority,
227
+ liqsolPoolAta: a.liqsolPoolAta,
228
+ warrantDepositRecord: a.wireReceipt,
229
+ liqsolPoolUserRecord: a.poolUserRecord,
230
+ distributionState: a.distributionState,
231
+ payRateHistory: a.payRateHistory,
232
+ bucketAuthority: a.bucketAuthority,
233
+ bucketTokenAccount: a.bucketTokenAccount,
234
+ solBucket: a.solBucket,
235
+ tokenProgram: TOKEN_2022_PROGRAM_ID,
236
+ associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
237
+ systemProgram: SystemProgram.programId,
238
+ })
239
+ .instruction();
240
+ }
241
+
242
+ /**
243
+ * withdrawStake(amount)
244
+ * (Outpost unstake: warrant pool -> user liqSOL)
245
+ */
246
+ async buildWithdrawStakeIx(amountLamports: bigint, userPubKey = this.wallet.publicKey): Promise<TransactionInstruction> {
247
+ const a = await buildOutpostAccounts(this.connection, userPubKey);
248
+ const amount = new BN(amountLamports.toString());
249
+
250
+ return this.program.methods
251
+ .withdrawStake(amount)
252
+ .accounts({
253
+ user: a.user,
254
+ liqsolMint: a.liqsolMint,
255
+ globalState: a.globalState,
256
+ userAta: a.userAta,
257
+ poolAuthority: a.poolAuthority,
258
+ liqsolPoolAta: a.liqsolPoolAta,
259
+ warrantDepositRecord: a.wireReceipt,
260
+ liqsolPoolUserRecord: a.poolUserRecord,
261
+ distributionState: a.distributionState,
262
+ payRateHistory: a.payRateHistory,
263
+ bucketAuthority: a.bucketAuthority,
264
+ bucketTokenAccount: a.bucketTokenAccount,
265
+ solBucket: a.solBucket,
266
+ tokenProgram: TOKEN_2022_PROGRAM_ID,
267
+ systemProgram: SystemProgram.programId,
268
+ })
269
+ .instruction();
270
+ }
271
+
272
+ /**
273
+ * purchaseWithLiqsol(amount)
274
+ */
275
+ async buildPurchaseWithLiqsolIx(amountLamports: bigint, userPubKey = this.wallet.publicKey): Promise<TransactionInstruction> {
276
+ const a = await buildOutpostAccounts(this.connection, userPubKey);
277
+ const amount = new BN(amountLamports.toString());
278
+
279
+ return this.program.methods
280
+ .purchaseWithLiqsol(amount)
281
+ .accounts({
282
+ user: a.user,
283
+ liqsolMint: a.liqsolMint,
284
+ globalState: a.globalState,
285
+ buyerAta: a.userAta,
286
+ poolAuthority: a.poolAuthority,
287
+ liqsolPoolAta: a.liqsolPoolAta,
288
+ warrantDepositRecord: a.wireReceipt,
289
+ liqsolPoolUserRecord: a.poolUserRecord,
290
+ distributionState: a.distributionState,
291
+ payRateHistory: a.payRateHistory,
292
+ bucketAuthority: a.bucketAuthority,
293
+ bucketTokenAccount: a.bucketTokenAccount,
294
+ solBucket: a.solBucket,
295
+ trancheState: a.trancheState,
296
+ userWarrantRecord: a.userWarrantRecord,
297
+ chainlinkFeed: a.chainLinkFeed,
298
+ chainlinkProgram: a.chainLinkProgram,
299
+ tokenProgram: TOKEN_2022_PROGRAM_ID,
300
+ associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
301
+ systemProgram: SystemProgram.programId,
302
+ })
303
+ .instruction();
304
+ }
305
+
306
+ /**
307
+ * purchaseWithSol(amount)
308
+ */
309
+ async buildPurchaseWithSolIx(amountLamports: bigint, userPubKey = this.wallet.publicKey): Promise<TransactionInstruction> {
310
+ const a = await buildOutpostAccounts(this.connection, userPubKey);
311
+ const amount = new BN(amountLamports.toString());
312
+
313
+ return this.program.methods
314
+ .purchaseWithSol(amount)
315
+ .accounts({
316
+ user: a.user,
317
+ liqsolMint: a.liqsolMint,
318
+ globalState: a.globalState,
319
+ poolAuthority: a.poolAuthority,
320
+ liqsolPoolAta: a.liqsolPoolAta,
321
+ liqsolPoolUserRecord: a.poolUserRecord,
322
+ distributionState: a.distributionState,
323
+ payRateHistory: a.payRateHistory,
324
+ bucketAuthority: a.bucketAuthority,
325
+ bucketTokenAccount: a.bucketTokenAccount,
326
+ solBucket: a.solBucket,
327
+ warrantDepositRecord: a.wireReceipt,
328
+ trancheState: a.trancheState,
329
+ userWarrantRecord: a.userWarrantRecord,
330
+ chainlinkFeed: a.chainLinkFeed,
331
+ chainlinkProgram: a.chainLinkProgram,
332
+ tokenProgram: TOKEN_2022_PROGRAM_ID,
333
+ systemProgram: SystemProgram.programId,
334
+ })
335
+ .instruction();
336
+ }
337
+
338
+ /**
339
+ * purchaseWarrantsFromYield()
340
+ *
341
+ * Source of truth: your test util executePurchaseFromYield (note: it passed
342
+ * liqsolPoolUserRecord: pdas.userUserRecord, not poolUserRecord).
343
+ */
344
+ async buildPurchaseFromYieldIx(userPubKey = this.wallet.publicKey): Promise<TransactionInstruction> {
345
+ const a = await buildOutpostAccounts(this.connection, userPubKey);
346
+
347
+ return this.program.methods
348
+ .purchaseWarrantsFromYield()
349
+ .accounts({
350
+ user: a.user,
351
+ globalState: a.globalState,
352
+ liqsolMint: a.liqsolMint,
353
+ poolAuthority: a.poolAuthority,
354
+ liqsolPoolAta: a.liqsolPoolAta,
355
+ solBucket: a.solBucket,
356
+ liqsolPoolUserRecord: a.userUserRecord,
357
+ distributionState: a.distributionState,
358
+ payRateHistory: a.payRateHistory,
359
+ bucketAuthority: a.bucketAuthority,
360
+ bucketTokenAccount: a.bucketTokenAccount,
361
+ tokenProgram: TOKEN_2022_PROGRAM_ID,
362
+ systemProgram: SystemProgram.programId,
363
+ trancheState: a.trancheState,
364
+ userWarrantRecord: a.userWarrantRecord,
365
+ chainlinkFeed: a.chainLinkFeed,
366
+ chainlinkProgram: a.chainLinkProgram,
367
+ })
368
+ .instruction();
369
+ }
370
+
371
+ // ---------------------------------------------------------------------------
372
+ // Optional send helpers (wallet-facing sugar)
373
+ // ---------------------------------------------------------------------------
374
+
375
+ /**
376
+ * Builds and sends a single-instruction transaction.
377
+ * (Hub can ignore this and use builder methods only.)
378
+ */
379
+ async sendIx(ix: TransactionInstruction, opts?: {
380
+ additionalIxs?: TransactionInstruction[];
381
+ }): Promise<string> {
382
+ const tx = new Transaction();
383
+ if (opts?.additionalIxs?.length) {
384
+ tx.add(...opts.additionalIxs);
385
+ }
386
+ tx.add(ix);
387
+
388
+ try {
389
+ const sig = await this.provider.sendAndConfirm(tx, [], { commitment: 'confirmed' });
390
+ return sig;
391
+ } catch (e: any) {
392
+ const msg = getErrorMessage(e);
393
+ throw new Error(`OutpostClient sendIx failed: ${msg}`);
394
+ }
395
+ }
396
+
397
+ /**
398
+ * Convenience: stake liqSOL and (optionally) create ATA first.
399
+ */
400
+ async stakeLiqsol(params: {
401
+ amount: BN;
402
+ user?: PublicKey;
403
+ ensureAta?: boolean; // default true
404
+ }): Promise<string> {
405
+ const user = params.user ?? this.wallet.publicKey;
406
+ const pre: TransactionInstruction[] = [];
407
+ if (params.ensureAta ?? true) {
408
+ pre.push(...(await this.maybeBuildCreateUserAtaIx(user)));
409
+ }
410
+ const ix = await this.buildStakeLiqsolIx(params.amount, user);
411
+ return this.sendIx(ix, { additionalIxs: pre });
412
+ }
413
+
414
+ async withdrawStake(params: {
415
+ amount: BN;
416
+ user?: PublicKey;
417
+ ensureAta?: boolean; // default true (usually exists, but harmless)
418
+ }): Promise<string> {
419
+ const user = params.user ?? this.wallet.publicKey;
420
+ const pre: TransactionInstruction[] = [];
421
+ if (params.ensureAta ?? true) {
422
+ pre.push(...(await this.maybeBuildCreateUserAtaIx(user)));
423
+ }
424
+ const ix = await this.buildWithdrawStakeIx(params.amount, user);
425
+ return this.sendIx(ix, { additionalIxs: pre });
426
+ }
427
+
428
+ async purchaseWithLiqsol(params: {
429
+ amount: BN;
430
+ user?: PublicKey;
431
+ ensureAta?: boolean; // default true
432
+ }): Promise<string> {
433
+ const user = params.user ?? this.wallet.publicKey;
434
+ const pre: TransactionInstruction[] = [];
435
+ if (params.ensureAta ?? true) {
436
+ pre.push(...(await this.maybeBuildCreateUserAtaIx(user)));
437
+ }
438
+ const ix = await this.buildPurchaseWithLiqsolIx(params.amount, user);
439
+ return this.sendIx(ix, { additionalIxs: pre });
440
+ }
441
+
442
+ async purchaseWithSol(params: {
443
+ amount: BN;
444
+ user?: PublicKey;
445
+ }): Promise<string> {
446
+ const user = params.user ?? this.wallet.publicKey;
447
+ const ix = await this.buildPurchaseWithSolIx(params.amount, user);
448
+ return this.sendIx(ix);
449
+ }
450
+
451
+ async purchaseFromYield(params?: {
452
+ user?: PublicKey;
453
+ }): Promise<string> {
454
+ const user = params?.user ?? this.wallet.publicKey;
455
+ const ix = await this.buildPurchaseFromYieldIx(user);
456
+ return this.sendIx(ix);
457
+ }
458
+
459
+ // ---------------------------------------------------------------------------
460
+ // Internals
461
+ // ---------------------------------------------------------------------------
462
+
463
+ /**
464
+ * Token balance helper returning BN(0) if ATA missing.
465
+ */
466
+ private async getTokenBalanceSafe(ata: PublicKey): Promise<BN> {
467
+ try {
468
+ const bal = await this.connection.getTokenAccountBalance(ata);
469
+ return new BN(bal.value.amount);
470
+ } catch {
471
+ return new BN(0);
472
+ }
473
+ }
474
+ }
@@ -43,7 +43,7 @@ export const PDA_SEEDS = {
43
43
  VAULT: 'vault',
44
44
  RESERVE_POOL: 'reserve_pool',
45
45
  STAKE_CONTROLLER_STATE: 'stake_controller',
46
- PAYOUT_STATE: 'payout-state',
46
+ PAYOUT_STATE: 'payout_state',
47
47
 
48
48
  // liqsol_token: mint + bucket
49
49
  LIQSOL_MINT: 'liqsol_mint',
@@ -61,12 +61,24 @@ export const PDA_SEEDS = {
61
61
  LEADERBOARD_STATE: 'leaderboard_state',
62
62
  VALIDATOR_RECORD: 'validator',
63
63
  GLOBAL_STAKE_INFO: 'global_stake_info',
64
+
65
+ // Outpost
66
+ WARRANT_DEPOSIT_GLOBAL: 'warrant_deposit_global',
67
+ LIQSOL_POOL: 'liqsol_pool',
68
+ WARRANT_DEPOSIT_RECORD: 'warrant_deposit_record',
69
+ WIRE_SOL_BUCKET: 'wire_sol_bucket',
70
+ TRANCHE_STATE: 'tranche_state',
71
+ USER_WARRANT_RECORD: 'user_warrant_record',
72
+
73
+ // BAR
74
+ BAR_STATE_SEED: 'bar_state',
75
+ BONDED_ACTOR_SEED: 'bonded_actor',
76
+ BOND_LEVEL_SEED: 'bond_level',
64
77
  } as const;
65
78
 
66
79
  /**
67
80
  * Helpers for PDA derivation so clients don’t duplicate logic.
68
81
  */
69
-
70
82
  export const deriveLiqsolMintPda = () =>
71
83
  PublicKey.findProgramAddressSync(
72
84
  [Buffer.from(PDA_SEEDS.LIQSOL_MINT)],
@@ -133,12 +145,6 @@ export const derivePayRateHistoryPda = () =>
133
145
  PROGRAM_IDS.LIQSOL_CORE,
134
146
  )[0];
135
147
 
136
- // export const deriveGlobalStakeInfoPda = () =>
137
- // PublicKey.findProgramAddressSync(
138
- // [Buffer.from(PDA_SEEDS.GLOBAL_STAKE_INFO)],
139
- // PROGRAM_IDS.LIQSOL_CORE,
140
- // )[0];
141
-
142
148
  export const deriveLeaderboardStatePda = () =>
143
149
  PublicKey.findProgramAddressSync(
144
150
  [Buffer.from(PDA_SEEDS.LEADERBOARD_STATE)],
@@ -151,16 +157,81 @@ export const deriveValidatorRecordPda = (voteAccount: PublicKey) =>
151
157
  PROGRAM_IDS.VALIDATOR_LEADERBOARD,
152
158
  )[0];
153
159
 
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
160
  export const deriveStakeControllerVaultPda = () =>
159
161
  PublicKey.findProgramAddressSync(
160
162
  [Buffer.from(PDA_SEEDS.VAULT)],
161
163
  PROGRAM_IDS.LIQSOL_CORE,
162
164
  )[0];
163
165
 
166
+ /**
167
+ * OUTPOST
168
+ */
169
+ export const deriveOutpostGlobalStatePda = () =>
170
+ PublicKey.findProgramAddressSync(
171
+ [Buffer.from(PDA_SEEDS.WARRANT_DEPOSIT_GLOBAL)],
172
+ LIQSOL_CORE,
173
+ )[0];
174
+
175
+ export const deriveOutpostPoolAuthorityPda = () =>
176
+ PublicKey.findProgramAddressSync(
177
+ [Buffer.from(PDA_SEEDS.LIQSOL_POOL)],
178
+ LIQSOL_CORE,
179
+ )[0];
180
+
181
+ export const deriveWireReceiptPda = (user: PublicKey) =>
182
+ PublicKey.findProgramAddressSync(
183
+ [Buffer.from(PDA_SEEDS.WARRANT_DEPOSIT_RECORD), user.toBuffer()],
184
+ LIQSOL_CORE,
185
+ )[0];
186
+
187
+ export const derivePoolUserRecordPda = (poolAuthority: PublicKey) =>
188
+ PublicKey.findProgramAddressSync(
189
+ [Buffer.from(PDA_SEEDS.USER_RECORD), poolAuthority.toBuffer()],
190
+ LIQSOL_CORE,
191
+ )[0];
192
+
193
+ export const deriveUserUserRecordPda = (user: PublicKey) =>
194
+ PublicKey.findProgramAddressSync(
195
+ [Buffer.from(PDA_SEEDS.USER_RECORD), user.toBuffer()],
196
+ LIQSOL_CORE,
197
+ )[0];
198
+
199
+ export const deriveSolBucketPda = () =>
200
+ PublicKey.findProgramAddressSync(
201
+ [Buffer.from(PDA_SEEDS.WIRE_SOL_BUCKET)],
202
+ LIQSOL_CORE,
203
+ )[0];
204
+
205
+ export const deriveTrancheStatePda = () =>
206
+ PublicKey.findProgramAddressSync(
207
+ [Buffer.from(PDA_SEEDS.TRANCHE_STATE)],
208
+ LIQSOL_CORE,
209
+ )[0];
210
+
211
+ export const deriveUserWarrantRecordPda = (user: PublicKey) =>
212
+ PublicKey.findProgramAddressSync(
213
+ [Buffer.from(PDA_SEEDS.USER_WARRANT_RECORD), user.toBuffer()],
214
+ LIQSOL_CORE,
215
+ )[0];
216
+
217
+ export const deriveBarConfigPda = () =>
218
+ PublicKey.findProgramAddressSync(
219
+ [Buffer.from(PDA_SEEDS.BAR_STATE_SEED)],
220
+ LIQSOL_CORE,
221
+ )[0];
222
+
223
+ export const deriveBondLevelPda = (bondLevelId: number[]) =>
224
+ PublicKey.findProgramAddressSync(
225
+ [Buffer.from(PDA_SEEDS.BOND_LEVEL_SEED), Buffer.from(bondLevelId)],
226
+ LIQSOL_CORE,
227
+ )[0];
228
+
229
+ export const deriveBondedActorPda = (actor: PublicKey) =>
230
+ PublicKey.findProgramAddressSync(
231
+ [Buffer.from(PDA_SEEDS.BONDED_ACTOR_SEED), actor.toBuffer()],
232
+ LIQSOL_CORE,
233
+ )[0];
234
+
164
235
  /**
165
236
  * Ephemeral stake account address used per-deposit.
166
237
  * On-chain convention: seed = `ephemeral_<u32>` under StakeProgram.programId.
@@ -173,7 +244,12 @@ export const deriveEphemeralStakeAddress = async (
173
244
  return await PublicKey.createWithSeed(user, seedStr, StakeProgram.programId);
174
245
  };
175
246
 
247
+ /**
248
+ * Constant keys
249
+ */
176
250
 
251
+ export const CHAINLINK_FEED = new PublicKey("99B2bTijsU6f1GCT73HmdR7HCFFjGMBcPZY6jZ96ynrR");
252
+ export const CHAINLINK_PROGRAM = new PublicKey("HEvSKofvBgfaexv23kMabbYqxasxU3mQ4ibBMEmJWHny");
177
253
 
178
254
  /**
179
255
  * ---------------------------------------------------------------------------
@@ -200,43 +276,5 @@ export const LAMPORTS_PER_SOL = 1_000_000_000;
200
276
  export const lamportsToSol = (lamports: number | bigint): number =>
201
277
  Number(lamports) / LAMPORTS_PER_SOL;
202
278
 
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
- // }
279
+ export const solToLamports = (sol: number): bigint =>
280
+ BigInt(Math.round(sol * LAMPORTS_PER_SOL));