@ignitionfi/spl-stake-pool 1.1.23 → 1.1.25
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.browser.cjs.js +140 -18
- package/dist/index.browser.cjs.js.map +1 -1
- package/dist/index.browser.esm.js +140 -19
- package/dist/index.browser.esm.js.map +1 -1
- package/dist/index.cjs.js +140 -18
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +42 -6
- package/dist/index.esm.js +140 -19
- package/dist/index.esm.js.map +1 -1
- package/dist/index.iife.js +140 -18
- 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 +23 -3
- package/package.json +1 -1
- package/src/constants.ts +1 -3
- package/src/index.ts +124 -22
- package/src/instructions.ts +70 -4
- package/src/utils/stake.ts +5 -2
|
@@ -823,13 +823,16 @@ async function prepareWithdrawAccounts(connection, stakePool, stakePoolAddress,
|
|
|
823
823
|
continue;
|
|
824
824
|
}
|
|
825
825
|
const stakeAccountAddress = await findStakeProgramAddress(stakePoolProgramId, validator.voteAccountAddress, stakePoolAddress);
|
|
826
|
-
|
|
826
|
+
// For active stake accounts, subtract the minimum balance that must remain
|
|
827
|
+
// to allow for merges and maintain rent exemption
|
|
828
|
+
const availableActiveLamports = validator.activeStakeLamports.sub(minBalance);
|
|
829
|
+
if (availableActiveLamports.gt(new BN(0))) {
|
|
827
830
|
const isPreferred = (_a = stakePool === null || stakePool === void 0 ? void 0 : stakePool.preferredWithdrawValidatorVoteAddress) === null || _a === void 0 ? void 0 : _a.equals(validator.voteAccountAddress);
|
|
828
831
|
accounts.push({
|
|
829
832
|
type: isPreferred ? 'preferred' : 'active',
|
|
830
833
|
voteAddress: validator.voteAccountAddress,
|
|
831
834
|
stakeAddress: stakeAccountAddress,
|
|
832
|
-
lamports:
|
|
835
|
+
lamports: availableActiveLamports,
|
|
833
836
|
});
|
|
834
837
|
}
|
|
835
838
|
const transientStakeLamports = validator.transientStakeLamports.sub(minBalance);
|
|
@@ -1120,6 +1123,14 @@ const STAKE_POOL_INSTRUCTION_LAYOUTS = Object.freeze({
|
|
|
1120
1123
|
BufferLayout.ns64('userStakeSeed'),
|
|
1121
1124
|
]),
|
|
1122
1125
|
},
|
|
1126
|
+
WithdrawFromStakeAccountWithSession: {
|
|
1127
|
+
index: 30,
|
|
1128
|
+
layout: BufferLayout.struct([
|
|
1129
|
+
BufferLayout.u8('instruction'),
|
|
1130
|
+
BufferLayout.ns64('lamports'),
|
|
1131
|
+
BufferLayout.ns64('userStakeSeed'),
|
|
1132
|
+
]),
|
|
1133
|
+
},
|
|
1123
1134
|
});
|
|
1124
1135
|
/**
|
|
1125
1136
|
* Stake Pool Instruction class
|
|
@@ -1553,9 +1564,9 @@ class StakePoolInstruction {
|
|
|
1553
1564
|
}
|
|
1554
1565
|
/**
|
|
1555
1566
|
* Creates a transaction instruction to withdraw WSOL from a stake pool using a session.
|
|
1567
|
+
* Rent for ATA creation (if needed) is paid from the withdrawal amount.
|
|
1556
1568
|
*/
|
|
1557
1569
|
static withdrawWsolWithSession(params) {
|
|
1558
|
-
var _a;
|
|
1559
1570
|
const type = STAKE_POOL_INSTRUCTION_LAYOUTS.WithdrawWsolWithSession;
|
|
1560
1571
|
const data = encodeData(type, {
|
|
1561
1572
|
poolTokensIn: params.poolTokensIn,
|
|
@@ -1576,7 +1587,6 @@ class StakePoolInstruction {
|
|
|
1576
1587
|
{ pubkey: params.tokenProgramId, isSigner: false, isWritable: false },
|
|
1577
1588
|
{ pubkey: params.wsolMint, isSigner: false, isWritable: false },
|
|
1578
1589
|
{ pubkey: params.programSigner, isSigner: false, isWritable: true },
|
|
1579
|
-
{ pubkey: (_a = params.payer) !== null && _a !== void 0 ? _a : params.userTransferAuthority, isSigner: true, isWritable: true },
|
|
1580
1590
|
{ pubkey: params.userWallet, isSigner: false, isWritable: false },
|
|
1581
1591
|
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
|
|
1582
1592
|
];
|
|
@@ -1597,6 +1607,7 @@ class StakePoolInstruction {
|
|
|
1597
1607
|
}
|
|
1598
1608
|
/**
|
|
1599
1609
|
* Creates a transaction instruction to withdraw stake from a stake pool using a Fogo session.
|
|
1610
|
+
* The stake account is created as a PDA and rent is paid by the payer (typically paymaster).
|
|
1600
1611
|
*/
|
|
1601
1612
|
static withdrawStakeWithSession(params) {
|
|
1602
1613
|
const type = STAKE_POOL_INSTRUCTION_LAYOUTS.WithdrawStakeWithSession;
|
|
@@ -1620,8 +1631,8 @@ class StakePoolInstruction {
|
|
|
1620
1631
|
{ pubkey: params.tokenProgramId, isSigner: false, isWritable: false },
|
|
1621
1632
|
{ pubkey: StakeProgram.programId, isSigner: false, isWritable: false },
|
|
1622
1633
|
{ pubkey: params.programSigner, isSigner: false, isWritable: false },
|
|
1623
|
-
{ pubkey: params.payer, isSigner: true, isWritable: true },
|
|
1624
1634
|
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
|
|
1635
|
+
{ pubkey: params.payer, isSigner: true, isWritable: true },
|
|
1625
1636
|
];
|
|
1626
1637
|
return new TransactionInstruction({
|
|
1627
1638
|
programId: params.programId,
|
|
@@ -1629,6 +1640,43 @@ class StakePoolInstruction {
|
|
|
1629
1640
|
data,
|
|
1630
1641
|
});
|
|
1631
1642
|
}
|
|
1643
|
+
/**
|
|
1644
|
+
* Creates a transaction instruction to withdraw SOL from a deactivated user stake account using a Fogo session.
|
|
1645
|
+
* The stake account must be fully deactivated (inactive).
|
|
1646
|
+
* User receives full stake balance (payer's rent contribution compensates for reduced split).
|
|
1647
|
+
*/
|
|
1648
|
+
static withdrawFromStakeAccountWithSession(params) {
|
|
1649
|
+
// For u64::MAX (full withdrawal), we need to manually encode since buffer-layout doesn't handle bigint well
|
|
1650
|
+
const U64_MAX = BigInt('18446744073709551615');
|
|
1651
|
+
const isFullWithdrawal = params.lamports >= U64_MAX;
|
|
1652
|
+
// Manually create the instruction data buffer using Uint8Array for browser compatibility
|
|
1653
|
+
// Layout: u8 instruction (1) + u64 lamports (8) + u64 userStakeSeed (8) = 17 bytes
|
|
1654
|
+
const data = new Uint8Array(17);
|
|
1655
|
+
data[0] = 30; // instruction discriminator (WithdrawFromStakeAccountWithSession = 30)
|
|
1656
|
+
// Write lamports as u64 little-endian (bytes 1-8)
|
|
1657
|
+
const lamportsBigInt = isFullWithdrawal ? U64_MAX : params.lamports;
|
|
1658
|
+
for (let i = 0; i < 8; i++) {
|
|
1659
|
+
data[1 + i] = Number((lamportsBigInt >> BigInt(i * 8)) & BigInt(0xff));
|
|
1660
|
+
}
|
|
1661
|
+
// Write userStakeSeed as u64 little-endian (bytes 9-16)
|
|
1662
|
+
const seedBigInt = BigInt(params.userStakeSeed);
|
|
1663
|
+
for (let i = 0; i < 8; i++) {
|
|
1664
|
+
data[9 + i] = Number((seedBigInt >> BigInt(i * 8)) & BigInt(0xff));
|
|
1665
|
+
}
|
|
1666
|
+
// Account order matches Rust: stake_account, recipient, clock, stake_history, session_signer
|
|
1667
|
+
const keys = [
|
|
1668
|
+
{ pubkey: params.userStakeAccount, isSigner: false, isWritable: true },
|
|
1669
|
+
{ pubkey: params.userWallet, isSigner: false, isWritable: true },
|
|
1670
|
+
{ pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
|
|
1671
|
+
{ pubkey: SYSVAR_STAKE_HISTORY_PUBKEY, isSigner: false, isWritable: false },
|
|
1672
|
+
{ pubkey: params.sessionSigner, isSigner: true, isWritable: false },
|
|
1673
|
+
];
|
|
1674
|
+
return new TransactionInstruction({
|
|
1675
|
+
programId: params.programId,
|
|
1676
|
+
keys,
|
|
1677
|
+
data: Buffer.from(data),
|
|
1678
|
+
});
|
|
1679
|
+
}
|
|
1632
1680
|
/**
|
|
1633
1681
|
* Creates an instruction to create metadata
|
|
1634
1682
|
* using the mpl token metadata program for the pool token
|
|
@@ -1892,14 +1940,21 @@ async function depositStake(connection, stakePoolAddress, authorizedPubkey, vali
|
|
|
1892
1940
|
/**
|
|
1893
1941
|
* Creates instructions required to deposit sol to stake pool.
|
|
1894
1942
|
*/
|
|
1895
|
-
async function depositWsolWithSession(connection, stakePoolAddress, signerOrSession, userPubkey, lamports, minimumPoolTokensOut = 0, destinationTokenAccount, referrerTokenAccount, depositAuthority, payer
|
|
1943
|
+
async function depositWsolWithSession(connection, stakePoolAddress, signerOrSession, userPubkey, lamports, minimumPoolTokensOut = 0, destinationTokenAccount, referrerTokenAccount, depositAuthority, payer,
|
|
1944
|
+
/**
|
|
1945
|
+
* Skip WSOL balance validation. Set to true when adding wrap instructions
|
|
1946
|
+
* in the same transaction that will fund the WSOL account before deposit.
|
|
1947
|
+
*/
|
|
1948
|
+
skipBalanceCheck = false) {
|
|
1896
1949
|
const wsolTokenAccount = getAssociatedTokenAddressSync(NATIVE_MINT, userPubkey);
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1950
|
+
if (!skipBalanceCheck) {
|
|
1951
|
+
const tokenAccountInfo = await connection.getTokenAccountBalance(wsolTokenAccount, 'confirmed');
|
|
1952
|
+
const wsolBalance = tokenAccountInfo
|
|
1953
|
+
? parseInt(tokenAccountInfo.value.amount)
|
|
1954
|
+
: 0;
|
|
1955
|
+
if (wsolBalance < lamports) {
|
|
1956
|
+
throw new Error(`Not enough WSOL to deposit into pool. Maximum deposit amount is ${lamportsToSol(wsolBalance)} WSOL.`);
|
|
1957
|
+
}
|
|
1903
1958
|
}
|
|
1904
1959
|
const stakePoolAccount = await getStakePoolAccount(connection, stakePoolAddress);
|
|
1905
1960
|
const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint);
|
|
@@ -2195,8 +2250,9 @@ async function withdrawSol(connection, stakePoolAddress, tokenOwner, solReceiver
|
|
|
2195
2250
|
}
|
|
2196
2251
|
/**
|
|
2197
2252
|
* Creates instructions required to withdraw wSOL from a stake pool.
|
|
2253
|
+
* Rent for ATA creation (if needed) is paid from the withdrawal amount.
|
|
2198
2254
|
*/
|
|
2199
|
-
async function withdrawWsolWithSession(connection, stakePoolAddress, signerOrSession, userPubkey, amount, minimumLamportsOut = 0, solWithdrawAuthority
|
|
2255
|
+
async function withdrawWsolWithSession(connection, stakePoolAddress, signerOrSession, userPubkey, amount, minimumLamportsOut = 0, solWithdrawAuthority) {
|
|
2200
2256
|
const stakePoolAccount = await getStakePoolAccount(connection, stakePoolAddress);
|
|
2201
2257
|
const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint);
|
|
2202
2258
|
const stakePool = stakePoolAccount.account.data;
|
|
@@ -2229,7 +2285,6 @@ async function withdrawWsolWithSession(connection, stakePoolAddress, signerOrSes
|
|
|
2229
2285
|
wsolMint: NATIVE_MINT,
|
|
2230
2286
|
programSigner,
|
|
2231
2287
|
userWallet: userPubkey,
|
|
2232
|
-
payer,
|
|
2233
2288
|
poolTokensIn: poolTokens,
|
|
2234
2289
|
minimumLamportsOut,
|
|
2235
2290
|
}));
|
|
@@ -2260,17 +2315,83 @@ async function findNextUserStakeSeed(connection, programId, userPubkey, startSee
|
|
|
2260
2315
|
}
|
|
2261
2316
|
throw new Error(`No available user stake seed found between ${startSeed} and ${startSeed + maxSeed - 1}`);
|
|
2262
2317
|
}
|
|
2318
|
+
/**
|
|
2319
|
+
* Fetches all user stake accounts created via WithdrawStakeWithSession.
|
|
2320
|
+
* These are PDAs derived from [b"user_stake", user_wallet, seed].
|
|
2321
|
+
*
|
|
2322
|
+
* @param connection - Solana connection
|
|
2323
|
+
* @param programId - The stake pool program ID
|
|
2324
|
+
* @param userPubkey - User's wallet address
|
|
2325
|
+
* @param maxSeed - Maximum seed to check (default: 100)
|
|
2326
|
+
* @returns Array of user stake accounts with their details
|
|
2327
|
+
*/
|
|
2328
|
+
async function getUserStakeAccounts(connection, programId, userPubkey, maxSeed = 100) {
|
|
2329
|
+
var _c, _d;
|
|
2330
|
+
const stakeAccounts = [];
|
|
2331
|
+
const currentEpoch = (await connection.getEpochInfo()).epoch;
|
|
2332
|
+
for (let seed = 0; seed < maxSeed; seed++) {
|
|
2333
|
+
const pda = findUserStakeProgramAddress(programId, userPubkey, seed);
|
|
2334
|
+
const accountInfo = await connection.getAccountInfo(pda);
|
|
2335
|
+
if (!accountInfo) {
|
|
2336
|
+
continue; // Skip empty slots, there might be gaps
|
|
2337
|
+
}
|
|
2338
|
+
// Check if owned by stake program
|
|
2339
|
+
if (!accountInfo.owner.equals(StakeProgram.programId)) {
|
|
2340
|
+
continue;
|
|
2341
|
+
}
|
|
2342
|
+
// Parse stake account data
|
|
2343
|
+
const stakeAccount = {
|
|
2344
|
+
pubkey: pda,
|
|
2345
|
+
seed,
|
|
2346
|
+
lamports: accountInfo.lamports,
|
|
2347
|
+
state: 'inactive',
|
|
2348
|
+
};
|
|
2349
|
+
try {
|
|
2350
|
+
// Parse the stake account to get delegation info
|
|
2351
|
+
const parsedAccount = await connection.getParsedAccountInfo(pda);
|
|
2352
|
+
if (parsedAccount.value && 'parsed' in parsedAccount.value.data) {
|
|
2353
|
+
const parsed = parsedAccount.value.data.parsed;
|
|
2354
|
+
if (parsed.type === 'delegated' && ((_d = (_c = parsed.info) === null || _c === void 0 ? void 0 : _c.stake) === null || _d === void 0 ? void 0 : _d.delegation)) {
|
|
2355
|
+
const delegation = parsed.info.stake.delegation;
|
|
2356
|
+
stakeAccount.voter = new PublicKey(delegation.voter);
|
|
2357
|
+
stakeAccount.activationEpoch = Number(delegation.activationEpoch);
|
|
2358
|
+
stakeAccount.deactivationEpoch = Number(delegation.deactivationEpoch);
|
|
2359
|
+
// Determine state based on epochs
|
|
2360
|
+
const activationEpoch = stakeAccount.activationEpoch;
|
|
2361
|
+
const deactivationEpoch = stakeAccount.deactivationEpoch;
|
|
2362
|
+
if (deactivationEpoch !== undefined && deactivationEpoch < Number.MAX_SAFE_INTEGER && deactivationEpoch <= currentEpoch) {
|
|
2363
|
+
stakeAccount.state = 'inactive';
|
|
2364
|
+
}
|
|
2365
|
+
else if (deactivationEpoch !== undefined && deactivationEpoch < Number.MAX_SAFE_INTEGER) {
|
|
2366
|
+
stakeAccount.state = 'deactivating';
|
|
2367
|
+
}
|
|
2368
|
+
else if (activationEpoch !== undefined && activationEpoch <= currentEpoch) {
|
|
2369
|
+
stakeAccount.state = 'active';
|
|
2370
|
+
}
|
|
2371
|
+
else {
|
|
2372
|
+
stakeAccount.state = 'activating';
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
catch {
|
|
2378
|
+
// If parsing fails, keep default 'inactive' state
|
|
2379
|
+
}
|
|
2380
|
+
stakeAccounts.push(stakeAccount);
|
|
2381
|
+
}
|
|
2382
|
+
return stakeAccounts;
|
|
2383
|
+
}
|
|
2263
2384
|
/**
|
|
2264
2385
|
* Withdraws stake from a stake pool using a Fogo session.
|
|
2265
2386
|
*
|
|
2266
|
-
* The on-chain program creates stake account PDAs
|
|
2267
|
-
*
|
|
2387
|
+
* The on-chain program creates stake account PDAs. The rent for these accounts
|
|
2388
|
+
* is paid by the payer (typically the paymaster), not deducted from the user's withdrawal.
|
|
2268
2389
|
*
|
|
2269
2390
|
* @param connection - Solana connection
|
|
2270
2391
|
* @param stakePoolAddress - The stake pool to withdraw from
|
|
2271
2392
|
* @param signerOrSession - The session signer public key
|
|
2272
2393
|
* @param userPubkey - User's wallet (used for PDA derivation and token ownership)
|
|
2273
|
-
* @param payer - Payer for stake account rent (paymaster
|
|
2394
|
+
* @param payer - Payer for stake account rent (typically paymaster)
|
|
2274
2395
|
* @param amount - Amount of pool tokens to withdraw
|
|
2275
2396
|
* @param userStakeSeedStart - Starting seed for user stake PDA derivation (default: 0)
|
|
2276
2397
|
* @param useReserve - Whether to withdraw from reserve (default: false)
|
|
@@ -2342,7 +2463,7 @@ async function withdrawStakeWithSession(connection, stakePoolAddress, signerOrSe
|
|
|
2342
2463
|
const stakeReceiverPubkey = findUserStakeProgramAddress(stakePoolProgramId, userPubkey, userStakeSeed);
|
|
2343
2464
|
stakeAccountPubkeys.push(stakeReceiverPubkey);
|
|
2344
2465
|
userStakeSeeds.push(userStakeSeed);
|
|
2345
|
-
// The on-chain program
|
|
2466
|
+
// The on-chain program creates the stake account PDA and rent is paid by payer.
|
|
2346
2467
|
instructions.push(StakePoolInstruction.withdrawStakeWithSession({
|
|
2347
2468
|
programId: stakePoolProgramId,
|
|
2348
2469
|
stakePool: stakePoolAddress,
|
|
@@ -2731,5 +2852,5 @@ async function updatePoolTokenMetadata(connection, stakePoolAddress, name, symbo
|
|
|
2731
2852
|
};
|
|
2732
2853
|
}
|
|
2733
2854
|
|
|
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 };
|
|
2855
|
+
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, getUserStakeAccounts, increaseValidatorStake, removeValidatorFromPool, stakePoolInfo, tokenMetadataLayout, updatePoolTokenMetadata, updateStakePool, withdrawSol, withdrawStake, withdrawStakeWithSession, withdrawWsolWithSession };
|
|
2735
2856
|
//# sourceMappingURL=index.browser.esm.js.map
|