@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
package/dist/constants.d.ts
CHANGED
|
@@ -9,4 +9,5 @@ export declare const DEVNET_STAKE_POOL_PROGRAM_ID: PublicKey;
|
|
|
9
9
|
export declare const MAX_VALIDATORS_TO_UPDATE = 4;
|
|
10
10
|
export declare const EPHEMERAL_STAKE_SEED_PREFIX: Buffer<ArrayBuffer>;
|
|
11
11
|
export declare const TRANSIENT_STAKE_SEED_PREFIX: Buffer<ArrayBuffer>;
|
|
12
|
+
export declare const USER_STAKE_SEED_PREFIX: Buffer<ArrayBuffer>;
|
|
12
13
|
export declare const MINIMUM_ACTIVE_STAKE = 1000000000;
|
|
@@ -453,6 +453,8 @@ const MAX_VALIDATORS_TO_UPDATE = 4;
|
|
|
453
453
|
const EPHEMERAL_STAKE_SEED_PREFIX = node_buffer.Buffer.from('ephemeral');
|
|
454
454
|
// Seed used to derive transient stake accounts.
|
|
455
455
|
const TRANSIENT_STAKE_SEED_PREFIX = node_buffer.Buffer.from('transient');
|
|
456
|
+
// Seed for user stake account created during session withdrawal
|
|
457
|
+
const USER_STAKE_SEED_PREFIX = node_buffer.Buffer.from('user_stake');
|
|
456
458
|
// Minimum amount of staked SOL required in a validator stake account to allow
|
|
457
459
|
// for merges without a mismatch on credits observed
|
|
458
460
|
const MINIMUM_ACTIVE_STAKE = web3_js.LAMPORTS_PER_SOL;
|
|
@@ -561,6 +563,19 @@ function findMetadataAddress(stakePoolMintAddress) {
|
|
|
561
563
|
const [publicKey] = web3_js.PublicKey.findProgramAddressSync([node_buffer.Buffer.from('metadata'), METADATA_PROGRAM_ID.toBuffer(), stakePoolMintAddress.toBuffer()], METADATA_PROGRAM_ID);
|
|
562
564
|
return publicKey;
|
|
563
565
|
}
|
|
566
|
+
/**
|
|
567
|
+
* Generates the user stake account PDA for session-based withdrawals.
|
|
568
|
+
* The PDA is derived from the user's wallet and a unique seed.
|
|
569
|
+
*/
|
|
570
|
+
function findUserStakeProgramAddress(programId, userWallet, seed) {
|
|
571
|
+
const seedBN = typeof seed === 'number' ? new BN(seed) : seed;
|
|
572
|
+
const [publicKey] = web3_js.PublicKey.findProgramAddressSync([
|
|
573
|
+
USER_STAKE_SEED_PREFIX,
|
|
574
|
+
userWallet.toBuffer(),
|
|
575
|
+
seedBN.toArrayLike(node_buffer.Buffer, 'le', 8),
|
|
576
|
+
], programId);
|
|
577
|
+
return publicKey;
|
|
578
|
+
}
|
|
564
579
|
|
|
565
580
|
class BNLayout extends bufferLayout.Layout {
|
|
566
581
|
constructor(span, signed, property) {
|
|
@@ -1123,6 +1138,7 @@ const STAKE_POOL_INSTRUCTION_LAYOUTS = Object.freeze({
|
|
|
1123
1138
|
BufferLayout__namespace.u8('instruction'),
|
|
1124
1139
|
BufferLayout__namespace.ns64('poolTokensIn'),
|
|
1125
1140
|
BufferLayout__namespace.ns64('minimumLamportsOut'),
|
|
1141
|
+
BufferLayout__namespace.ns64('userStakeSeed'),
|
|
1126
1142
|
]),
|
|
1127
1143
|
},
|
|
1128
1144
|
});
|
|
@@ -1608,6 +1624,7 @@ class StakePoolInstruction {
|
|
|
1608
1624
|
const data = encodeData(type, {
|
|
1609
1625
|
poolTokensIn: params.poolTokensIn,
|
|
1610
1626
|
minimumLamportsOut: params.minimumLamportsOut,
|
|
1627
|
+
userStakeSeed: params.userStakeSeed,
|
|
1611
1628
|
});
|
|
1612
1629
|
const keys = [
|
|
1613
1630
|
{ pubkey: params.stakePool, isSigner: false, isWritable: true },
|
|
@@ -1624,6 +1641,8 @@ class StakePoolInstruction {
|
|
|
1624
1641
|
{ pubkey: params.tokenProgramId, isSigner: false, isWritable: false },
|
|
1625
1642
|
{ pubkey: web3_js.StakeProgram.programId, isSigner: false, isWritable: false },
|
|
1626
1643
|
{ pubkey: params.programSigner, isSigner: false, isWritable: false },
|
|
1644
|
+
{ pubkey: params.payer, isSigner: true, isWritable: true },
|
|
1645
|
+
{ pubkey: web3_js.SystemProgram.programId, isSigner: false, isWritable: false },
|
|
1627
1646
|
];
|
|
1628
1647
|
return new web3_js.TransactionInstruction({
|
|
1629
1648
|
programId: params.programId,
|
|
@@ -2241,10 +2260,46 @@ async function withdrawWsolWithSession(connection, stakePoolAddress, signerOrSes
|
|
|
2241
2260
|
};
|
|
2242
2261
|
}
|
|
2243
2262
|
/**
|
|
2244
|
-
*
|
|
2245
|
-
*
|
|
2263
|
+
* Finds the next available seed for creating a user stake PDA.
|
|
2264
|
+
* Scans from startSeed until an unused PDA is found.
|
|
2265
|
+
*
|
|
2266
|
+
* @param connection - Solana connection
|
|
2267
|
+
* @param programId - The stake pool program ID
|
|
2268
|
+
* @param userPubkey - User's wallet (used for PDA derivation)
|
|
2269
|
+
* @param startSeed - Starting seed to search from (default: 0)
|
|
2270
|
+
* @param maxSeed - Maximum seed to check before giving up (default: 1000)
|
|
2271
|
+
* @returns The next available seed
|
|
2272
|
+
* @throws Error if no available seed found within maxSeed
|
|
2273
|
+
*/
|
|
2274
|
+
async function findNextUserStakeSeed(connection, programId, userPubkey, startSeed = 0, maxSeed = 1000) {
|
|
2275
|
+
for (let seed = startSeed; seed < startSeed + maxSeed; seed++) {
|
|
2276
|
+
const pda = findUserStakeProgramAddress(programId, userPubkey, seed);
|
|
2277
|
+
const account = await connection.getAccountInfo(pda);
|
|
2278
|
+
if (!account) {
|
|
2279
|
+
return seed;
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2282
|
+
throw new Error(`No available user stake seed found between ${startSeed} and ${startSeed + maxSeed - 1}`);
|
|
2283
|
+
}
|
|
2284
|
+
/**
|
|
2285
|
+
* Withdraws stake from a stake pool using a Fogo session.
|
|
2286
|
+
*
|
|
2287
|
+
* The on-chain program creates stake account PDAs, so no pre-creation step is needed.
|
|
2288
|
+
* The paymaster payer provides rent for the stake account PDAs.
|
|
2289
|
+
*
|
|
2290
|
+
* @param connection - Solana connection
|
|
2291
|
+
* @param stakePoolAddress - The stake pool to withdraw from
|
|
2292
|
+
* @param signerOrSession - The session signer public key
|
|
2293
|
+
* @param userPubkey - User's wallet (used for PDA derivation and token ownership)
|
|
2294
|
+
* @param payer - Payer for stake account rent (paymaster payer in session context)
|
|
2295
|
+
* @param amount - Amount of pool tokens to withdraw
|
|
2296
|
+
* @param userStakeSeedStart - Starting seed for user stake PDA derivation (default: 0)
|
|
2297
|
+
* @param useReserve - Whether to withdraw from reserve (default: false)
|
|
2298
|
+
* @param voteAccountAddress - Optional specific validator to withdraw from
|
|
2299
|
+
* @param minimumLamportsOut - Minimum lamports to receive (slippage protection)
|
|
2300
|
+
* @param validatorComparator - Optional comparator for validator selection
|
|
2246
2301
|
*/
|
|
2247
|
-
async function withdrawStakeWithSession(connection, stakePoolAddress, signerOrSession, userPubkey, amount, useReserve = false, voteAccountAddress, minimumLamportsOut = 0,
|
|
2302
|
+
async function withdrawStakeWithSession(connection, stakePoolAddress, signerOrSession, userPubkey, payer, amount, userStakeSeedStart = 0, useReserve = false, voteAccountAddress, minimumLamportsOut = 0, validatorComparator) {
|
|
2248
2303
|
const stakePoolAccount = await getStakePoolAccount(connection, stakePoolAddress);
|
|
2249
2304
|
const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint);
|
|
2250
2305
|
const stakePool = stakePoolAccount.account.data;
|
|
@@ -2294,8 +2349,8 @@ async function withdrawStakeWithSession(connection, stakePoolAddress, signerOrSe
|
|
|
2294
2349
|
withdrawAccounts.push(...(await prepareWithdrawAccounts(connection, stakePool, stakePoolAddress, poolAmount, validatorComparator, poolTokenAccount.equals(stakePool.managerFeeAccount))));
|
|
2295
2350
|
}
|
|
2296
2351
|
const instructions = [];
|
|
2297
|
-
const signers = [];
|
|
2298
2352
|
const stakeAccountPubkeys = [];
|
|
2353
|
+
const userStakeSeeds = [];
|
|
2299
2354
|
// Max 5 accounts to prevent an error: "Transaction too large"
|
|
2300
2355
|
const maxWithdrawAccounts = 5;
|
|
2301
2356
|
let i = 0;
|
|
@@ -2303,41 +2358,36 @@ async function withdrawStakeWithSession(connection, stakePoolAddress, signerOrSe
|
|
|
2303
2358
|
if (i >= maxWithdrawAccounts) {
|
|
2304
2359
|
break;
|
|
2305
2360
|
}
|
|
2306
|
-
//
|
|
2307
|
-
const
|
|
2308
|
-
|
|
2309
|
-
stakeAccountPubkeys.push(
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
fromPubkey: payer !== null && payer !== void 0 ? payer : userPubkey,
|
|
2313
|
-
newAccountPubkey: stakeReceiver.publicKey,
|
|
2314
|
-
lamports: stakeAccountRentExemption,
|
|
2315
|
-
space: web3_js.StakeProgram.space,
|
|
2316
|
-
programId: web3_js.StakeProgram.programId,
|
|
2317
|
-
}));
|
|
2318
|
-
// Add the withdraw stake with session instruction
|
|
2361
|
+
// Derive the stake account PDA for this withdrawal
|
|
2362
|
+
const userStakeSeed = userStakeSeedStart + i;
|
|
2363
|
+
const stakeReceiverPubkey = findUserStakeProgramAddress(stakePoolProgramId, userPubkey, userStakeSeed);
|
|
2364
|
+
stakeAccountPubkeys.push(stakeReceiverPubkey);
|
|
2365
|
+
userStakeSeeds.push(userStakeSeed);
|
|
2366
|
+
// The on-chain program will create the stake account PDA
|
|
2319
2367
|
instructions.push(StakePoolInstruction.withdrawStakeWithSession({
|
|
2320
2368
|
programId: stakePoolProgramId,
|
|
2321
2369
|
stakePool: stakePoolAddress,
|
|
2322
2370
|
validatorList: stakePool.validatorList,
|
|
2323
2371
|
withdrawAuthority,
|
|
2324
2372
|
stakeToSplit: withdrawAccount.stakeAddress,
|
|
2325
|
-
stakeToReceive:
|
|
2373
|
+
stakeToReceive: stakeReceiverPubkey,
|
|
2326
2374
|
sessionSigner: signerOrSession,
|
|
2327
2375
|
burnFromPool: poolTokenAccount,
|
|
2328
2376
|
managerFeeAccount: stakePool.managerFeeAccount,
|
|
2329
2377
|
poolMint: stakePool.poolMint,
|
|
2330
2378
|
tokenProgramId: stakePool.tokenProgramId,
|
|
2331
2379
|
programSigner,
|
|
2380
|
+
payer,
|
|
2332
2381
|
poolTokensIn: withdrawAccount.poolAmount.toNumber(),
|
|
2333
|
-
minimumLamportsOut
|
|
2382
|
+
minimumLamportsOut,
|
|
2383
|
+
userStakeSeed,
|
|
2334
2384
|
}));
|
|
2335
2385
|
i++;
|
|
2336
2386
|
}
|
|
2337
2387
|
return {
|
|
2338
2388
|
instructions,
|
|
2339
|
-
signers,
|
|
2340
2389
|
stakeAccountPubkeys,
|
|
2390
|
+
userStakeSeeds,
|
|
2341
2391
|
};
|
|
2342
2392
|
}
|
|
2343
2393
|
async function addValidatorToPool(connection, stakePoolAddress, validatorVote, seed) {
|
|
@@ -2715,6 +2765,13 @@ exports.decreaseValidatorStake = decreaseValidatorStake;
|
|
|
2715
2765
|
exports.depositSol = depositSol;
|
|
2716
2766
|
exports.depositStake = depositStake;
|
|
2717
2767
|
exports.depositWsolWithSession = depositWsolWithSession;
|
|
2768
|
+
exports.findEphemeralStakeProgramAddress = findEphemeralStakeProgramAddress;
|
|
2769
|
+
exports.findNextUserStakeSeed = findNextUserStakeSeed;
|
|
2770
|
+
exports.findStakeProgramAddress = findStakeProgramAddress;
|
|
2771
|
+
exports.findTransientStakeProgramAddress = findTransientStakeProgramAddress;
|
|
2772
|
+
exports.findUserStakeProgramAddress = findUserStakeProgramAddress;
|
|
2773
|
+
exports.findWithdrawAuthorityProgramAddress = findWithdrawAuthorityProgramAddress;
|
|
2774
|
+
exports.findWsolTransientProgramAddress = findWsolTransientProgramAddress;
|
|
2718
2775
|
exports.getStakeAccount = getStakeAccount;
|
|
2719
2776
|
exports.getStakePoolAccount = getStakePoolAccount;
|
|
2720
2777
|
exports.getStakePoolAccounts = getStakePoolAccounts;
|