@wireio/stake 0.3.0 → 0.4.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.
@@ -6,20 +6,31 @@ import {
6
6
  ASSOCIATED_TOKEN_PROGRAM_ID,
7
7
  } from '@solana/spl-token';
8
8
 
9
- import { buildOutpostAccounts, type OutpostAccounts, buildSolanaTrancheSnapshot } from '../utils';
9
+ import {
10
+ buildOutpostAccounts,
11
+ type OutpostAccounts,
12
+ } from '../utils';
13
+
10
14
  import { SolanaProgramService } from '../program';
11
- import { LiqsolCore } from '../../../assets/solana/types/liqsol_core';
15
+ import type { LiqsolCore } from '../../../assets/solana/types/liqsol_core';
16
+
12
17
  import {
13
18
  GlobalState,
14
19
  PriceHistory,
15
20
  TrancheState,
16
- UserWarrantRecord,
17
21
  WalletLike,
18
- WireReceipt,
22
+ OutpostAccount,
23
+ UserPretokenRecord,
19
24
  } from '../types';
20
- import { derivePriceHistoryPda } from '../constants';
21
- import type { } from '../types';
22
- import { ChainID, SolChainID } from '@wireio/core';
25
+
26
+ import {
27
+ derivePriceHistoryPda,
28
+ CHAINLINK_FEED,
29
+ CHAINLINK_PROGRAM,
30
+ PROGRAM_IDS,
31
+ deriveExtraAccountMetaListPda,
32
+ } from '../constants';
33
+
23
34
 
24
35
  export class TokenClient {
25
36
  private readonly program: Program<LiqsolCore>;
@@ -28,6 +39,10 @@ export class TokenClient {
28
39
  return this.provider.wallet;
29
40
  }
30
41
 
42
+ get connection(): Connection {
43
+ return this.provider.connection;
44
+ }
45
+
31
46
  constructor(private readonly provider: AnchorProvider) {
32
47
  const svc = new SolanaProgramService(provider);
33
48
  this.program = svc.getProgram('liqsolCore');
@@ -51,92 +66,83 @@ export class TokenClient {
51
66
  return this.program.account.trancheState.fetch(trancheState);
52
67
  }
53
68
 
54
- async fetchWireReceipt(user: PublicKey): Promise<WireReceipt> {
55
- const { wireReceipt } = await this.getAccounts(user);
56
- return this.program.account.wireReceipt.fetch(wireReceipt);
69
+ /**
70
+ * Fetch the per-user Outpost account (old "wire receipt").
71
+ * Returns null if the user has never interacted with Outpost.
72
+ */
73
+ async fetchOutpostAccount(user: PublicKey): Promise<OutpostAccount | null> {
74
+ const { outpostAccount } = await this.getAccounts(user);
75
+ return this.program.account.outpostAccount.fetchNullable(outpostAccount);
57
76
  }
58
77
 
59
- async fetchUserWarrantRecord(user: PublicKey): Promise<UserWarrantRecord> {
60
- const { userWarrantRecord } = await this.getAccounts(user);
61
- return this.program.account.userWarrantRecord.fetch(userWarrantRecord);
78
+ /**
79
+ * Fetch the per-user pretoken purchase record.
80
+ * Returns null if the user has never purchased pretokens.
81
+ */
82
+ async fetchUserPretokenRecord(
83
+ user: PublicKey,
84
+ ): Promise<UserPretokenRecord | null> {
85
+ const { userPretokenRecord } = await this.getAccounts(user);
86
+ return this.program.account.userPretokenRecord.fetchNullable(
87
+ userPretokenRecord,
88
+ );
62
89
  }
63
90
 
64
- // ---------------------------------------------------------------------------
65
- // Tranche snapshot / quoting
66
- // ---------------------------------------------------------------------------
67
-
68
91
  // ---------------------------------------------------------------------------
69
92
  // Instruction builders (no send / confirm)
70
93
  // ---------------------------------------------------------------------------
71
94
 
72
- async buildPurchaseWithSolIx(
95
+ /**
96
+ * Build a pretoken `purchase` instruction using liqSOL from the user’s ATA.
97
+ *
98
+ * This mirrors capital-staking `executePurchase` wiring:
99
+ * - amountLamports: liqSOL amount (raw token-2022 units, not SOL)
100
+ */
101
+ async buildPurchaseIx(
73
102
  amountLamports: bigint,
74
103
  user = this.wallet.publicKey,
75
104
  ): Promise<TransactionInstruction> {
76
105
  const a = await this.getAccounts(user);
77
106
 
107
+ const extraAccountMetaList = deriveExtraAccountMetaListPda(a.liqsolMint);
108
+ const liqsolCoreProgram = PROGRAM_IDS.LIQSOL_CORE;
109
+ const transferHookProgram = PROGRAM_IDS.TRANSFER_HOOK;
110
+
78
111
  return this.program.methods
79
- .purchaseWithSol(new BN(amountLamports.toString()))
112
+ .purchase(new BN(amountLamports.toString()))
80
113
  .accounts({
81
114
  user: a.user,
82
115
  liqsolMint: a.liqsolMint,
83
116
  globalState: a.globalState,
117
+ distributionState: a.distributionState,
84
118
 
119
+ // buyer’s liqSOL
120
+ buyerAta: a.userAta,
121
+
122
+ // pool / bucket context
85
123
  poolAuthority: a.poolAuthority,
86
- liqsolPoolAta: a.liqsolPoolAta,
87
- liqsolPoolUserRecord: a.poolUserRecord,
88
- distributionState: a.distributionState,
89
- payRateHistory: a.payRateHistory,
90
124
  bucketAuthority: a.bucketAuthority,
91
125
  bucketTokenAccount: a.bucketTokenAccount,
92
- solBucket: a.solBucket,
93
-
94
- // IDL name is warrantDepositRecord (wireReceipt PDA)
95
- warrantDepositRecord: a.wireReceipt,
126
+ bucketUserRecord: a.bucketUserRecord,
96
127
 
97
- trancheState: a.trancheState,
98
- userWarrantRecord: a.userWarrantRecord,
99
-
100
- chainlinkFeed: a.chainLinkFeed,
101
- chainlinkProgram: a.chainLinkProgram,
102
-
103
- tokenProgram: TOKEN_2022_PROGRAM_ID,
104
- systemProgram: SystemProgram.programId,
105
- })
106
- .instruction();
107
- }
128
+ // distribution userRecords (token-account keyed)
129
+ senderUserRecord: a.userUserRecord,
130
+ receiverUserRecord: a.liqsolPoolUserRecord,
108
131
 
109
- async buildPurchaseWithLiqsolIx(
110
- amountLamports: bigint,
111
- user = this.wallet.publicKey,
112
- ): Promise<TransactionInstruction> {
113
- const a = await this.getAccounts(user);
132
+ // transfer-hook wiring
133
+ extraAccountMetaList,
134
+ liqsolCoreProgram,
135
+ transferHookProgram,
114
136
 
115
- return this.program.methods
116
- .purchaseWithLiqsol(new BN(amountLamports.toString()))
117
- .accounts({
118
- user: a.user,
119
- liqsolMint: a.liqsolMint,
120
- globalState: a.globalState,
121
-
122
- buyerAta: a.userAta,
123
- poolAuthority: a.poolAuthority,
137
+ // pool + outpost + tranche
124
138
  liqsolPoolAta: a.liqsolPoolAta,
125
-
126
- warrantDepositRecord: a.wireReceipt,
127
-
128
- liqsolPoolUserRecord: a.poolUserRecord,
129
- distributionState: a.distributionState,
130
- payRateHistory: a.payRateHistory,
131
- bucketAuthority: a.bucketAuthority,
132
- bucketTokenAccount: a.bucketTokenAccount,
133
- solBucket: a.solBucket,
134
-
139
+ outpostAccount: a.outpostAccount,
135
140
  trancheState: a.trancheState,
136
- userWarrantRecord: a.userWarrantRecord,
141
+ userPretokenRecord: a.userPretokenRecord,
137
142
 
138
- chainlinkFeed: a.chainLinkFeed,
139
- chainlinkProgram: a.chainLinkProgram,
143
+ // Chainlink pricing
144
+ chainlinkFeed: a.chainLinkFeed ?? CHAINLINK_FEED,
145
+ chainlinkProgram: a.chainLinkProgram ?? CHAINLINK_PROGRAM,
140
146
 
141
147
  tokenProgram: TOKEN_2022_PROGRAM_ID,
142
148
  associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
@@ -145,37 +151,12 @@ export class TokenClient {
145
151
  .instruction();
146
152
  }
147
153
 
148
- async buildPurchaseFromYieldIx(
149
- user = this.wallet.publicKey,
150
- ): Promise<TransactionInstruction> {
151
- const a = await this.getAccounts(user);
152
-
153
- return this.program.methods
154
- .purchaseWarrantsFromYield()
155
- .accounts({
156
- user: a.user,
157
- globalState: a.globalState,
158
- liqsolMint: a.liqsolMint,
159
- poolAuthority: a.poolAuthority,
160
- liqsolPoolAta: a.liqsolPoolAta,
161
- solBucket: a.solBucket,
162
-
163
- liqsolPoolUserRecord: a.poolUserRecord,
164
- distributionState: a.distributionState,
165
- payRateHistory: a.payRateHistory,
166
- bucketAuthority: a.bucketAuthority,
167
- bucketTokenAccount: a.bucketTokenAccount,
168
-
169
- trancheState: a.trancheState,
170
- userWarrantRecord: a.userWarrantRecord,
171
- chainlinkFeed: a.chainLinkFeed,
172
- chainlinkProgram: a.chainLinkProgram,
173
-
174
- tokenProgram: TOKEN_2022_PROGRAM_ID,
175
- systemProgram: SystemProgram.programId,
176
- })
177
- .instruction();
178
- }
154
+ // NOTE:
155
+ // - There is no longer `purchaseWithSol` in the IDL - SOL → liqSOL happens
156
+ // through the deposit / liqSOL minting path, not directly in pretokens.
157
+ // - `purchaseFromYield` is an operator-facing / protocol flow and you
158
+ // indicated you’ll trigger it from Wire infra, so we don’t expose a
159
+ // client helper here for now.
179
160
 
180
161
  // ---------------------------------------------------------------------------
181
162
  // Price helpers (SOL/USD via priceHistory account)
@@ -193,7 +174,7 @@ export class TokenClient {
193
174
 
194
175
  /**
195
176
  * Fetch latest SOL/USD price (1e8 scale) from liqsol_core.priceHistory.
196
- * Uses the ring-buffer semantics from earlier SDK code.
177
+ * Uses the ring-buffer semantics from capital-staking.
197
178
  */
198
179
  async getSolPriceUsd(): Promise<bigint> {
199
180
  const priceHistoryPda = derivePriceHistoryPda();
@@ -204,19 +185,23 @@ export class TokenClient {
204
185
  const { prices, nextIndex, count, windowSize } = history;
205
186
 
206
187
  if (!prices || prices.length === 0 || !count) {
207
- throw new Error('Price history is empty no SOL price available');
188
+ throw new Error('Price history is empty - no SOL price available');
208
189
  }
209
190
 
210
191
  const capacity = prices.length || windowSize;
211
192
  if (!capacity) {
212
- throw new Error('Price history capacity is zero – check account layout');
193
+ throw new Error(
194
+ 'Price history capacity is zero - check account layout',
195
+ );
213
196
  }
214
197
 
215
198
  const lastIndex = nextIndex === 0 ? capacity - 1 : nextIndex - 1;
216
199
  const latest = prices[lastIndex];
217
200
 
218
201
  if (!BN.isBN(latest)) {
219
- throw new Error('Latest price entry is not a BN – check IDL/decoder');
202
+ throw new Error(
203
+ 'Latest price entry is not a BN - check IDL/decoder',
204
+ );
220
205
  }
221
206
 
222
207
  return BigInt(latest.toString());
@@ -1,9 +1,10 @@
1
1
  // src/networks/solana/constants.ts
2
2
  import { PublicKey, StakeProgram } from '@solana/web3.js';
3
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";
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
+ import transferHookIDL from '../../assets/solana/idl/transfer_hook.json';
7
8
 
8
9
  /**
9
10
  * ---------------------------------------------------------------------------
@@ -14,27 +15,24 @@ import validatorLeaderboardIDL from "../../assets/solana/idl/validator_leaderboa
14
15
  * - `metadata.address` in your Anchor IDLs under src/assets/solana/idl/*.json
15
16
  * - The program IDs printed by your deploy scripts
16
17
  */
17
- // Extract program IDs from IDL files
18
18
  export const PROGRAM_IDS = {
19
19
  LIQSOL_CORE: new PublicKey(liqsolCoreIDL.address),
20
20
  LIQSOL_TOKEN: new PublicKey(liqSolTokenIDL.address),
21
21
  VALIDATOR_LEADERBOARD: new PublicKey(validatorLeaderboardIDL.address),
22
+ TRANSFER_HOOK: new PublicKey(transferHookIDL.address),
22
23
  } as const;
23
24
 
24
- // Export individual program IDs for convenience
25
25
  export const {
26
26
  LIQSOL_CORE,
27
27
  LIQSOL_TOKEN,
28
28
  VALIDATOR_LEADERBOARD,
29
+ TRANSFER_HOOK,
29
30
  } = PROGRAM_IDS;
30
31
 
31
32
  /**
32
33
  * ---------------------------------------------------------------------------
33
34
  * PDA SEEDS (must match on-chain programs)
34
35
  * ---------------------------------------------------------------------------
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
36
  */
39
37
 
40
38
  export const PDA_SEEDS = {
@@ -52,156 +50,238 @@ export const PDA_SEEDS = {
52
50
 
53
51
  // distribution program (embedded in liqsol_core)
54
52
  DISTRIBUTION_STATE: 'distribution_state',
53
+ // NOTE: in the current IDL, userRecord is keyed by the USER (wallet), not ATA
55
54
  USER_RECORD: 'user_record',
56
55
 
57
- // pay-rate history
56
+ // pay-rate / price history
58
57
  PAY_RATE_HISTORY: 'pay_rate_history',
58
+ PRICE_HISTORY: 'price_history',
59
59
 
60
60
  // validator leaderboard (state + records)
61
61
  LEADERBOARD_STATE: 'leaderboard_state',
62
62
  VALIDATOR_RECORD: 'validator',
63
63
  GLOBAL_STAKE_INFO: 'global_stake_info',
64
64
 
65
- // Outpost
66
- WARRANT_DEPOSIT_GLOBAL: 'warrant_deposit_global',
65
+ // Outpost / Wire pretokens
66
+ OUTPOST_GLOBAL_STATE: 'outpost_global_state',
67
67
  LIQSOL_POOL: 'liqsol_pool',
68
- WARRANT_DEPOSIT_RECORD: 'warrant_deposit_record',
69
- WIRE_SOL_BUCKET: 'wire_sol_bucket',
68
+ OUTPOST_ACCOUNT: 'outpost_account',
69
+ USER_PRETOKEN_RECORD: 'user_pretoken_record',
70
70
  TRANCHE_STATE: 'tranche_state',
71
- USER_WARRANT_RECORD: 'user_warrant_record',
72
71
 
73
- // BAR
72
+ // BAR module (bonded actor roles)
74
73
  BAR_STATE_SEED: 'bar_state',
75
74
  BONDED_ACTOR_SEED: 'bonded_actor',
76
75
  BOND_LEVEL_SEED: 'bond_level',
77
76
 
78
- // Other?
79
- PRICE_HISTORY: 'price_history',
77
+ // SPL transfer-hook extra account metas
78
+ EXTRA_ACCOUNT_METAS: 'extra-account-metas',
79
+
80
+ // Withdraw module / receipts
81
+ WITHDRAW_GLOBAL: 'global',
82
+ STAKE_ALLOCATION_STATE: 'stake_allocation_state',
83
+ STAKE_METRICS: 'stake_metrics',
84
+ MAINTENANCE_LEDGER: 'maintenance_ledger',
85
+ WITHDRAW_MINT_AUTHORITY: 'mint_authority',
86
+ MINT_METADATA: 'mint_metadata',
87
+ LIQ_RECEIPT_DATA: 'liq_receipt_data',
88
+ WITHDRAW_MINT: 'mint',
80
89
  } as const;
81
90
 
82
91
  /**
83
- * Helpers for PDA derivation so clients don’t duplicate logic.
92
+ * ---------------------------------------------------------------------------
93
+ * CORE / DISTRIBUTION / DEPOSIT PDAS
94
+ * ---------------------------------------------------------------------------
84
95
  */
96
+
85
97
  export const deriveLiqsolMintPda = () =>
86
98
  PublicKey.findProgramAddressSync(
87
99
  [Buffer.from(PDA_SEEDS.LIQSOL_MINT)],
88
- PROGRAM_IDS.LIQSOL_TOKEN,
100
+ LIQSOL_TOKEN,
89
101
  )[0];
90
102
 
91
103
  export const deriveLiqsolMintAuthorityPda = () =>
92
104
  PublicKey.findProgramAddressSync(
93
105
  [Buffer.from(PDA_SEEDS.LIQSOL_MINT_AUTHORITY)],
94
- PROGRAM_IDS.LIQSOL_TOKEN,
106
+ LIQSOL_TOKEN,
95
107
  )[0];
96
108
 
97
109
  export const deriveDepositAuthorityPda = () =>
98
110
  PublicKey.findProgramAddressSync(
99
111
  [Buffer.from(PDA_SEEDS.DEPOSIT_AUTHORITY)],
100
- PROGRAM_IDS.LIQSOL_CORE,
112
+ LIQSOL_CORE,
101
113
  )[0];
102
114
 
103
115
  export const deriveVaultPda = () =>
104
116
  PublicKey.findProgramAddressSync(
105
117
  [Buffer.from(PDA_SEEDS.VAULT)],
106
- PROGRAM_IDS.LIQSOL_CORE,
118
+ LIQSOL_CORE,
107
119
  )[0];
108
120
 
109
121
  export const deriveReservePoolPda = () =>
110
122
  PublicKey.findProgramAddressSync(
111
123
  [Buffer.from(PDA_SEEDS.RESERVE_POOL)],
112
- PROGRAM_IDS.LIQSOL_CORE,
124
+ LIQSOL_CORE,
113
125
  )[0];
114
126
 
115
127
  export const deriveStakeControllerStatePda = () =>
116
128
  PublicKey.findProgramAddressSync(
117
129
  [Buffer.from(PDA_SEEDS.STAKE_CONTROLLER_STATE)],
118
- PROGRAM_IDS.LIQSOL_CORE,
130
+ LIQSOL_CORE,
119
131
  )[0];
120
132
 
121
133
  export const derivePayoutStatePda = () =>
122
134
  PublicKey.findProgramAddressSync(
123
135
  [Buffer.from(PDA_SEEDS.PAYOUT_STATE)],
124
- PROGRAM_IDS.LIQSOL_CORE,
136
+ LIQSOL_CORE,
125
137
  )[0];
126
138
 
127
139
  export const deriveBucketAuthorityPda = () =>
128
140
  PublicKey.findProgramAddressSync(
129
141
  [Buffer.from(PDA_SEEDS.BUCKET_AUTHORITY)],
130
- PROGRAM_IDS.LIQSOL_CORE,
142
+ LIQSOL_CORE,
131
143
  )[0];
132
144
 
133
145
  export const deriveDistributionStatePda = () =>
134
146
  PublicKey.findProgramAddressSync(
135
147
  [Buffer.from(PDA_SEEDS.DISTRIBUTION_STATE)],
136
- PROGRAM_IDS.LIQSOL_CORE,
148
+ LIQSOL_CORE,
137
149
  )[0];
138
150
 
151
+ /**
152
+ * user_record PDA
153
+ *
154
+ * In the current liqsol_core IDL, this is keyed by USER (wallet),
155
+ * not by token account.
156
+ */
139
157
  export const deriveUserRecordPda = (user: PublicKey) =>
140
158
  PublicKey.findProgramAddressSync(
141
159
  [Buffer.from(PDA_SEEDS.USER_RECORD), user.toBuffer()],
142
- PROGRAM_IDS.LIQSOL_CORE,
160
+ LIQSOL_CORE,
143
161
  )[0];
144
162
 
145
163
  export const derivePayRateHistoryPda = () =>
146
164
  PublicKey.findProgramAddressSync(
147
165
  [Buffer.from(PDA_SEEDS.PAY_RATE_HISTORY)],
148
- PROGRAM_IDS.LIQSOL_CORE,
166
+ LIQSOL_CORE,
149
167
  )[0];
150
168
 
151
- export const deriveLeaderboardStatePda = () =>
169
+ /**
170
+ * ---------------------------------------------------------------------------
171
+ * WITHDRAW MODULE / RECEIPTS
172
+ * ---------------------------------------------------------------------------
173
+ */
174
+
175
+ export const deriveWithdrawGlobalPda = () =>
152
176
  PublicKey.findProgramAddressSync(
153
- [Buffer.from(PDA_SEEDS.LEADERBOARD_STATE)],
154
- PROGRAM_IDS.VALIDATOR_LEADERBOARD,
177
+ [Buffer.from(PDA_SEEDS.WITHDRAW_GLOBAL)],
178
+ LIQSOL_CORE,
155
179
  )[0];
156
180
 
157
- export const deriveValidatorRecordPda = (voteAccount: PublicKey) =>
181
+ export const deriveStakeAllocationStatePda = () =>
158
182
  PublicKey.findProgramAddressSync(
159
- [Buffer.from(PDA_SEEDS.VALIDATOR_RECORD), voteAccount.toBuffer()],
160
- PROGRAM_IDS.VALIDATOR_LEADERBOARD,
183
+ [Buffer.from(PDA_SEEDS.STAKE_ALLOCATION_STATE)],
184
+ LIQSOL_CORE,
161
185
  )[0];
162
186
 
163
- export const deriveStakeControllerVaultPda = () =>
187
+ export const deriveStakeMetricsPda = () =>
164
188
  PublicKey.findProgramAddressSync(
165
- [Buffer.from(PDA_SEEDS.VAULT)],
166
- PROGRAM_IDS.LIQSOL_CORE,
189
+ [Buffer.from(PDA_SEEDS.STAKE_METRICS)],
190
+ LIQSOL_CORE,
191
+ )[0];
192
+
193
+ export const deriveMaintenanceLedgerPda = () =>
194
+ PublicKey.findProgramAddressSync(
195
+ [Buffer.from(PDA_SEEDS.MAINTENANCE_LEDGER)],
196
+ LIQSOL_CORE,
197
+ )[0];
198
+
199
+ export const deriveWithdrawMintAuthorityPda = () =>
200
+ PublicKey.findProgramAddressSync(
201
+ [Buffer.from(PDA_SEEDS.WITHDRAW_MINT_AUTHORITY)],
202
+ LIQSOL_CORE,
203
+ )[0];
204
+
205
+ export const deriveWithdrawMintMetadataPda = () =>
206
+ PublicKey.findProgramAddressSync(
207
+ [Buffer.from(PDA_SEEDS.MINT_METADATA)],
208
+ LIQSOL_CORE,
167
209
  )[0];
168
210
 
169
211
  /**
170
- * OUTPOST
212
+ * NFT mint for withdrawal receipt, derived from nextReceiptId.
171
213
  */
172
- export const deriveOutpostGlobalStatePda = () =>
214
+ export const deriveWithdrawNftMintPda = (receiptId: bigint | number) => {
215
+ const receiptIdBytes = Buffer.alloc(8);
216
+ // receiptId comes in as BN or bigint upstream → normalize
217
+ const asBigInt =
218
+ typeof receiptId === 'bigint'
219
+ ? receiptId
220
+ : BigInt(receiptId.toString());
221
+ receiptIdBytes.writeBigUInt64LE(asBigInt);
222
+ return PublicKey.findProgramAddressSync(
223
+ [Buffer.from(PDA_SEEDS.WITHDRAW_MINT), receiptIdBytes],
224
+ LIQSOL_CORE,
225
+ )[0];
226
+ };
227
+
228
+ export const deriveLiqReceiptDataPda = (nftMint: PublicKey) =>
173
229
  PublicKey.findProgramAddressSync(
174
- [Buffer.from(PDA_SEEDS.WARRANT_DEPOSIT_GLOBAL)],
230
+ [Buffer.from(PDA_SEEDS.LIQ_RECEIPT_DATA), nftMint.toBuffer()],
175
231
  LIQSOL_CORE,
176
232
  )[0];
177
233
 
178
- export const deriveOutpostPoolAuthorityPda = () =>
234
+ /**
235
+ * ---------------------------------------------------------------------------
236
+ * VALIDATOR LEADERBOARD
237
+ * ---------------------------------------------------------------------------
238
+ */
239
+
240
+ export const deriveLeaderboardStatePda = () =>
179
241
  PublicKey.findProgramAddressSync(
180
- [Buffer.from(PDA_SEEDS.LIQSOL_POOL)],
242
+ [Buffer.from(PDA_SEEDS.LEADERBOARD_STATE)],
243
+ VALIDATOR_LEADERBOARD,
244
+ )[0];
245
+
246
+ export const deriveValidatorRecordPda = (voteAccount: PublicKey) =>
247
+ PublicKey.findProgramAddressSync(
248
+ [Buffer.from(PDA_SEEDS.VALIDATOR_RECORD), voteAccount.toBuffer()],
249
+ VALIDATOR_LEADERBOARD,
250
+ )[0];
251
+
252
+ export const deriveStakeControllerVaultPda = () =>
253
+ PublicKey.findProgramAddressSync(
254
+ [Buffer.from(PDA_SEEDS.VAULT)],
181
255
  LIQSOL_CORE,
182
256
  )[0];
183
257
 
184
- export const deriveWireReceiptPda = (user: PublicKey) =>
258
+ /**
259
+ * ---------------------------------------------------------------------------
260
+ * OUTPOST / PRETOKENS
261
+ * ---------------------------------------------------------------------------
262
+ */
263
+
264
+ export const deriveOutpostGlobalStatePda = () =>
185
265
  PublicKey.findProgramAddressSync(
186
- [Buffer.from(PDA_SEEDS.WARRANT_DEPOSIT_RECORD), user.toBuffer()],
266
+ [Buffer.from(PDA_SEEDS.OUTPOST_GLOBAL_STATE)],
187
267
  LIQSOL_CORE,
188
268
  )[0];
189
269
 
190
- export const derivePoolUserRecordPda = (poolAuthority: PublicKey) =>
270
+ export const deriveOutpostPoolAuthorityPda = () =>
191
271
  PublicKey.findProgramAddressSync(
192
- [Buffer.from(PDA_SEEDS.USER_RECORD), poolAuthority.toBuffer()],
272
+ [Buffer.from(PDA_SEEDS.LIQSOL_POOL)],
193
273
  LIQSOL_CORE,
194
274
  )[0];
195
275
 
196
- export const deriveUserUserRecordPda = (user: PublicKey) =>
276
+ export const deriveOutpostAccountPda = (user: PublicKey) =>
197
277
  PublicKey.findProgramAddressSync(
198
- [Buffer.from(PDA_SEEDS.USER_RECORD), user.toBuffer()],
278
+ [Buffer.from(PDA_SEEDS.OUTPOST_ACCOUNT), user.toBuffer()],
199
279
  LIQSOL_CORE,
200
280
  )[0];
201
281
 
202
- export const deriveSolBucketPda = () =>
282
+ export const deriveUserPretokenRecordPda = (user: PublicKey) =>
203
283
  PublicKey.findProgramAddressSync(
204
- [Buffer.from(PDA_SEEDS.WIRE_SOL_BUCKET)],
284
+ [Buffer.from(PDA_SEEDS.USER_PRETOKEN_RECORD), user.toBuffer()],
205
285
  LIQSOL_CORE,
206
286
  )[0];
207
287
 
@@ -211,12 +291,16 @@ export const deriveTrancheStatePda = () =>
211
291
  LIQSOL_CORE,
212
292
  )[0];
213
293
 
214
- export const deriveUserWarrantRecordPda = (user: PublicKey) =>
294
+ export const derivePriceHistoryPda = () =>
215
295
  PublicKey.findProgramAddressSync(
216
- [Buffer.from(PDA_SEEDS.USER_WARRANT_RECORD), user.toBuffer()],
296
+ [Buffer.from(PDA_SEEDS.PRICE_HISTORY)],
217
297
  LIQSOL_CORE,
218
298
  )[0];
219
299
 
300
+ /**
301
+ * BAR (bonded actor roles)
302
+ */
303
+
220
304
  export const deriveBarConfigPda = () =>
221
305
  PublicKey.findProgramAddressSync(
222
306
  [Buffer.from(PDA_SEEDS.BAR_STATE_SEED)],
@@ -235,10 +319,13 @@ export const deriveBondedActorPda = (actor: PublicKey) =>
235
319
  LIQSOL_CORE,
236
320
  )[0];
237
321
 
238
- export const derivePriceHistoryPda = () =>
322
+ /**
323
+ * SPL Transfer-hook: extra-account-metas PDA for the liqSOL mint.
324
+ */
325
+ export const deriveExtraAccountMetaListPda = (liqsolMint: PublicKey) =>
239
326
  PublicKey.findProgramAddressSync(
240
- [Buffer.from(PDA_SEEDS.PRICE_HISTORY)],
241
- LIQSOL_CORE,
327
+ [Buffer.from(PDA_SEEDS.EXTRA_ACCOUNT_METAS), liqsolMint.toBuffer()],
328
+ PROGRAM_IDS.TRANSFER_HOOK,
242
329
  )[0];
243
330
 
244
331
  /**
@@ -247,18 +334,21 @@ export const derivePriceHistoryPda = () =>
247
334
  */
248
335
  export const deriveEphemeralStakeAddress = async (
249
336
  user: PublicKey,
250
- seed: any,
337
+ seed: number,
251
338
  ): Promise<PublicKey> => {
252
339
  const seedStr = `ephemeral_${seed}`;
253
- return await PublicKey.createWithSeed(user, seedStr, StakeProgram.programId);
340
+ return PublicKey.createWithSeed(user, seedStr, StakeProgram.programId);
254
341
  };
255
342
 
256
343
  /**
257
- * Constant keys
344
+ * Constant keys (Chainlink)
258
345
  */
259
-
260
- export const CHAINLINK_FEED = new PublicKey("99B2bTijsU6f1GCT73HmdR7HCFFjGMBcPZY6jZ96ynrR");
261
- export const CHAINLINK_PROGRAM = new PublicKey("HEvSKofvBgfaexv23kMabbYqxasxU3mQ4ibBMEmJWHny");
346
+ export const CHAINLINK_FEED = new PublicKey(
347
+ '99B2bTijsU6f1GCT73HmdR7HCFFjGMBcPZY6jZ96ynrR',
348
+ );
349
+ export const CHAINLINK_PROGRAM = new PublicKey(
350
+ 'HEvSKofvBgfaexv23kMabbYqxasxU3mQ4ibBMEmJWHny',
351
+ );
262
352
 
263
353
  /**
264
354
  * ---------------------------------------------------------------------------
@@ -276,14 +366,15 @@ export const DEFAULT_AVERAGE_PAY_RATE = BigInt(191_780_821);
276
366
  export const DEFAULT_PAY_RATE_LOOKBACK = 5;
277
367
 
278
368
  // Rent exemption for ephemeral stake account (lamports)
279
- // Mirrors EPHEMERAL_RENT_EXEMPTION = 2_282_880 used in tests
280
369
  export const EPHEMERAL_RENT_EXEMPTION = 2_282_880;
281
370
 
282
371
  // For convenience: lamports <-> SOL helpers (no RPC dependency)
283
372
  export const LAMPORTS_PER_SOL = 1_000_000_000;
284
373
 
374
+ export const INDEX_SCALE = BigInt(1_000_000_000_000); // 1e12
375
+
285
376
  export const lamportsToSol = (lamports: number | bigint): number =>
286
377
  Number(lamports) / LAMPORTS_PER_SOL;
287
378
 
288
379
  export const solToLamports = (sol: number): bigint =>
289
- BigInt(Math.round(sol * LAMPORTS_PER_SOL));
380
+ BigInt(Math.round(sol * LAMPORTS_PER_SOL));