@ignitionfi/spl-stake-pool 1.1.19 → 1.1.21

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/dist/index.d.ts CHANGED
@@ -86,10 +86,19 @@ export declare function withdrawSol(connection: Connection, stakePoolAddress: Pu
86
86
  /**
87
87
  * Creates instructions required to withdraw wSOL from a stake pool.
88
88
  */
89
- export declare function withdrawWsolWithSession(connection: Connection, stakePoolAddress: PublicKey, signerOrSession: PublicKey, userPubkey: PublicKey, amount: number, minimumLamportsOut?: number, solWithdrawAuthority?: PublicKey): Promise<{
89
+ export declare function withdrawWsolWithSession(connection: Connection, stakePoolAddress: PublicKey, signerOrSession: PublicKey, userPubkey: PublicKey, amount: number, minimumLamportsOut?: number, solWithdrawAuthority?: PublicKey, payer?: PublicKey): Promise<{
90
90
  instructions: TransactionInstruction[];
91
91
  signers: Signer[];
92
92
  }>;
93
+ /**
94
+ * Creates instructions required to withdraw stake from a stake pool using a Fogo session.
95
+ * The withdrawn stake account will be authorized to the user's wallet.
96
+ */
97
+ export declare function withdrawStakeWithSession(connection: Connection, stakePoolAddress: PublicKey, signerOrSession: PublicKey, userPubkey: PublicKey, amount: number, useReserve?: boolean, voteAccountAddress?: PublicKey, minimumLamportsOut?: number, payer?: PublicKey, validatorComparator?: (_a: ValidatorAccount, _b: ValidatorAccount) => number): Promise<{
98
+ instructions: TransactionInstruction[];
99
+ signers: Signer[];
100
+ stakeAccountPubkeys: PublicKey[];
101
+ }>;
93
102
  export declare function addValidatorToPool(connection: Connection, stakePoolAddress: PublicKey, validatorVote: PublicKey, seed?: number): Promise<{
94
103
  instructions: TransactionInstruction[];
95
104
  }>;
package/dist/index.esm.js CHANGED
@@ -1062,7 +1062,8 @@ const STAKE_POOL_INSTRUCTION_LAYOUTS = Object.freeze({
1062
1062
  index: 24,
1063
1063
  layout: BufferLayout.struct([
1064
1064
  BufferLayout.u8('instruction'),
1065
- BufferLayout.ns64('lamports'),
1065
+ BufferLayout.ns64('poolTokensIn'),
1066
+ BufferLayout.ns64('minimumLamportsOut'),
1066
1067
  ]),
1067
1068
  },
1068
1069
  DepositSolWithSlippage: {
@@ -1095,6 +1096,14 @@ const STAKE_POOL_INSTRUCTION_LAYOUTS = Object.freeze({
1095
1096
  BufferLayout.ns64('minimumLamportsOut'),
1096
1097
  ]),
1097
1098
  },
1099
+ WithdrawStakeWithSession: {
1100
+ index: 29,
1101
+ layout: BufferLayout.struct([
1102
+ BufferLayout.u8('instruction'),
1103
+ BufferLayout.ns64('poolTokensIn'),
1104
+ BufferLayout.ns64('minimumLamportsOut'),
1105
+ ]),
1106
+ },
1098
1107
  });
1099
1108
  /**
1100
1109
  * Stake Pool Instruction class
@@ -1530,6 +1539,7 @@ class StakePoolInstruction {
1530
1539
  * Creates a transaction instruction to withdraw WSOL from a stake pool using a session.
1531
1540
  */
1532
1541
  static withdrawWsolWithSession(params) {
1542
+ var _a;
1533
1543
  const type = STAKE_POOL_INSTRUCTION_LAYOUTS.WithdrawWsolWithSession;
1534
1544
  const data = encodeData(type, {
1535
1545
  poolTokensIn: params.poolTokensIn,
@@ -1550,6 +1560,9 @@ class StakePoolInstruction {
1550
1560
  { pubkey: params.tokenProgramId, isSigner: false, isWritable: false },
1551
1561
  { pubkey: params.wsolMint, isSigner: false, isWritable: false },
1552
1562
  { pubkey: params.programSigner, isSigner: false, isWritable: true },
1563
+ { pubkey: (_a = params.payer) !== null && _a !== void 0 ? _a : params.userTransferAuthority, isSigner: true, isWritable: true },
1564
+ { pubkey: params.userWallet, isSigner: false, isWritable: false },
1565
+ { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
1553
1566
  ];
1554
1567
  if (params.solWithdrawAuthority) {
1555
1568
  keys.push({
@@ -1558,6 +1571,39 @@ class StakePoolInstruction {
1558
1571
  isWritable: false,
1559
1572
  });
1560
1573
  }
1574
+ // Associated Token Program must be last - only needed in transaction for CPI routing
1575
+ keys.push({ pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false });
1576
+ return new TransactionInstruction({
1577
+ programId: params.programId,
1578
+ keys,
1579
+ data,
1580
+ });
1581
+ }
1582
+ /**
1583
+ * Creates a transaction instruction to withdraw stake from a stake pool using a Fogo session.
1584
+ */
1585
+ static withdrawStakeWithSession(params) {
1586
+ const type = STAKE_POOL_INSTRUCTION_LAYOUTS.WithdrawStakeWithSession;
1587
+ const data = encodeData(type, {
1588
+ poolTokensIn: params.poolTokensIn,
1589
+ minimumLamportsOut: params.minimumLamportsOut,
1590
+ });
1591
+ const keys = [
1592
+ { pubkey: params.stakePool, isSigner: false, isWritable: true },
1593
+ { pubkey: params.validatorList, isSigner: false, isWritable: true },
1594
+ { pubkey: params.withdrawAuthority, isSigner: false, isWritable: false },
1595
+ { pubkey: params.stakeToSplit, isSigner: false, isWritable: true },
1596
+ { pubkey: params.stakeToReceive, isSigner: false, isWritable: true },
1597
+ { pubkey: params.sessionSigner, isSigner: true, isWritable: false }, // user_stake_authority_info (signer_or_session)
1598
+ { pubkey: params.sessionSigner, isSigner: false, isWritable: false }, // user_transfer_authority_info (not used in session path)
1599
+ { pubkey: params.burnFromPool, isSigner: false, isWritable: true },
1600
+ { pubkey: params.managerFeeAccount, isSigner: false, isWritable: true },
1601
+ { pubkey: params.poolMint, isSigner: false, isWritable: true },
1602
+ { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
1603
+ { pubkey: params.tokenProgramId, isSigner: false, isWritable: false },
1604
+ { pubkey: StakeProgram.programId, isSigner: false, isWritable: false },
1605
+ { pubkey: params.programSigner, isSigner: false, isWritable: false },
1606
+ ];
1561
1607
  return new TransactionInstruction({
1562
1608
  programId: params.programId,
1563
1609
  keys,
@@ -2131,7 +2177,7 @@ async function withdrawSol(connection, stakePoolAddress, tokenOwner, solReceiver
2131
2177
  /**
2132
2178
  * Creates instructions required to withdraw wSOL from a stake pool.
2133
2179
  */
2134
- async function withdrawWsolWithSession(connection, stakePoolAddress, signerOrSession, userPubkey, amount, minimumLamportsOut = 0, solWithdrawAuthority) {
2180
+ async function withdrawWsolWithSession(connection, stakePoolAddress, signerOrSession, userPubkey, amount, minimumLamportsOut = 0, solWithdrawAuthority, payer) {
2135
2181
  const stakePoolAccount = await getStakePoolAccount(connection, stakePoolAddress);
2136
2182
  const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint);
2137
2183
  const stakePool = stakePoolAccount.account.data;
@@ -2145,7 +2191,8 @@ async function withdrawWsolWithSession(connection, stakePoolAddress, signerOrSes
2145
2191
  const userWsolAccount = getAssociatedTokenAddressSync(NATIVE_MINT, userPubkey);
2146
2192
  const instructions = [];
2147
2193
  const signers = [];
2148
- instructions.push(createAssociatedTokenAccountIdempotentInstruction(signerOrSession, userWsolAccount, userPubkey, NATIVE_MINT));
2194
+ // The program handles wSOL ATA creation internally
2195
+ // This prevents rent drain attacks where paymaster pays for ATA and user reclaims rent
2149
2196
  const [programSigner] = PublicKey.findProgramAddressSync([Buffer.from('fogo_session_program_signer')], stakePoolProgramId);
2150
2197
  const withdrawAuthority = await findWithdrawAuthorityProgramAddress(stakePoolProgramId, stakePoolAddress);
2151
2198
  instructions.push(StakePoolInstruction.withdrawWsolWithSession({
@@ -2162,6 +2209,8 @@ async function withdrawWsolWithSession(connection, stakePoolAddress, signerOrSes
2162
2209
  solWithdrawAuthority,
2163
2210
  wsolMint: NATIVE_MINT,
2164
2211
  programSigner,
2212
+ userWallet: userPubkey,
2213
+ payer,
2165
2214
  poolTokensIn: poolTokens,
2166
2215
  minimumLamportsOut,
2167
2216
  }));
@@ -2170,6 +2219,106 @@ async function withdrawWsolWithSession(connection, stakePoolAddress, signerOrSes
2170
2219
  signers,
2171
2220
  };
2172
2221
  }
2222
+ /**
2223
+ * Creates instructions required to withdraw stake from a stake pool using a Fogo session.
2224
+ * The withdrawn stake account will be authorized to the user's wallet.
2225
+ */
2226
+ async function withdrawStakeWithSession(connection, stakePoolAddress, signerOrSession, userPubkey, amount, useReserve = false, voteAccountAddress, minimumLamportsOut = 0, payer, validatorComparator) {
2227
+ const stakePoolAccount = await getStakePoolAccount(connection, stakePoolAddress);
2228
+ const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint);
2229
+ const stakePool = stakePoolAccount.account.data;
2230
+ const poolTokens = solToLamports(amount);
2231
+ const poolAmount = new BN(poolTokens);
2232
+ const poolTokenAccount = getAssociatedTokenAddressSync(stakePool.poolMint, userPubkey);
2233
+ const tokenAccount = await getAccount(connection, poolTokenAccount);
2234
+ if (tokenAccount.amount < poolTokens) {
2235
+ throw new Error(`Not enough token balance to withdraw ${amount} pool tokens.
2236
+ Maximum withdraw amount is ${lamportsToSol(tokenAccount.amount)} pool tokens.`);
2237
+ }
2238
+ const [programSigner] = PublicKey.findProgramAddressSync([Buffer.from('fogo_session_program_signer')], stakePoolProgramId);
2239
+ const withdrawAuthority = await findWithdrawAuthorityProgramAddress(stakePoolProgramId, stakePoolAddress);
2240
+ const stakeAccountRentExemption = await connection.getMinimumBalanceForRentExemption(StakeProgram.space);
2241
+ // Determine which stake accounts to withdraw from
2242
+ const withdrawAccounts = [];
2243
+ if (useReserve) {
2244
+ withdrawAccounts.push({
2245
+ stakeAddress: stakePool.reserveStake,
2246
+ voteAddress: undefined,
2247
+ poolAmount,
2248
+ });
2249
+ }
2250
+ else if (voteAccountAddress) {
2251
+ const stakeAccountAddress = await findStakeProgramAddress(stakePoolProgramId, voteAccountAddress, stakePoolAddress);
2252
+ const stakeAccount = await connection.getAccountInfo(stakeAccountAddress);
2253
+ if (!stakeAccount) {
2254
+ throw new Error(`Validator stake account not found for vote address ${voteAccountAddress.toBase58()}`);
2255
+ }
2256
+ const availableLamports = new BN(stakeAccount.lamports - MINIMUM_ACTIVE_STAKE - stakeAccountRentExemption);
2257
+ if (availableLamports.lt(new BN(0))) {
2258
+ throw new Error('Invalid Stake Account');
2259
+ }
2260
+ const availableForWithdrawal = calcLamportsWithdrawAmount(stakePool, availableLamports);
2261
+ if (availableForWithdrawal.lt(poolAmount)) {
2262
+ throw new Error(`Not enough lamports available for withdrawal from ${stakeAccountAddress},
2263
+ ${poolAmount} asked, ${availableForWithdrawal} available.`);
2264
+ }
2265
+ withdrawAccounts.push({
2266
+ stakeAddress: stakeAccountAddress,
2267
+ voteAddress: voteAccountAddress,
2268
+ poolAmount,
2269
+ });
2270
+ }
2271
+ else {
2272
+ // Get the list of accounts to withdraw from automatically
2273
+ withdrawAccounts.push(...(await prepareWithdrawAccounts(connection, stakePool, stakePoolAddress, poolAmount, validatorComparator, poolTokenAccount.equals(stakePool.managerFeeAccount))));
2274
+ }
2275
+ const instructions = [];
2276
+ const signers = [];
2277
+ const stakeAccountPubkeys = [];
2278
+ // Max 5 accounts to prevent an error: "Transaction too large"
2279
+ const maxWithdrawAccounts = 5;
2280
+ let i = 0;
2281
+ for (const withdrawAccount of withdrawAccounts) {
2282
+ if (i >= maxWithdrawAccounts) {
2283
+ break;
2284
+ }
2285
+ // Create a new stake account to receive the withdrawal
2286
+ const stakeReceiver = Keypair.generate();
2287
+ signers.push(stakeReceiver);
2288
+ stakeAccountPubkeys.push(stakeReceiver.publicKey);
2289
+ // Create the stake account that will receive the split stake
2290
+ instructions.push(SystemProgram.createAccount({
2291
+ fromPubkey: payer !== null && payer !== void 0 ? payer : userPubkey,
2292
+ newAccountPubkey: stakeReceiver.publicKey,
2293
+ lamports: stakeAccountRentExemption,
2294
+ space: StakeProgram.space,
2295
+ programId: StakeProgram.programId,
2296
+ }));
2297
+ // Add the withdraw stake with session instruction
2298
+ instructions.push(StakePoolInstruction.withdrawStakeWithSession({
2299
+ programId: stakePoolProgramId,
2300
+ stakePool: stakePoolAddress,
2301
+ validatorList: stakePool.validatorList,
2302
+ withdrawAuthority,
2303
+ stakeToSplit: withdrawAccount.stakeAddress,
2304
+ stakeToReceive: stakeReceiver.publicKey,
2305
+ sessionSigner: signerOrSession,
2306
+ burnFromPool: poolTokenAccount,
2307
+ managerFeeAccount: stakePool.managerFeeAccount,
2308
+ poolMint: stakePool.poolMint,
2309
+ tokenProgramId: stakePool.tokenProgramId,
2310
+ programSigner,
2311
+ poolTokensIn: withdrawAccount.poolAmount.toNumber(),
2312
+ minimumLamportsOut: solToLamports(minimumLamportsOut),
2313
+ }));
2314
+ i++;
2315
+ }
2316
+ return {
2317
+ instructions,
2318
+ signers,
2319
+ stakeAccountPubkeys,
2320
+ };
2321
+ }
2173
2322
  async function addValidatorToPool(connection, stakePoolAddress, validatorVote, seed) {
2174
2323
  const stakePoolAccount = await getStakePoolAccount(connection, stakePoolAddress);
2175
2324
  const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint);
@@ -2532,5 +2681,5 @@ async function updatePoolTokenMetadata(connection, stakePoolAddress, name, symbo
2532
2681
  };
2533
2682
  }
2534
2683
 
2535
- export { DEVNET_STAKE_POOL_PROGRAM_ID, STAKE_POOL_INSTRUCTION_LAYOUTS, STAKE_POOL_PROGRAM_ID, StakePoolInstruction, StakePoolLayout, ValidatorListLayout, ValidatorStakeInfoLayout, addValidatorToPool, createPoolTokenMetadata, decreaseValidatorStake, depositSol, depositStake, depositWsolWithSession, getStakeAccount, getStakePoolAccount, getStakePoolAccounts, getStakePoolProgramId, increaseValidatorStake, removeValidatorFromPool, stakePoolInfo, tokenMetadataLayout, updatePoolTokenMetadata, updateStakePool, withdrawSol, withdrawStake, withdrawWsolWithSession };
2684
+ export { DEVNET_STAKE_POOL_PROGRAM_ID, STAKE_POOL_INSTRUCTION_LAYOUTS, STAKE_POOL_PROGRAM_ID, StakePoolInstruction, StakePoolLayout, ValidatorListLayout, ValidatorStakeInfoLayout, addValidatorToPool, createPoolTokenMetadata, decreaseValidatorStake, depositSol, depositStake, depositWsolWithSession, getStakeAccount, getStakePoolAccount, getStakePoolAccounts, getStakePoolProgramId, increaseValidatorStake, removeValidatorFromPool, stakePoolInfo, tokenMetadataLayout, updatePoolTokenMetadata, updateStakePool, withdrawSol, withdrawStake, withdrawStakeWithSession, withdrawWsolWithSession };
2536
2685
  //# sourceMappingURL=index.esm.js.map