@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
|
@@ -844,13 +844,16 @@ async function prepareWithdrawAccounts(connection, stakePool, stakePoolAddress,
|
|
|
844
844
|
continue;
|
|
845
845
|
}
|
|
846
846
|
const stakeAccountAddress = await findStakeProgramAddress(stakePoolProgramId, validator.voteAccountAddress, stakePoolAddress);
|
|
847
|
-
|
|
847
|
+
// For active stake accounts, subtract the minimum balance that must remain
|
|
848
|
+
// to allow for merges and maintain rent exemption
|
|
849
|
+
const availableActiveLamports = validator.activeStakeLamports.sub(minBalance);
|
|
850
|
+
if (availableActiveLamports.gt(new BN(0))) {
|
|
848
851
|
const isPreferred = (_a = stakePool === null || stakePool === void 0 ? void 0 : stakePool.preferredWithdrawValidatorVoteAddress) === null || _a === void 0 ? void 0 : _a.equals(validator.voteAccountAddress);
|
|
849
852
|
accounts.push({
|
|
850
853
|
type: isPreferred ? 'preferred' : 'active',
|
|
851
854
|
voteAddress: validator.voteAccountAddress,
|
|
852
855
|
stakeAddress: stakeAccountAddress,
|
|
853
|
-
lamports:
|
|
856
|
+
lamports: availableActiveLamports,
|
|
854
857
|
});
|
|
855
858
|
}
|
|
856
859
|
const transientStakeLamports = validator.transientStakeLamports.sub(minBalance);
|
|
@@ -1141,6 +1144,14 @@ const STAKE_POOL_INSTRUCTION_LAYOUTS = Object.freeze({
|
|
|
1141
1144
|
BufferLayout__namespace.ns64('userStakeSeed'),
|
|
1142
1145
|
]),
|
|
1143
1146
|
},
|
|
1147
|
+
WithdrawFromStakeAccountWithSession: {
|
|
1148
|
+
index: 30,
|
|
1149
|
+
layout: BufferLayout__namespace.struct([
|
|
1150
|
+
BufferLayout__namespace.u8('instruction'),
|
|
1151
|
+
BufferLayout__namespace.ns64('lamports'),
|
|
1152
|
+
BufferLayout__namespace.ns64('userStakeSeed'),
|
|
1153
|
+
]),
|
|
1154
|
+
},
|
|
1144
1155
|
});
|
|
1145
1156
|
/**
|
|
1146
1157
|
* Stake Pool Instruction class
|
|
@@ -1574,9 +1585,9 @@ class StakePoolInstruction {
|
|
|
1574
1585
|
}
|
|
1575
1586
|
/**
|
|
1576
1587
|
* Creates a transaction instruction to withdraw WSOL from a stake pool using a session.
|
|
1588
|
+
* Rent for ATA creation (if needed) is paid from the withdrawal amount.
|
|
1577
1589
|
*/
|
|
1578
1590
|
static withdrawWsolWithSession(params) {
|
|
1579
|
-
var _a;
|
|
1580
1591
|
const type = STAKE_POOL_INSTRUCTION_LAYOUTS.WithdrawWsolWithSession;
|
|
1581
1592
|
const data = encodeData(type, {
|
|
1582
1593
|
poolTokensIn: params.poolTokensIn,
|
|
@@ -1597,7 +1608,6 @@ class StakePoolInstruction {
|
|
|
1597
1608
|
{ pubkey: params.tokenProgramId, isSigner: false, isWritable: false },
|
|
1598
1609
|
{ pubkey: params.wsolMint, isSigner: false, isWritable: false },
|
|
1599
1610
|
{ pubkey: params.programSigner, isSigner: false, isWritable: true },
|
|
1600
|
-
{ pubkey: (_a = params.payer) !== null && _a !== void 0 ? _a : params.userTransferAuthority, isSigner: true, isWritable: true },
|
|
1601
1611
|
{ pubkey: params.userWallet, isSigner: false, isWritable: false },
|
|
1602
1612
|
{ pubkey: web3_js.SystemProgram.programId, isSigner: false, isWritable: false },
|
|
1603
1613
|
];
|
|
@@ -1618,6 +1628,7 @@ class StakePoolInstruction {
|
|
|
1618
1628
|
}
|
|
1619
1629
|
/**
|
|
1620
1630
|
* Creates a transaction instruction to withdraw stake from a stake pool using a Fogo session.
|
|
1631
|
+
* The stake account is created as a PDA and rent is paid by the payer (typically paymaster).
|
|
1621
1632
|
*/
|
|
1622
1633
|
static withdrawStakeWithSession(params) {
|
|
1623
1634
|
const type = STAKE_POOL_INSTRUCTION_LAYOUTS.WithdrawStakeWithSession;
|
|
@@ -1641,8 +1652,8 @@ class StakePoolInstruction {
|
|
|
1641
1652
|
{ pubkey: params.tokenProgramId, isSigner: false, isWritable: false },
|
|
1642
1653
|
{ pubkey: web3_js.StakeProgram.programId, isSigner: false, isWritable: false },
|
|
1643
1654
|
{ pubkey: params.programSigner, isSigner: false, isWritable: false },
|
|
1644
|
-
{ pubkey: params.payer, isSigner: true, isWritable: true },
|
|
1645
1655
|
{ pubkey: web3_js.SystemProgram.programId, isSigner: false, isWritable: false },
|
|
1656
|
+
{ pubkey: params.payer, isSigner: true, isWritable: true },
|
|
1646
1657
|
];
|
|
1647
1658
|
return new web3_js.TransactionInstruction({
|
|
1648
1659
|
programId: params.programId,
|
|
@@ -1650,6 +1661,43 @@ class StakePoolInstruction {
|
|
|
1650
1661
|
data,
|
|
1651
1662
|
});
|
|
1652
1663
|
}
|
|
1664
|
+
/**
|
|
1665
|
+
* Creates a transaction instruction to withdraw SOL from a deactivated user stake account using a Fogo session.
|
|
1666
|
+
* The stake account must be fully deactivated (inactive).
|
|
1667
|
+
* User receives full stake balance (payer's rent contribution compensates for reduced split).
|
|
1668
|
+
*/
|
|
1669
|
+
static withdrawFromStakeAccountWithSession(params) {
|
|
1670
|
+
// For u64::MAX (full withdrawal), we need to manually encode since buffer-layout doesn't handle bigint well
|
|
1671
|
+
const U64_MAX = BigInt('18446744073709551615');
|
|
1672
|
+
const isFullWithdrawal = params.lamports >= U64_MAX;
|
|
1673
|
+
// Manually create the instruction data buffer using Uint8Array for browser compatibility
|
|
1674
|
+
// Layout: u8 instruction (1) + u64 lamports (8) + u64 userStakeSeed (8) = 17 bytes
|
|
1675
|
+
const data = new Uint8Array(17);
|
|
1676
|
+
data[0] = 30; // instruction discriminator (WithdrawFromStakeAccountWithSession = 30)
|
|
1677
|
+
// Write lamports as u64 little-endian (bytes 1-8)
|
|
1678
|
+
const lamportsBigInt = isFullWithdrawal ? U64_MAX : params.lamports;
|
|
1679
|
+
for (let i = 0; i < 8; i++) {
|
|
1680
|
+
data[1 + i] = Number((lamportsBigInt >> BigInt(i * 8)) & BigInt(0xff));
|
|
1681
|
+
}
|
|
1682
|
+
// Write userStakeSeed as u64 little-endian (bytes 9-16)
|
|
1683
|
+
const seedBigInt = BigInt(params.userStakeSeed);
|
|
1684
|
+
for (let i = 0; i < 8; i++) {
|
|
1685
|
+
data[9 + i] = Number((seedBigInt >> BigInt(i * 8)) & BigInt(0xff));
|
|
1686
|
+
}
|
|
1687
|
+
// Account order matches Rust: stake_account, recipient, clock, stake_history, session_signer
|
|
1688
|
+
const keys = [
|
|
1689
|
+
{ pubkey: params.userStakeAccount, isSigner: false, isWritable: true },
|
|
1690
|
+
{ pubkey: params.userWallet, isSigner: false, isWritable: true },
|
|
1691
|
+
{ pubkey: web3_js.SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
|
|
1692
|
+
{ pubkey: web3_js.SYSVAR_STAKE_HISTORY_PUBKEY, isSigner: false, isWritable: false },
|
|
1693
|
+
{ pubkey: params.sessionSigner, isSigner: true, isWritable: false },
|
|
1694
|
+
];
|
|
1695
|
+
return new web3_js.TransactionInstruction({
|
|
1696
|
+
programId: params.programId,
|
|
1697
|
+
keys,
|
|
1698
|
+
data: Buffer.from(data),
|
|
1699
|
+
});
|
|
1700
|
+
}
|
|
1653
1701
|
/**
|
|
1654
1702
|
* Creates an instruction to create metadata
|
|
1655
1703
|
* using the mpl token metadata program for the pool token
|
|
@@ -1913,14 +1961,21 @@ async function depositStake(connection, stakePoolAddress, authorizedPubkey, vali
|
|
|
1913
1961
|
/**
|
|
1914
1962
|
* Creates instructions required to deposit sol to stake pool.
|
|
1915
1963
|
*/
|
|
1916
|
-
async function depositWsolWithSession(connection, stakePoolAddress, signerOrSession, userPubkey, lamports, minimumPoolTokensOut = 0, destinationTokenAccount, referrerTokenAccount, depositAuthority, payer
|
|
1964
|
+
async function depositWsolWithSession(connection, stakePoolAddress, signerOrSession, userPubkey, lamports, minimumPoolTokensOut = 0, destinationTokenAccount, referrerTokenAccount, depositAuthority, payer,
|
|
1965
|
+
/**
|
|
1966
|
+
* Skip WSOL balance validation. Set to true when adding wrap instructions
|
|
1967
|
+
* in the same transaction that will fund the WSOL account before deposit.
|
|
1968
|
+
*/
|
|
1969
|
+
skipBalanceCheck = false) {
|
|
1917
1970
|
const wsolTokenAccount = splToken.getAssociatedTokenAddressSync(splToken.NATIVE_MINT, userPubkey);
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1971
|
+
if (!skipBalanceCheck) {
|
|
1972
|
+
const tokenAccountInfo = await connection.getTokenAccountBalance(wsolTokenAccount, 'confirmed');
|
|
1973
|
+
const wsolBalance = tokenAccountInfo
|
|
1974
|
+
? parseInt(tokenAccountInfo.value.amount)
|
|
1975
|
+
: 0;
|
|
1976
|
+
if (wsolBalance < lamports) {
|
|
1977
|
+
throw new Error(`Not enough WSOL to deposit into pool. Maximum deposit amount is ${lamportsToSol(wsolBalance)} WSOL.`);
|
|
1978
|
+
}
|
|
1924
1979
|
}
|
|
1925
1980
|
const stakePoolAccount = await getStakePoolAccount(connection, stakePoolAddress);
|
|
1926
1981
|
const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint);
|
|
@@ -2216,8 +2271,9 @@ async function withdrawSol(connection, stakePoolAddress, tokenOwner, solReceiver
|
|
|
2216
2271
|
}
|
|
2217
2272
|
/**
|
|
2218
2273
|
* Creates instructions required to withdraw wSOL from a stake pool.
|
|
2274
|
+
* Rent for ATA creation (if needed) is paid from the withdrawal amount.
|
|
2219
2275
|
*/
|
|
2220
|
-
async function withdrawWsolWithSession(connection, stakePoolAddress, signerOrSession, userPubkey, amount, minimumLamportsOut = 0, solWithdrawAuthority
|
|
2276
|
+
async function withdrawWsolWithSession(connection, stakePoolAddress, signerOrSession, userPubkey, amount, minimumLamportsOut = 0, solWithdrawAuthority) {
|
|
2221
2277
|
const stakePoolAccount = await getStakePoolAccount(connection, stakePoolAddress);
|
|
2222
2278
|
const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint);
|
|
2223
2279
|
const stakePool = stakePoolAccount.account.data;
|
|
@@ -2250,7 +2306,6 @@ async function withdrawWsolWithSession(connection, stakePoolAddress, signerOrSes
|
|
|
2250
2306
|
wsolMint: splToken.NATIVE_MINT,
|
|
2251
2307
|
programSigner,
|
|
2252
2308
|
userWallet: userPubkey,
|
|
2253
|
-
payer,
|
|
2254
2309
|
poolTokensIn: poolTokens,
|
|
2255
2310
|
minimumLamportsOut,
|
|
2256
2311
|
}));
|
|
@@ -2281,17 +2336,83 @@ async function findNextUserStakeSeed(connection, programId, userPubkey, startSee
|
|
|
2281
2336
|
}
|
|
2282
2337
|
throw new Error(`No available user stake seed found between ${startSeed} and ${startSeed + maxSeed - 1}`);
|
|
2283
2338
|
}
|
|
2339
|
+
/**
|
|
2340
|
+
* Fetches all user stake accounts created via WithdrawStakeWithSession.
|
|
2341
|
+
* These are PDAs derived from [b"user_stake", user_wallet, seed].
|
|
2342
|
+
*
|
|
2343
|
+
* @param connection - Solana connection
|
|
2344
|
+
* @param programId - The stake pool program ID
|
|
2345
|
+
* @param userPubkey - User's wallet address
|
|
2346
|
+
* @param maxSeed - Maximum seed to check (default: 100)
|
|
2347
|
+
* @returns Array of user stake accounts with their details
|
|
2348
|
+
*/
|
|
2349
|
+
async function getUserStakeAccounts(connection, programId, userPubkey, maxSeed = 100) {
|
|
2350
|
+
var _c, _d;
|
|
2351
|
+
const stakeAccounts = [];
|
|
2352
|
+
const currentEpoch = (await connection.getEpochInfo()).epoch;
|
|
2353
|
+
for (let seed = 0; seed < maxSeed; seed++) {
|
|
2354
|
+
const pda = findUserStakeProgramAddress(programId, userPubkey, seed);
|
|
2355
|
+
const accountInfo = await connection.getAccountInfo(pda);
|
|
2356
|
+
if (!accountInfo) {
|
|
2357
|
+
continue; // Skip empty slots, there might be gaps
|
|
2358
|
+
}
|
|
2359
|
+
// Check if owned by stake program
|
|
2360
|
+
if (!accountInfo.owner.equals(web3_js.StakeProgram.programId)) {
|
|
2361
|
+
continue;
|
|
2362
|
+
}
|
|
2363
|
+
// Parse stake account data
|
|
2364
|
+
const stakeAccount = {
|
|
2365
|
+
pubkey: pda,
|
|
2366
|
+
seed,
|
|
2367
|
+
lamports: accountInfo.lamports,
|
|
2368
|
+
state: 'inactive',
|
|
2369
|
+
};
|
|
2370
|
+
try {
|
|
2371
|
+
// Parse the stake account to get delegation info
|
|
2372
|
+
const parsedAccount = await connection.getParsedAccountInfo(pda);
|
|
2373
|
+
if (parsedAccount.value && 'parsed' in parsedAccount.value.data) {
|
|
2374
|
+
const parsed = parsedAccount.value.data.parsed;
|
|
2375
|
+
if (parsed.type === 'delegated' && ((_d = (_c = parsed.info) === null || _c === void 0 ? void 0 : _c.stake) === null || _d === void 0 ? void 0 : _d.delegation)) {
|
|
2376
|
+
const delegation = parsed.info.stake.delegation;
|
|
2377
|
+
stakeAccount.voter = new web3_js.PublicKey(delegation.voter);
|
|
2378
|
+
stakeAccount.activationEpoch = Number(delegation.activationEpoch);
|
|
2379
|
+
stakeAccount.deactivationEpoch = Number(delegation.deactivationEpoch);
|
|
2380
|
+
// Determine state based on epochs
|
|
2381
|
+
const activationEpoch = stakeAccount.activationEpoch;
|
|
2382
|
+
const deactivationEpoch = stakeAccount.deactivationEpoch;
|
|
2383
|
+
if (deactivationEpoch !== undefined && deactivationEpoch < Number.MAX_SAFE_INTEGER && deactivationEpoch <= currentEpoch) {
|
|
2384
|
+
stakeAccount.state = 'inactive';
|
|
2385
|
+
}
|
|
2386
|
+
else if (deactivationEpoch !== undefined && deactivationEpoch < Number.MAX_SAFE_INTEGER) {
|
|
2387
|
+
stakeAccount.state = 'deactivating';
|
|
2388
|
+
}
|
|
2389
|
+
else if (activationEpoch !== undefined && activationEpoch <= currentEpoch) {
|
|
2390
|
+
stakeAccount.state = 'active';
|
|
2391
|
+
}
|
|
2392
|
+
else {
|
|
2393
|
+
stakeAccount.state = 'activating';
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
}
|
|
2398
|
+
catch {
|
|
2399
|
+
// If parsing fails, keep default 'inactive' state
|
|
2400
|
+
}
|
|
2401
|
+
stakeAccounts.push(stakeAccount);
|
|
2402
|
+
}
|
|
2403
|
+
return stakeAccounts;
|
|
2404
|
+
}
|
|
2284
2405
|
/**
|
|
2285
2406
|
* Withdraws stake from a stake pool using a Fogo session.
|
|
2286
2407
|
*
|
|
2287
|
-
* The on-chain program creates stake account PDAs
|
|
2288
|
-
*
|
|
2408
|
+
* The on-chain program creates stake account PDAs. The rent for these accounts
|
|
2409
|
+
* is paid by the payer (typically the paymaster), not deducted from the user's withdrawal.
|
|
2289
2410
|
*
|
|
2290
2411
|
* @param connection - Solana connection
|
|
2291
2412
|
* @param stakePoolAddress - The stake pool to withdraw from
|
|
2292
2413
|
* @param signerOrSession - The session signer public key
|
|
2293
2414
|
* @param userPubkey - User's wallet (used for PDA derivation and token ownership)
|
|
2294
|
-
* @param payer - Payer for stake account rent (paymaster
|
|
2415
|
+
* @param payer - Payer for stake account rent (typically paymaster)
|
|
2295
2416
|
* @param amount - Amount of pool tokens to withdraw
|
|
2296
2417
|
* @param userStakeSeedStart - Starting seed for user stake PDA derivation (default: 0)
|
|
2297
2418
|
* @param useReserve - Whether to withdraw from reserve (default: false)
|
|
@@ -2363,7 +2484,7 @@ async function withdrawStakeWithSession(connection, stakePoolAddress, signerOrSe
|
|
|
2363
2484
|
const stakeReceiverPubkey = findUserStakeProgramAddress(stakePoolProgramId, userPubkey, userStakeSeed);
|
|
2364
2485
|
stakeAccountPubkeys.push(stakeReceiverPubkey);
|
|
2365
2486
|
userStakeSeeds.push(userStakeSeed);
|
|
2366
|
-
// The on-chain program
|
|
2487
|
+
// The on-chain program creates the stake account PDA and rent is paid by payer.
|
|
2367
2488
|
instructions.push(StakePoolInstruction.withdrawStakeWithSession({
|
|
2368
2489
|
programId: stakePoolProgramId,
|
|
2369
2490
|
stakePool: stakePoolAddress,
|
|
@@ -2776,6 +2897,7 @@ exports.getStakeAccount = getStakeAccount;
|
|
|
2776
2897
|
exports.getStakePoolAccount = getStakePoolAccount;
|
|
2777
2898
|
exports.getStakePoolAccounts = getStakePoolAccounts;
|
|
2778
2899
|
exports.getStakePoolProgramId = getStakePoolProgramId;
|
|
2900
|
+
exports.getUserStakeAccounts = getUserStakeAccounts;
|
|
2779
2901
|
exports.increaseValidatorStake = increaseValidatorStake;
|
|
2780
2902
|
exports.removeValidatorFromPool = removeValidatorFromPool;
|
|
2781
2903
|
exports.stakePoolInfo = stakePoolInfo;
|