@ignitionfi/spl-stake-pool 1.1.21 → 1.1.23
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/constants.d.ts +1 -0
- package/dist/index.browser.cjs.js +77 -20
- package/dist/index.browser.cjs.js.map +1 -1
- package/dist/index.browser.esm.js +71 -21
- package/dist/index.browser.esm.js.map +1 -1
- package/dist/index.cjs.js +77 -20
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +33 -5
- package/dist/index.esm.js +71 -21
- package/dist/index.esm.js.map +1 -1
- package/dist/index.iife.js +78 -21
- package/dist/index.iife.js.map +1 -1
- package/dist/index.iife.min.js +1 -1
- package/dist/index.iife.min.js.map +1 -1
- package/dist/instructions.d.ts +5 -0
- package/dist/utils/program-address.d.ts +5 -0
- package/package.json +1 -1
- package/src/constants.ts +3 -0
- package/src/index.ts +72 -22
- package/src/instructions.ts +9 -0
- package/src/utils/program-address.ts +22 -0
|
@@ -432,6 +432,8 @@ const MAX_VALIDATORS_TO_UPDATE = 4;
|
|
|
432
432
|
const EPHEMERAL_STAKE_SEED_PREFIX = Buffer$1.from('ephemeral');
|
|
433
433
|
// Seed used to derive transient stake accounts.
|
|
434
434
|
const TRANSIENT_STAKE_SEED_PREFIX = Buffer$1.from('transient');
|
|
435
|
+
// Seed for user stake account created during session withdrawal
|
|
436
|
+
const USER_STAKE_SEED_PREFIX = Buffer$1.from('user_stake');
|
|
435
437
|
// Minimum amount of staked SOL required in a validator stake account to allow
|
|
436
438
|
// for merges without a mismatch on credits observed
|
|
437
439
|
const MINIMUM_ACTIVE_STAKE = LAMPORTS_PER_SOL;
|
|
@@ -540,6 +542,19 @@ function findMetadataAddress(stakePoolMintAddress) {
|
|
|
540
542
|
const [publicKey] = PublicKey.findProgramAddressSync([Buffer$1.from('metadata'), METADATA_PROGRAM_ID.toBuffer(), stakePoolMintAddress.toBuffer()], METADATA_PROGRAM_ID);
|
|
541
543
|
return publicKey;
|
|
542
544
|
}
|
|
545
|
+
/**
|
|
546
|
+
* Generates the user stake account PDA for session-based withdrawals.
|
|
547
|
+
* The PDA is derived from the user's wallet and a unique seed.
|
|
548
|
+
*/
|
|
549
|
+
function findUserStakeProgramAddress(programId, userWallet, seed) {
|
|
550
|
+
const seedBN = typeof seed === 'number' ? new BN(seed) : seed;
|
|
551
|
+
const [publicKey] = PublicKey.findProgramAddressSync([
|
|
552
|
+
USER_STAKE_SEED_PREFIX,
|
|
553
|
+
userWallet.toBuffer(),
|
|
554
|
+
seedBN.toArrayLike(Buffer$1, 'le', 8),
|
|
555
|
+
], programId);
|
|
556
|
+
return publicKey;
|
|
557
|
+
}
|
|
543
558
|
|
|
544
559
|
class BNLayout extends Layout {
|
|
545
560
|
constructor(span, signed, property) {
|
|
@@ -1102,6 +1117,7 @@ const STAKE_POOL_INSTRUCTION_LAYOUTS = Object.freeze({
|
|
|
1102
1117
|
BufferLayout.u8('instruction'),
|
|
1103
1118
|
BufferLayout.ns64('poolTokensIn'),
|
|
1104
1119
|
BufferLayout.ns64('minimumLamportsOut'),
|
|
1120
|
+
BufferLayout.ns64('userStakeSeed'),
|
|
1105
1121
|
]),
|
|
1106
1122
|
},
|
|
1107
1123
|
});
|
|
@@ -1587,6 +1603,7 @@ class StakePoolInstruction {
|
|
|
1587
1603
|
const data = encodeData(type, {
|
|
1588
1604
|
poolTokensIn: params.poolTokensIn,
|
|
1589
1605
|
minimumLamportsOut: params.minimumLamportsOut,
|
|
1606
|
+
userStakeSeed: params.userStakeSeed,
|
|
1590
1607
|
});
|
|
1591
1608
|
const keys = [
|
|
1592
1609
|
{ pubkey: params.stakePool, isSigner: false, isWritable: true },
|
|
@@ -1603,6 +1620,8 @@ class StakePoolInstruction {
|
|
|
1603
1620
|
{ pubkey: params.tokenProgramId, isSigner: false, isWritable: false },
|
|
1604
1621
|
{ pubkey: StakeProgram.programId, isSigner: false, isWritable: false },
|
|
1605
1622
|
{ pubkey: params.programSigner, isSigner: false, isWritable: false },
|
|
1623
|
+
{ pubkey: params.payer, isSigner: true, isWritable: true },
|
|
1624
|
+
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
|
|
1606
1625
|
];
|
|
1607
1626
|
return new TransactionInstruction({
|
|
1608
1627
|
programId: params.programId,
|
|
@@ -2220,10 +2239,46 @@ async function withdrawWsolWithSession(connection, stakePoolAddress, signerOrSes
|
|
|
2220
2239
|
};
|
|
2221
2240
|
}
|
|
2222
2241
|
/**
|
|
2223
|
-
*
|
|
2224
|
-
*
|
|
2242
|
+
* Finds the next available seed for creating a user stake PDA.
|
|
2243
|
+
* Scans from startSeed until an unused PDA is found.
|
|
2244
|
+
*
|
|
2245
|
+
* @param connection - Solana connection
|
|
2246
|
+
* @param programId - The stake pool program ID
|
|
2247
|
+
* @param userPubkey - User's wallet (used for PDA derivation)
|
|
2248
|
+
* @param startSeed - Starting seed to search from (default: 0)
|
|
2249
|
+
* @param maxSeed - Maximum seed to check before giving up (default: 1000)
|
|
2250
|
+
* @returns The next available seed
|
|
2251
|
+
* @throws Error if no available seed found within maxSeed
|
|
2252
|
+
*/
|
|
2253
|
+
async function findNextUserStakeSeed(connection, programId, userPubkey, startSeed = 0, maxSeed = 1000) {
|
|
2254
|
+
for (let seed = startSeed; seed < startSeed + maxSeed; seed++) {
|
|
2255
|
+
const pda = findUserStakeProgramAddress(programId, userPubkey, seed);
|
|
2256
|
+
const account = await connection.getAccountInfo(pda);
|
|
2257
|
+
if (!account) {
|
|
2258
|
+
return seed;
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
throw new Error(`No available user stake seed found between ${startSeed} and ${startSeed + maxSeed - 1}`);
|
|
2262
|
+
}
|
|
2263
|
+
/**
|
|
2264
|
+
* Withdraws stake from a stake pool using a Fogo session.
|
|
2265
|
+
*
|
|
2266
|
+
* The on-chain program creates stake account PDAs, so no pre-creation step is needed.
|
|
2267
|
+
* The paymaster payer provides rent for the stake account PDAs.
|
|
2268
|
+
*
|
|
2269
|
+
* @param connection - Solana connection
|
|
2270
|
+
* @param stakePoolAddress - The stake pool to withdraw from
|
|
2271
|
+
* @param signerOrSession - The session signer public key
|
|
2272
|
+
* @param userPubkey - User's wallet (used for PDA derivation and token ownership)
|
|
2273
|
+
* @param payer - Payer for stake account rent (paymaster payer in session context)
|
|
2274
|
+
* @param amount - Amount of pool tokens to withdraw
|
|
2275
|
+
* @param userStakeSeedStart - Starting seed for user stake PDA derivation (default: 0)
|
|
2276
|
+
* @param useReserve - Whether to withdraw from reserve (default: false)
|
|
2277
|
+
* @param voteAccountAddress - Optional specific validator to withdraw from
|
|
2278
|
+
* @param minimumLamportsOut - Minimum lamports to receive (slippage protection)
|
|
2279
|
+
* @param validatorComparator - Optional comparator for validator selection
|
|
2225
2280
|
*/
|
|
2226
|
-
async function withdrawStakeWithSession(connection, stakePoolAddress, signerOrSession, userPubkey, amount, useReserve = false, voteAccountAddress, minimumLamportsOut = 0,
|
|
2281
|
+
async function withdrawStakeWithSession(connection, stakePoolAddress, signerOrSession, userPubkey, payer, amount, userStakeSeedStart = 0, useReserve = false, voteAccountAddress, minimumLamportsOut = 0, validatorComparator) {
|
|
2227
2282
|
const stakePoolAccount = await getStakePoolAccount(connection, stakePoolAddress);
|
|
2228
2283
|
const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint);
|
|
2229
2284
|
const stakePool = stakePoolAccount.account.data;
|
|
@@ -2273,8 +2328,8 @@ async function withdrawStakeWithSession(connection, stakePoolAddress, signerOrSe
|
|
|
2273
2328
|
withdrawAccounts.push(...(await prepareWithdrawAccounts(connection, stakePool, stakePoolAddress, poolAmount, validatorComparator, poolTokenAccount.equals(stakePool.managerFeeAccount))));
|
|
2274
2329
|
}
|
|
2275
2330
|
const instructions = [];
|
|
2276
|
-
const signers = [];
|
|
2277
2331
|
const stakeAccountPubkeys = [];
|
|
2332
|
+
const userStakeSeeds = [];
|
|
2278
2333
|
// Max 5 accounts to prevent an error: "Transaction too large"
|
|
2279
2334
|
const maxWithdrawAccounts = 5;
|
|
2280
2335
|
let i = 0;
|
|
@@ -2282,41 +2337,36 @@ async function withdrawStakeWithSession(connection, stakePoolAddress, signerOrSe
|
|
|
2282
2337
|
if (i >= maxWithdrawAccounts) {
|
|
2283
2338
|
break;
|
|
2284
2339
|
}
|
|
2285
|
-
//
|
|
2286
|
-
const
|
|
2287
|
-
|
|
2288
|
-
stakeAccountPubkeys.push(
|
|
2289
|
-
|
|
2290
|
-
|
|
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
|
|
2340
|
+
// Derive the stake account PDA for this withdrawal
|
|
2341
|
+
const userStakeSeed = userStakeSeedStart + i;
|
|
2342
|
+
const stakeReceiverPubkey = findUserStakeProgramAddress(stakePoolProgramId, userPubkey, userStakeSeed);
|
|
2343
|
+
stakeAccountPubkeys.push(stakeReceiverPubkey);
|
|
2344
|
+
userStakeSeeds.push(userStakeSeed);
|
|
2345
|
+
// The on-chain program will create the stake account PDA
|
|
2298
2346
|
instructions.push(StakePoolInstruction.withdrawStakeWithSession({
|
|
2299
2347
|
programId: stakePoolProgramId,
|
|
2300
2348
|
stakePool: stakePoolAddress,
|
|
2301
2349
|
validatorList: stakePool.validatorList,
|
|
2302
2350
|
withdrawAuthority,
|
|
2303
2351
|
stakeToSplit: withdrawAccount.stakeAddress,
|
|
2304
|
-
stakeToReceive:
|
|
2352
|
+
stakeToReceive: stakeReceiverPubkey,
|
|
2305
2353
|
sessionSigner: signerOrSession,
|
|
2306
2354
|
burnFromPool: poolTokenAccount,
|
|
2307
2355
|
managerFeeAccount: stakePool.managerFeeAccount,
|
|
2308
2356
|
poolMint: stakePool.poolMint,
|
|
2309
2357
|
tokenProgramId: stakePool.tokenProgramId,
|
|
2310
2358
|
programSigner,
|
|
2359
|
+
payer,
|
|
2311
2360
|
poolTokensIn: withdrawAccount.poolAmount.toNumber(),
|
|
2312
|
-
minimumLamportsOut
|
|
2361
|
+
minimumLamportsOut,
|
|
2362
|
+
userStakeSeed,
|
|
2313
2363
|
}));
|
|
2314
2364
|
i++;
|
|
2315
2365
|
}
|
|
2316
2366
|
return {
|
|
2317
2367
|
instructions,
|
|
2318
|
-
signers,
|
|
2319
2368
|
stakeAccountPubkeys,
|
|
2369
|
+
userStakeSeeds,
|
|
2320
2370
|
};
|
|
2321
2371
|
}
|
|
2322
2372
|
async function addValidatorToPool(connection, stakePoolAddress, validatorVote, seed) {
|
|
@@ -2681,5 +2731,5 @@ async function updatePoolTokenMetadata(connection, stakePoolAddress, name, symbo
|
|
|
2681
2731
|
};
|
|
2682
2732
|
}
|
|
2683
2733
|
|
|
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 };
|
|
2734
|
+
export { DEVNET_STAKE_POOL_PROGRAM_ID, STAKE_POOL_INSTRUCTION_LAYOUTS, STAKE_POOL_PROGRAM_ID, StakePoolInstruction, StakePoolLayout, ValidatorListLayout, ValidatorStakeInfoLayout, addValidatorToPool, createPoolTokenMetadata, decreaseValidatorStake, depositSol, depositStake, depositWsolWithSession, findEphemeralStakeProgramAddress, findNextUserStakeSeed, findStakeProgramAddress, findTransientStakeProgramAddress, findUserStakeProgramAddress, findWithdrawAuthorityProgramAddress, findWsolTransientProgramAddress, getStakeAccount, getStakePoolAccount, getStakePoolAccounts, getStakePoolProgramId, increaseValidatorStake, removeValidatorFromPool, stakePoolInfo, tokenMetadataLayout, updatePoolTokenMetadata, updateStakePool, withdrawSol, withdrawStake, withdrawStakeWithSession, withdrawWsolWithSession };
|
|
2685
2735
|
//# sourceMappingURL=index.browser.esm.js.map
|