@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.browser.cjs.js +153 -3
- package/dist/index.browser.cjs.js.map +1 -1
- package/dist/index.browser.esm.js +153 -4
- package/dist/index.browser.esm.js.map +1 -1
- package/dist/index.cjs.js +153 -3
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.esm.js +153 -4
- package/dist/index.esm.js.map +1 -1
- package/dist/index.iife.js +153 -3
- 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 +26 -2
- package/package.json +1 -1
- package/src/index.ts +163 -8
- package/src/instructions.ts +73 -2
package/dist/instructions.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { InstructionType } from './utils';
|
|
|
4
4
|
/**
|
|
5
5
|
* An enumeration of valid StakePoolInstructionType's
|
|
6
6
|
*/
|
|
7
|
-
export type StakePoolInstructionType = 'IncreaseValidatorStake' | 'DecreaseValidatorStake' | 'UpdateValidatorListBalance' | 'UpdateStakePoolBalance' | 'CleanupRemovedValidatorEntries' | 'DepositStake' | 'DepositSol' | 'WithdrawStake' | 'WithdrawSol' | 'IncreaseAdditionalValidatorStake' | 'DecreaseAdditionalValidatorStake' | 'DecreaseValidatorStakeWithReserve' | 'Redelegate' | 'AddValidatorToPool' | 'RemoveValidatorFromPool' | 'DepositWsolWithSession' | 'WithdrawWsolWithSession';
|
|
7
|
+
export type StakePoolInstructionType = 'IncreaseValidatorStake' | 'DecreaseValidatorStake' | 'UpdateValidatorListBalance' | 'UpdateStakePoolBalance' | 'CleanupRemovedValidatorEntries' | 'DepositStake' | 'DepositSol' | 'WithdrawStake' | 'WithdrawSol' | 'IncreaseAdditionalValidatorStake' | 'DecreaseAdditionalValidatorStake' | 'DecreaseValidatorStakeWithReserve' | 'Redelegate' | 'AddValidatorToPool' | 'RemoveValidatorFromPool' | 'DepositWsolWithSession' | 'WithdrawWsolWithSession' | 'WithdrawStakeWithSession';
|
|
8
8
|
export declare function tokenMetadataLayout(instruction: number, nameLength: number, symbolLength: number, uriLength: number): {
|
|
9
9
|
index: number;
|
|
10
10
|
layout: BufferLayout.Structure<any>;
|
|
@@ -155,9 +155,29 @@ export type WithdrawWsolWithSessionParams = {
|
|
|
155
155
|
managerFeeAccount: PublicKey;
|
|
156
156
|
poolMint: PublicKey;
|
|
157
157
|
tokenProgramId: PublicKey;
|
|
158
|
-
solWithdrawAuthority?: PublicKey;
|
|
159
158
|
wsolMint: PublicKey;
|
|
160
159
|
programSigner: PublicKey;
|
|
160
|
+
userWallet: PublicKey;
|
|
161
|
+
poolTokensIn: number;
|
|
162
|
+
minimumLamportsOut: number;
|
|
163
|
+
payer?: PublicKey;
|
|
164
|
+
solWithdrawAuthority?: PublicKey;
|
|
165
|
+
};
|
|
166
|
+
export type WithdrawStakeWithSessionParams = {
|
|
167
|
+
programId: PublicKey;
|
|
168
|
+
stakePool: PublicKey;
|
|
169
|
+
validatorList: PublicKey;
|
|
170
|
+
withdrawAuthority: PublicKey;
|
|
171
|
+
stakeToSplit: PublicKey;
|
|
172
|
+
stakeToReceive: PublicKey;
|
|
173
|
+
/** The session signer (user or session) - used as both stake authority and transfer authority */
|
|
174
|
+
sessionSigner: PublicKey;
|
|
175
|
+
burnFromPool: PublicKey;
|
|
176
|
+
managerFeeAccount: PublicKey;
|
|
177
|
+
poolMint: PublicKey;
|
|
178
|
+
tokenProgramId: PublicKey;
|
|
179
|
+
/** The program signer PDA derived from PROGRAM_SIGNER_SEED */
|
|
180
|
+
programSigner: PublicKey;
|
|
161
181
|
poolTokensIn: number;
|
|
162
182
|
minimumLamportsOut: number;
|
|
163
183
|
};
|
|
@@ -304,6 +324,10 @@ export declare class StakePoolInstruction {
|
|
|
304
324
|
* Creates a transaction instruction to withdraw WSOL from a stake pool using a session.
|
|
305
325
|
*/
|
|
306
326
|
static withdrawWsolWithSession(params: WithdrawWsolWithSessionParams): TransactionInstruction;
|
|
327
|
+
/**
|
|
328
|
+
* Creates a transaction instruction to withdraw stake from a stake pool using a Fogo session.
|
|
329
|
+
*/
|
|
330
|
+
static withdrawStakeWithSession(params: WithdrawStakeWithSessionParams): TransactionInstruction;
|
|
307
331
|
/**
|
|
308
332
|
* Creates an instruction to create metadata
|
|
309
333
|
* using the mpl token metadata program for the pool token
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -827,6 +827,7 @@ export async function withdrawWsolWithSession(
|
|
|
827
827
|
amount: number,
|
|
828
828
|
minimumLamportsOut: number = 0,
|
|
829
829
|
solWithdrawAuthority?: PublicKey,
|
|
830
|
+
payer?: PublicKey,
|
|
830
831
|
) {
|
|
831
832
|
const stakePoolAccount = await getStakePoolAccount(connection, stakePoolAddress)
|
|
832
833
|
const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint)
|
|
@@ -848,14 +849,8 @@ export async function withdrawWsolWithSession(
|
|
|
848
849
|
const instructions: TransactionInstruction[] = []
|
|
849
850
|
const signers: Signer[] = []
|
|
850
851
|
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
signerOrSession,
|
|
854
|
-
userWsolAccount,
|
|
855
|
-
userPubkey,
|
|
856
|
-
NATIVE_MINT,
|
|
857
|
-
),
|
|
858
|
-
)
|
|
852
|
+
// The program handles wSOL ATA creation internally
|
|
853
|
+
// This prevents rent drain attacks where paymaster pays for ATA and user reclaims rent
|
|
859
854
|
|
|
860
855
|
const [programSigner] = PublicKey.findProgramAddressSync(
|
|
861
856
|
[Buffer.from('fogo_session_program_signer')],
|
|
@@ -882,6 +877,8 @@ export async function withdrawWsolWithSession(
|
|
|
882
877
|
solWithdrawAuthority,
|
|
883
878
|
wsolMint: NATIVE_MINT,
|
|
884
879
|
programSigner,
|
|
880
|
+
userWallet: userPubkey,
|
|
881
|
+
payer,
|
|
885
882
|
poolTokensIn: poolTokens,
|
|
886
883
|
minimumLamportsOut,
|
|
887
884
|
}),
|
|
@@ -893,6 +890,164 @@ export async function withdrawWsolWithSession(
|
|
|
893
890
|
}
|
|
894
891
|
}
|
|
895
892
|
|
|
893
|
+
/**
|
|
894
|
+
* Creates instructions required to withdraw stake from a stake pool using a Fogo session.
|
|
895
|
+
* The withdrawn stake account will be authorized to the user's wallet.
|
|
896
|
+
*/
|
|
897
|
+
export async function withdrawStakeWithSession(
|
|
898
|
+
connection: Connection,
|
|
899
|
+
stakePoolAddress: PublicKey,
|
|
900
|
+
signerOrSession: PublicKey,
|
|
901
|
+
userPubkey: PublicKey,
|
|
902
|
+
amount: number,
|
|
903
|
+
useReserve = false,
|
|
904
|
+
voteAccountAddress?: PublicKey,
|
|
905
|
+
minimumLamportsOut: number = 0,
|
|
906
|
+
payer?: PublicKey,
|
|
907
|
+
validatorComparator?: (_a: ValidatorAccount, _b: ValidatorAccount) => number,
|
|
908
|
+
) {
|
|
909
|
+
const stakePoolAccount = await getStakePoolAccount(connection, stakePoolAddress)
|
|
910
|
+
const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint)
|
|
911
|
+
const stakePool = stakePoolAccount.account.data
|
|
912
|
+
const poolTokens = solToLamports(amount)
|
|
913
|
+
const poolAmount = new BN(poolTokens)
|
|
914
|
+
|
|
915
|
+
const poolTokenAccount = getAssociatedTokenAddressSync(stakePool.poolMint, userPubkey)
|
|
916
|
+
const tokenAccount = await getAccount(connection, poolTokenAccount)
|
|
917
|
+
|
|
918
|
+
if (tokenAccount.amount < poolTokens) {
|
|
919
|
+
throw new Error(
|
|
920
|
+
`Not enough token balance to withdraw ${amount} pool tokens.
|
|
921
|
+
Maximum withdraw amount is ${lamportsToSol(tokenAccount.amount)} pool tokens.`,
|
|
922
|
+
)
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
const [programSigner] = PublicKey.findProgramAddressSync(
|
|
926
|
+
[Buffer.from('fogo_session_program_signer')],
|
|
927
|
+
stakePoolProgramId,
|
|
928
|
+
)
|
|
929
|
+
|
|
930
|
+
const withdrawAuthority = await findWithdrawAuthorityProgramAddress(
|
|
931
|
+
stakePoolProgramId,
|
|
932
|
+
stakePoolAddress,
|
|
933
|
+
)
|
|
934
|
+
|
|
935
|
+
const stakeAccountRentExemption = await connection.getMinimumBalanceForRentExemption(StakeProgram.space)
|
|
936
|
+
|
|
937
|
+
// Determine which stake accounts to withdraw from
|
|
938
|
+
const withdrawAccounts: WithdrawAccount[] = []
|
|
939
|
+
|
|
940
|
+
if (useReserve) {
|
|
941
|
+
withdrawAccounts.push({
|
|
942
|
+
stakeAddress: stakePool.reserveStake,
|
|
943
|
+
voteAddress: undefined,
|
|
944
|
+
poolAmount,
|
|
945
|
+
})
|
|
946
|
+
} else if (voteAccountAddress) {
|
|
947
|
+
const stakeAccountAddress = await findStakeProgramAddress(
|
|
948
|
+
stakePoolProgramId,
|
|
949
|
+
voteAccountAddress,
|
|
950
|
+
stakePoolAddress,
|
|
951
|
+
)
|
|
952
|
+
const stakeAccount = await connection.getAccountInfo(stakeAccountAddress)
|
|
953
|
+
if (!stakeAccount) {
|
|
954
|
+
throw new Error(`Validator stake account not found for vote address ${voteAccountAddress.toBase58()}`)
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
const availableLamports = new BN(
|
|
958
|
+
stakeAccount.lamports - MINIMUM_ACTIVE_STAKE - stakeAccountRentExemption,
|
|
959
|
+
)
|
|
960
|
+
if (availableLamports.lt(new BN(0))) {
|
|
961
|
+
throw new Error('Invalid Stake Account')
|
|
962
|
+
}
|
|
963
|
+
const availableForWithdrawal = calcLamportsWithdrawAmount(
|
|
964
|
+
stakePool,
|
|
965
|
+
availableLamports,
|
|
966
|
+
)
|
|
967
|
+
|
|
968
|
+
if (availableForWithdrawal.lt(poolAmount)) {
|
|
969
|
+
throw new Error(
|
|
970
|
+
`Not enough lamports available for withdrawal from ${stakeAccountAddress},
|
|
971
|
+
${poolAmount} asked, ${availableForWithdrawal} available.`,
|
|
972
|
+
)
|
|
973
|
+
}
|
|
974
|
+
withdrawAccounts.push({
|
|
975
|
+
stakeAddress: stakeAccountAddress,
|
|
976
|
+
voteAddress: voteAccountAddress,
|
|
977
|
+
poolAmount,
|
|
978
|
+
})
|
|
979
|
+
} else {
|
|
980
|
+
// Get the list of accounts to withdraw from automatically
|
|
981
|
+
withdrawAccounts.push(
|
|
982
|
+
...(await prepareWithdrawAccounts(
|
|
983
|
+
connection,
|
|
984
|
+
stakePool,
|
|
985
|
+
stakePoolAddress,
|
|
986
|
+
poolAmount,
|
|
987
|
+
validatorComparator,
|
|
988
|
+
poolTokenAccount.equals(stakePool.managerFeeAccount),
|
|
989
|
+
)),
|
|
990
|
+
)
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
const instructions: TransactionInstruction[] = []
|
|
994
|
+
const signers: Signer[] = []
|
|
995
|
+
const stakeAccountPubkeys: PublicKey[] = []
|
|
996
|
+
|
|
997
|
+
// Max 5 accounts to prevent an error: "Transaction too large"
|
|
998
|
+
const maxWithdrawAccounts = 5
|
|
999
|
+
let i = 0
|
|
1000
|
+
|
|
1001
|
+
for (const withdrawAccount of withdrawAccounts) {
|
|
1002
|
+
if (i >= maxWithdrawAccounts) {
|
|
1003
|
+
break
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
// Create a new stake account to receive the withdrawal
|
|
1007
|
+
const stakeReceiver = Keypair.generate()
|
|
1008
|
+
signers.push(stakeReceiver)
|
|
1009
|
+
stakeAccountPubkeys.push(stakeReceiver.publicKey)
|
|
1010
|
+
|
|
1011
|
+
// Create the stake account that will receive the split stake
|
|
1012
|
+
instructions.push(
|
|
1013
|
+
SystemProgram.createAccount({
|
|
1014
|
+
fromPubkey: payer ?? userPubkey,
|
|
1015
|
+
newAccountPubkey: stakeReceiver.publicKey,
|
|
1016
|
+
lamports: stakeAccountRentExemption,
|
|
1017
|
+
space: StakeProgram.space,
|
|
1018
|
+
programId: StakeProgram.programId,
|
|
1019
|
+
}),
|
|
1020
|
+
)
|
|
1021
|
+
|
|
1022
|
+
// Add the withdraw stake with session instruction
|
|
1023
|
+
instructions.push(
|
|
1024
|
+
StakePoolInstruction.withdrawStakeWithSession({
|
|
1025
|
+
programId: stakePoolProgramId,
|
|
1026
|
+
stakePool: stakePoolAddress,
|
|
1027
|
+
validatorList: stakePool.validatorList,
|
|
1028
|
+
withdrawAuthority,
|
|
1029
|
+
stakeToSplit: withdrawAccount.stakeAddress,
|
|
1030
|
+
stakeToReceive: stakeReceiver.publicKey,
|
|
1031
|
+
sessionSigner: signerOrSession,
|
|
1032
|
+
burnFromPool: poolTokenAccount,
|
|
1033
|
+
managerFeeAccount: stakePool.managerFeeAccount,
|
|
1034
|
+
poolMint: stakePool.poolMint,
|
|
1035
|
+
tokenProgramId: stakePool.tokenProgramId,
|
|
1036
|
+
programSigner,
|
|
1037
|
+
poolTokensIn: withdrawAccount.poolAmount.toNumber(),
|
|
1038
|
+
minimumLamportsOut: solToLamports(minimumLamportsOut),
|
|
1039
|
+
}),
|
|
1040
|
+
)
|
|
1041
|
+
i++
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
return {
|
|
1045
|
+
instructions,
|
|
1046
|
+
signers,
|
|
1047
|
+
stakeAccountPubkeys,
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
|
|
896
1051
|
export async function addValidatorToPool(
|
|
897
1052
|
connection: Connection,
|
|
898
1053
|
stakePoolAddress: PublicKey,
|
package/src/instructions.ts
CHANGED
|
@@ -41,6 +41,7 @@ export type StakePoolInstructionType
|
|
|
41
41
|
| 'RemoveValidatorFromPool'
|
|
42
42
|
| 'DepositWsolWithSession'
|
|
43
43
|
| 'WithdrawWsolWithSession'
|
|
44
|
+
| 'WithdrawStakeWithSession'
|
|
44
45
|
|
|
45
46
|
// 'UpdateTokenMetadata' and 'CreateTokenMetadata' have dynamic layouts
|
|
46
47
|
|
|
@@ -193,7 +194,8 @@ export const STAKE_POOL_INSTRUCTION_LAYOUTS: {
|
|
|
193
194
|
index: 24,
|
|
194
195
|
layout: BufferLayout.struct<any>([
|
|
195
196
|
BufferLayout.u8('instruction'),
|
|
196
|
-
BufferLayout.ns64('
|
|
197
|
+
BufferLayout.ns64('poolTokensIn'),
|
|
198
|
+
BufferLayout.ns64('minimumLamportsOut'),
|
|
197
199
|
]),
|
|
198
200
|
},
|
|
199
201
|
DepositSolWithSlippage: {
|
|
@@ -226,6 +228,14 @@ export const STAKE_POOL_INSTRUCTION_LAYOUTS: {
|
|
|
226
228
|
BufferLayout.ns64('minimumLamportsOut'),
|
|
227
229
|
]),
|
|
228
230
|
},
|
|
231
|
+
WithdrawStakeWithSession: {
|
|
232
|
+
index: 29,
|
|
233
|
+
layout: BufferLayout.struct<any>([
|
|
234
|
+
BufferLayout.u8('instruction'),
|
|
235
|
+
BufferLayout.ns64('poolTokensIn'),
|
|
236
|
+
BufferLayout.ns64('minimumLamportsOut'),
|
|
237
|
+
]),
|
|
238
|
+
},
|
|
229
239
|
})
|
|
230
240
|
|
|
231
241
|
/**
|
|
@@ -382,9 +392,30 @@ export type WithdrawWsolWithSessionParams = {
|
|
|
382
392
|
managerFeeAccount: PublicKey
|
|
383
393
|
poolMint: PublicKey
|
|
384
394
|
tokenProgramId: PublicKey
|
|
385
|
-
solWithdrawAuthority?: PublicKey
|
|
386
395
|
wsolMint: PublicKey
|
|
387
396
|
programSigner: PublicKey
|
|
397
|
+
userWallet: PublicKey
|
|
398
|
+
poolTokensIn: number
|
|
399
|
+
minimumLamportsOut: number
|
|
400
|
+
payer?: PublicKey
|
|
401
|
+
solWithdrawAuthority?: PublicKey
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
export type WithdrawStakeWithSessionParams = {
|
|
405
|
+
programId: PublicKey
|
|
406
|
+
stakePool: PublicKey
|
|
407
|
+
validatorList: PublicKey
|
|
408
|
+
withdrawAuthority: PublicKey
|
|
409
|
+
stakeToSplit: PublicKey
|
|
410
|
+
stakeToReceive: PublicKey
|
|
411
|
+
/** The session signer (user or session) - used as both stake authority and transfer authority */
|
|
412
|
+
sessionSigner: PublicKey
|
|
413
|
+
burnFromPool: PublicKey
|
|
414
|
+
managerFeeAccount: PublicKey
|
|
415
|
+
poolMint: PublicKey
|
|
416
|
+
tokenProgramId: PublicKey
|
|
417
|
+
/** The program signer PDA derived from PROGRAM_SIGNER_SEED */
|
|
418
|
+
programSigner: PublicKey
|
|
388
419
|
poolTokensIn: number
|
|
389
420
|
minimumLamportsOut: number
|
|
390
421
|
}
|
|
@@ -1138,6 +1169,9 @@ export class StakePoolInstruction {
|
|
|
1138
1169
|
|
|
1139
1170
|
{ pubkey: params.wsolMint, isSigner: false, isWritable: false },
|
|
1140
1171
|
{ pubkey: params.programSigner, isSigner: false, isWritable: true },
|
|
1172
|
+
{ pubkey: params.payer ?? params.userTransferAuthority, isSigner: true, isWritable: true },
|
|
1173
|
+
{ pubkey: params.userWallet, isSigner: false, isWritable: false },
|
|
1174
|
+
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
|
|
1141
1175
|
]
|
|
1142
1176
|
|
|
1143
1177
|
if (params.solWithdrawAuthority) {
|
|
@@ -1148,6 +1182,43 @@ export class StakePoolInstruction {
|
|
|
1148
1182
|
})
|
|
1149
1183
|
}
|
|
1150
1184
|
|
|
1185
|
+
// Associated Token Program must be last - only needed in transaction for CPI routing
|
|
1186
|
+
keys.push({ pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false })
|
|
1187
|
+
|
|
1188
|
+
return new TransactionInstruction({
|
|
1189
|
+
programId: params.programId,
|
|
1190
|
+
keys,
|
|
1191
|
+
data,
|
|
1192
|
+
})
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
/**
|
|
1196
|
+
* Creates a transaction instruction to withdraw stake from a stake pool using a Fogo session.
|
|
1197
|
+
*/
|
|
1198
|
+
static withdrawStakeWithSession(params: WithdrawStakeWithSessionParams): TransactionInstruction {
|
|
1199
|
+
const type = STAKE_POOL_INSTRUCTION_LAYOUTS.WithdrawStakeWithSession
|
|
1200
|
+
const data = encodeData(type, {
|
|
1201
|
+
poolTokensIn: params.poolTokensIn,
|
|
1202
|
+
minimumLamportsOut: params.minimumLamportsOut,
|
|
1203
|
+
})
|
|
1204
|
+
|
|
1205
|
+
const keys = [
|
|
1206
|
+
{ pubkey: params.stakePool, isSigner: false, isWritable: true },
|
|
1207
|
+
{ pubkey: params.validatorList, isSigner: false, isWritable: true },
|
|
1208
|
+
{ pubkey: params.withdrawAuthority, isSigner: false, isWritable: false },
|
|
1209
|
+
{ pubkey: params.stakeToSplit, isSigner: false, isWritable: true },
|
|
1210
|
+
{ pubkey: params.stakeToReceive, isSigner: false, isWritable: true },
|
|
1211
|
+
{ pubkey: params.sessionSigner, isSigner: true, isWritable: false }, // user_stake_authority_info (signer_or_session)
|
|
1212
|
+
{ pubkey: params.sessionSigner, isSigner: false, isWritable: false }, // user_transfer_authority_info (not used in session path)
|
|
1213
|
+
{ pubkey: params.burnFromPool, isSigner: false, isWritable: true },
|
|
1214
|
+
{ pubkey: params.managerFeeAccount, isSigner: false, isWritable: true },
|
|
1215
|
+
{ pubkey: params.poolMint, isSigner: false, isWritable: true },
|
|
1216
|
+
{ pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
|
|
1217
|
+
{ pubkey: params.tokenProgramId, isSigner: false, isWritable: false },
|
|
1218
|
+
{ pubkey: StakeProgram.programId, isSigner: false, isWritable: false },
|
|
1219
|
+
{ pubkey: params.programSigner, isSigner: false, isWritable: false },
|
|
1220
|
+
]
|
|
1221
|
+
|
|
1151
1222
|
return new TransactionInstruction({
|
|
1152
1223
|
programId: params.programId,
|
|
1153
1224
|
keys,
|