@ignitionfi/fogo-stake-pool 1.0.2 → 1.1.0
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/codecs.d.ts +10 -0
- package/dist/index.browser.cjs.js +369 -208
- package/dist/index.browser.cjs.js.map +1 -1
- package/dist/index.browser.esm.js +369 -208
- package/dist/index.browser.esm.js.map +1 -1
- package/dist/index.cjs.js +369 -208
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +9 -7
- package/dist/index.esm.js +369 -208
- package/dist/index.esm.js.map +1 -1
- package/dist/index.iife.js +403 -242
- 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 +31 -22
- package/dist/utils/stake.d.ts +19 -2
- package/package.json +1 -1
- package/src/codecs.ts +59 -6
- package/src/constants.ts +1 -1
- package/src/index.ts +79 -26
- package/src/instructions.ts +140 -67
- package/src/utils/stake.ts +133 -75
package/dist/instructions.d.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import * as BufferLayout from '@solana/buffer-layout';
|
|
2
2
|
import { PublicKey, TransactionInstruction } from '@solana/web3.js';
|
|
3
|
+
import BN from 'bn.js';
|
|
3
4
|
import { InstructionType } from './utils';
|
|
5
|
+
/**
|
|
6
|
+
* Type for amounts that can be converted to BN.
|
|
7
|
+
* Accepts number, bigint, BN, or string representations.
|
|
8
|
+
*
|
|
9
|
+
* IMPORTANT: For values > 9,007,199,254,740,991 (Number.MAX_SAFE_INTEGER),
|
|
10
|
+
* you MUST use bigint, BN, or string to avoid precision loss.
|
|
11
|
+
*/
|
|
12
|
+
export type AmountInput = number | bigint | BN | string;
|
|
4
13
|
/**
|
|
5
14
|
* An enumeration of valid StakePoolInstructionType's
|
|
6
15
|
*/
|
|
@@ -60,8 +69,8 @@ export type DecreaseValidatorStakeParams = {
|
|
|
60
69
|
validatorList: PublicKey;
|
|
61
70
|
validatorStake: PublicKey;
|
|
62
71
|
transientStake: PublicKey;
|
|
63
|
-
lamports:
|
|
64
|
-
transientStakeSeed:
|
|
72
|
+
lamports: AmountInput;
|
|
73
|
+
transientStakeSeed: AmountInput;
|
|
65
74
|
};
|
|
66
75
|
export interface DecreaseValidatorStakeWithReserveParams extends DecreaseValidatorStakeParams {
|
|
67
76
|
reserveStake: PublicKey;
|
|
@@ -69,7 +78,7 @@ export interface DecreaseValidatorStakeWithReserveParams extends DecreaseValidat
|
|
|
69
78
|
export interface DecreaseAdditionalValidatorStakeParams extends DecreaseValidatorStakeParams {
|
|
70
79
|
reserveStake: PublicKey;
|
|
71
80
|
ephemeralStake: PublicKey;
|
|
72
|
-
ephemeralStakeSeed:
|
|
81
|
+
ephemeralStakeSeed: AmountInput;
|
|
73
82
|
}
|
|
74
83
|
/**
|
|
75
84
|
* (Staker only) Increase stake on a validator from the reserve account.
|
|
@@ -84,12 +93,12 @@ export type IncreaseValidatorStakeParams = {
|
|
|
84
93
|
transientStake: PublicKey;
|
|
85
94
|
validatorStake: PublicKey;
|
|
86
95
|
validatorVote: PublicKey;
|
|
87
|
-
lamports:
|
|
88
|
-
transientStakeSeed:
|
|
96
|
+
lamports: AmountInput;
|
|
97
|
+
transientStakeSeed: AmountInput;
|
|
89
98
|
};
|
|
90
99
|
export interface IncreaseAdditionalValidatorStakeParams extends IncreaseValidatorStakeParams {
|
|
91
100
|
ephemeralStake: PublicKey;
|
|
92
|
-
ephemeralStakeSeed:
|
|
101
|
+
ephemeralStakeSeed: AmountInput;
|
|
93
102
|
}
|
|
94
103
|
/**
|
|
95
104
|
* Deposits a stake account into the pool in exchange for pool tokens
|
|
@@ -123,7 +132,7 @@ export type WithdrawStakeParams = {
|
|
|
123
132
|
sourcePoolAccount: PublicKey;
|
|
124
133
|
managerFeeAccount: PublicKey;
|
|
125
134
|
poolMint: PublicKey;
|
|
126
|
-
poolTokens:
|
|
135
|
+
poolTokens: AmountInput;
|
|
127
136
|
};
|
|
128
137
|
/**
|
|
129
138
|
* Withdraw sol instruction params
|
|
@@ -139,7 +148,7 @@ export type WithdrawSolParams = {
|
|
|
139
148
|
solWithdrawAuthority?: PublicKey | undefined;
|
|
140
149
|
managerFeeAccount: PublicKey;
|
|
141
150
|
poolMint: PublicKey;
|
|
142
|
-
poolTokens:
|
|
151
|
+
poolTokens: AmountInput;
|
|
143
152
|
};
|
|
144
153
|
/**
|
|
145
154
|
* Withdraw WSOL with session instruction params
|
|
@@ -158,8 +167,8 @@ export type WithdrawWsolWithSessionParams = {
|
|
|
158
167
|
wsolMint: PublicKey;
|
|
159
168
|
programSigner: PublicKey;
|
|
160
169
|
userWallet: PublicKey;
|
|
161
|
-
poolTokensIn:
|
|
162
|
-
minimumLamportsOut:
|
|
170
|
+
poolTokensIn: AmountInput;
|
|
171
|
+
minimumLamportsOut: AmountInput;
|
|
163
172
|
solWithdrawAuthority?: PublicKey;
|
|
164
173
|
};
|
|
165
174
|
export type WithdrawStakeWithSessionParams = {
|
|
@@ -178,12 +187,12 @@ export type WithdrawStakeWithSessionParams = {
|
|
|
178
187
|
tokenProgramId: PublicKey;
|
|
179
188
|
/** The program signer PDA derived from PROGRAM_SIGNER_SEED */
|
|
180
189
|
programSigner: PublicKey;
|
|
181
|
-
/**
|
|
182
|
-
|
|
183
|
-
poolTokensIn:
|
|
184
|
-
minimumLamportsOut:
|
|
190
|
+
/** Reserve stake account for rent funding */
|
|
191
|
+
reserveStake: PublicKey;
|
|
192
|
+
poolTokensIn: AmountInput;
|
|
193
|
+
minimumLamportsOut: AmountInput;
|
|
185
194
|
/** Seed used to derive the user stake PDA */
|
|
186
|
-
userStakeSeed:
|
|
195
|
+
userStakeSeed: AmountInput;
|
|
187
196
|
};
|
|
188
197
|
export type WithdrawFromStakeAccountWithSessionParams = {
|
|
189
198
|
programId: PublicKey;
|
|
@@ -194,9 +203,9 @@ export type WithdrawFromStakeAccountWithSessionParams = {
|
|
|
194
203
|
/** The session signer (user or session) */
|
|
195
204
|
sessionSigner: PublicKey;
|
|
196
205
|
/** Seed used to derive the user stake PDA */
|
|
197
|
-
userStakeSeed:
|
|
198
|
-
/** Lamports to withdraw (use Number.MAX_SAFE_INTEGER for full withdrawal) */
|
|
199
|
-
lamports:
|
|
206
|
+
userStakeSeed: AmountInput;
|
|
207
|
+
/** Lamports to withdraw (use BigInt(Number.MAX_SAFE_INTEGER) for full withdrawal) */
|
|
208
|
+
lamports: AmountInput;
|
|
200
209
|
};
|
|
201
210
|
/**
|
|
202
211
|
* Deposit SOL directly into the pool's reserve account. The output is a "pool" token
|
|
@@ -213,7 +222,7 @@ export type DepositSolParams = {
|
|
|
213
222
|
managerFeeAccount: PublicKey;
|
|
214
223
|
referralPoolAccount: PublicKey;
|
|
215
224
|
poolMint: PublicKey;
|
|
216
|
-
lamports:
|
|
225
|
+
lamports: AmountInput;
|
|
217
226
|
};
|
|
218
227
|
export type CreateTokenMetadataParams = {
|
|
219
228
|
programId?: PublicKey | undefined;
|
|
@@ -325,8 +334,8 @@ export declare class StakePoolInstruction {
|
|
|
325
334
|
tokenProgramId: PublicKey;
|
|
326
335
|
programId: PublicKey;
|
|
327
336
|
userWallet: PublicKey;
|
|
328
|
-
lamportsIn:
|
|
329
|
-
minimumPoolTokensOut:
|
|
337
|
+
lamportsIn: AmountInput;
|
|
338
|
+
minimumPoolTokensOut: AmountInput;
|
|
330
339
|
payer?: PublicKey;
|
|
331
340
|
}): TransactionInstruction;
|
|
332
341
|
/**
|
|
@@ -344,7 +353,7 @@ export declare class StakePoolInstruction {
|
|
|
344
353
|
static withdrawWsolWithSession(params: WithdrawWsolWithSessionParams): TransactionInstruction;
|
|
345
354
|
/**
|
|
346
355
|
* Creates a transaction instruction to withdraw stake from a stake pool using a Fogo session.
|
|
347
|
-
* The stake account is created as a PDA and rent is
|
|
356
|
+
* The stake account is created as a PDA and rent is funded from the reserve.
|
|
348
357
|
*/
|
|
349
358
|
static withdrawStakeWithSession(params: WithdrawStakeWithSessionParams): TransactionInstruction;
|
|
350
359
|
/**
|
package/dist/utils/stake.d.ts
CHANGED
|
@@ -12,12 +12,29 @@ export declare function getValidatorListAccount(connection: Connection, pubkey:
|
|
|
12
12
|
};
|
|
13
13
|
}>;
|
|
14
14
|
export interface ValidatorAccount {
|
|
15
|
-
type: 'preferred' | 'active' | 'transient'
|
|
15
|
+
type: 'preferred' | 'active' | 'transient';
|
|
16
16
|
voteAddress?: PublicKey | undefined;
|
|
17
17
|
stakeAddress: PublicKey;
|
|
18
18
|
lamports: BN;
|
|
19
19
|
}
|
|
20
|
-
export
|
|
20
|
+
export interface PrepareWithdrawResult {
|
|
21
|
+
withdrawAccounts: WithdrawAccount[];
|
|
22
|
+
/** Pool tokens that will be withdrawn via delayed unstake */
|
|
23
|
+
delayedAmount: BN;
|
|
24
|
+
/** Pool tokens remaining that need instant unstake */
|
|
25
|
+
remainingAmount: BN;
|
|
26
|
+
}
|
|
27
|
+
/** Pre-fetched data to avoid duplicate RPC calls */
|
|
28
|
+
export interface PrepareWithdrawPrefetchedData {
|
|
29
|
+
/** Raw validator list account data from getAccountInfo */
|
|
30
|
+
validatorListData: Buffer | null;
|
|
31
|
+
/** Rent exemption for stake accounts in lamports */
|
|
32
|
+
minBalanceForRentExemption: number;
|
|
33
|
+
/** Minimum stake delegation in lamports */
|
|
34
|
+
stakeMinimumDelegation: number;
|
|
35
|
+
}
|
|
36
|
+
export declare function prepareWithdrawAccounts(connection: Connection, stakePool: StakePool, stakePoolAddress: PublicKey, amount: BN, compareFn?: (a: ValidatorAccount, b: ValidatorAccount) => number, skipFee?: boolean, allowPartial?: boolean, prefetchedData?: PrepareWithdrawPrefetchedData): Promise<WithdrawAccount[]>;
|
|
37
|
+
export declare function prepareWithdrawAccounts(connection: Connection, stakePool: StakePool, stakePoolAddress: PublicKey, amount: BN, compareFn: ((a: ValidatorAccount, b: ValidatorAccount) => number) | undefined, skipFee: boolean | undefined, allowPartial: true, prefetchedData?: PrepareWithdrawPrefetchedData): Promise<PrepareWithdrawResult>;
|
|
21
38
|
/**
|
|
22
39
|
* Calculate the pool tokens that should be minted for a deposit of `stakeLamports`
|
|
23
40
|
*/
|
package/package.json
CHANGED
package/src/codecs.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as BufferLayout from '@solana/buffer-layout'
|
|
1
2
|
import { PublicKey } from '@solana/web3.js'
|
|
2
3
|
import BN from 'bn.js'
|
|
3
4
|
import { blob, Layout as LayoutCls, offset, seq, struct, u8, u32 } from 'buffer-layout'
|
|
@@ -15,18 +16,22 @@ export interface Layout<T> {
|
|
|
15
16
|
replicate: (name: string) => this
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
/**
|
|
20
|
+
* BN-based layout for data decoding using buffer-layout.
|
|
21
|
+
* Used for decoding on-chain account data (StakePool, ValidatorList, etc.)
|
|
22
|
+
*/
|
|
23
|
+
class BNDataLayout extends LayoutCls<BN> {
|
|
24
|
+
blobLayout: Layout<Buffer>
|
|
20
25
|
signed: boolean
|
|
21
26
|
|
|
22
27
|
constructor(span: number, signed: boolean, property?: string) {
|
|
23
28
|
super(span, property)
|
|
24
|
-
this.
|
|
29
|
+
this.blobLayout = blob(span)
|
|
25
30
|
this.signed = signed
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
decode(b: Buffer, offset = 0) {
|
|
29
|
-
const num = new BN(this.
|
|
34
|
+
const num = new BN(this.blobLayout.decode(b, offset), 10, 'le')
|
|
30
35
|
if (this.signed) {
|
|
31
36
|
return num.fromTwos(this.span * 8).clone()
|
|
32
37
|
}
|
|
@@ -37,12 +42,60 @@ class BNLayout extends LayoutCls<BN> {
|
|
|
37
42
|
if (this.signed) {
|
|
38
43
|
src = src.toTwos(this.span * 8)
|
|
39
44
|
}
|
|
40
|
-
return this.
|
|
45
|
+
return this.blobLayout.encode(src.toArrayLike(Buffer, 'le', this.span), b, offset)
|
|
41
46
|
}
|
|
42
47
|
}
|
|
43
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Creates a u64 layout for data decoding (account layouts).
|
|
51
|
+
* Used in StakePoolLayout, ValidatorListLayout, etc.
|
|
52
|
+
*/
|
|
44
53
|
export function u64(property?: string): Layout<BN> {
|
|
45
|
-
return new
|
|
54
|
+
return new BNDataLayout(8, false, property)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* BN-based layout for 64-bit unsigned integers using @solana/buffer-layout.
|
|
59
|
+
* Used for encoding instruction data with support for values > MAX_SAFE_INTEGER.
|
|
60
|
+
*/
|
|
61
|
+
class BNInstructionLayout extends BufferLayout.Layout<BN> {
|
|
62
|
+
blobLayout: BufferLayout.Blob
|
|
63
|
+
signed: boolean
|
|
64
|
+
|
|
65
|
+
constructor(span: number, signed: boolean, property?: string) {
|
|
66
|
+
super(span, property)
|
|
67
|
+
this.blobLayout = BufferLayout.blob(span)
|
|
68
|
+
this.signed = signed
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
decode(b: Uint8Array, offset = 0): BN {
|
|
72
|
+
const num = new BN(this.blobLayout.decode(b, offset), 10, 'le')
|
|
73
|
+
if (this.signed) {
|
|
74
|
+
return num.fromTwos(this.span * 8).clone()
|
|
75
|
+
}
|
|
76
|
+
return num
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
encode(src: BN, b: Uint8Array, offset = 0): number {
|
|
80
|
+
if (this.signed) {
|
|
81
|
+
src = src.toTwos(this.span * 8)
|
|
82
|
+
}
|
|
83
|
+
return this.blobLayout.encode(src.toArrayLike(Buffer, 'le', this.span), b, offset)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
getSpan(_b?: Uint8Array, _offset?: number): number {
|
|
87
|
+
return this.span
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Creates a u64 layout for instruction encoding.
|
|
93
|
+
* Properly handles BN values larger than Number.MAX_SAFE_INTEGER.
|
|
94
|
+
* Compatible with @solana/buffer-layout.struct().
|
|
95
|
+
*/
|
|
96
|
+
// eslint-disable-next-line ts/no-explicit-any
|
|
97
|
+
export function u64Instruction(property?: string): any {
|
|
98
|
+
return new BNInstructionLayout(8, false, property)
|
|
46
99
|
}
|
|
47
100
|
|
|
48
101
|
class WrappedLayout<T, U> extends LayoutCls<U> {
|
package/src/constants.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer'
|
|
2
|
-
import {
|
|
2
|
+
import { PublicKey } from '@solana/web3.js'
|
|
3
3
|
|
|
4
4
|
// Public key that identifies the metadata program.
|
|
5
5
|
export const METADATA_PROGRAM_ID = new PublicKey('metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s')
|
package/src/index.ts
CHANGED
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
MINIMUM_ACTIVE_STAKE,
|
|
25
25
|
STAKE_POOL_PROGRAM_ID,
|
|
26
26
|
} from './constants'
|
|
27
|
-
import { StakePoolInstruction } from './instructions'
|
|
27
|
+
import { AmountInput, StakePoolInstruction } from './instructions'
|
|
28
28
|
import {
|
|
29
29
|
StakeAccount,
|
|
30
30
|
StakePool,
|
|
@@ -47,6 +47,7 @@ import {
|
|
|
47
47
|
lamportsToSol,
|
|
48
48
|
newStakeAccount,
|
|
49
49
|
prepareWithdrawAccounts,
|
|
50
|
+
PrepareWithdrawPrefetchedData,
|
|
50
51
|
solToLamports,
|
|
51
52
|
ValidatorAccount,
|
|
52
53
|
} from './utils'
|
|
@@ -303,8 +304,8 @@ export async function depositWsolWithSession(
|
|
|
303
304
|
stakePoolAddress: PublicKey,
|
|
304
305
|
signerOrSession: PublicKey,
|
|
305
306
|
userPubkey: PublicKey,
|
|
306
|
-
lamports:
|
|
307
|
-
minimumPoolTokensOut:
|
|
307
|
+
lamports: AmountInput,
|
|
308
|
+
minimumPoolTokensOut: AmountInput = 0,
|
|
308
309
|
destinationTokenAccount?: PublicKey,
|
|
309
310
|
referrerTokenAccount?: PublicKey,
|
|
310
311
|
depositAuthority?: PublicKey,
|
|
@@ -323,13 +324,22 @@ export async function depositWsolWithSession(
|
|
|
323
324
|
'confirmed',
|
|
324
325
|
)
|
|
325
326
|
const wsolBalance = tokenAccountInfo
|
|
326
|
-
?
|
|
327
|
-
: 0
|
|
328
|
-
|
|
329
|
-
|
|
327
|
+
? BigInt(tokenAccountInfo.value.amount)
|
|
328
|
+
: BigInt(0)
|
|
329
|
+
|
|
330
|
+
// Convert lamports to BigInt for comparison
|
|
331
|
+
const lamportsBigInt = typeof lamports === 'bigint'
|
|
332
|
+
? lamports
|
|
333
|
+
: typeof lamports === 'string'
|
|
334
|
+
? BigInt(lamports)
|
|
335
|
+
: BN.isBN(lamports)
|
|
336
|
+
? BigInt(lamports.toString())
|
|
337
|
+
: BigInt(lamports)
|
|
338
|
+
|
|
339
|
+
if (wsolBalance < lamportsBigInt) {
|
|
330
340
|
throw new Error(
|
|
331
341
|
`Not enough WSOL to deposit into pool. Maximum deposit amount is ${lamportsToSol(
|
|
332
|
-
wsolBalance,
|
|
342
|
+
Number(wsolBalance),
|
|
333
343
|
)} WSOL.`,
|
|
334
344
|
)
|
|
335
345
|
}
|
|
@@ -401,13 +411,23 @@ export async function depositSol(
|
|
|
401
411
|
connection: Connection,
|
|
402
412
|
stakePoolAddress: PublicKey,
|
|
403
413
|
from: PublicKey,
|
|
404
|
-
lamports:
|
|
414
|
+
lamports: AmountInput,
|
|
405
415
|
destinationTokenAccount?: PublicKey,
|
|
406
416
|
referrerTokenAccount?: PublicKey,
|
|
407
417
|
depositAuthority?: PublicKey,
|
|
408
418
|
) {
|
|
409
419
|
const fromBalance = await connection.getBalance(from, 'confirmed')
|
|
410
|
-
|
|
420
|
+
|
|
421
|
+
// Convert lamports to BigInt for comparison
|
|
422
|
+
const lamportsBigInt = typeof lamports === 'bigint'
|
|
423
|
+
? lamports
|
|
424
|
+
: typeof lamports === 'string'
|
|
425
|
+
? BigInt(lamports)
|
|
426
|
+
: BN.isBN(lamports)
|
|
427
|
+
? BigInt(lamports.toString())
|
|
428
|
+
: BigInt(lamports)
|
|
429
|
+
|
|
430
|
+
if (BigInt(fromBalance) < lamportsBigInt) {
|
|
411
431
|
throw new Error(
|
|
412
432
|
`Not enough SOL to deposit into pool. Maximum deposit amount is ${lamportsToSol(
|
|
413
433
|
fromBalance,
|
|
@@ -432,7 +452,7 @@ export async function depositSol(
|
|
|
432
452
|
SystemProgram.transfer({
|
|
433
453
|
fromPubkey: from,
|
|
434
454
|
toPubkey: userSolTransfer.publicKey,
|
|
435
|
-
lamports,
|
|
455
|
+
lamports: lamportsBigInt,
|
|
436
456
|
}),
|
|
437
457
|
)
|
|
438
458
|
|
|
@@ -1034,41 +1054,57 @@ export async function getUserStakeAccounts(
|
|
|
1034
1054
|
* Withdraws stake from a stake pool using a Fogo session.
|
|
1035
1055
|
*
|
|
1036
1056
|
* The on-chain program creates stake account PDAs. The rent for these accounts
|
|
1037
|
-
* is
|
|
1057
|
+
* is funded from the reserve stake.
|
|
1038
1058
|
*
|
|
1039
1059
|
* @param connection - Solana connection
|
|
1040
1060
|
* @param stakePoolAddress - The stake pool to withdraw from
|
|
1041
1061
|
* @param signerOrSession - The session signer public key
|
|
1042
1062
|
* @param userPubkey - User's wallet (used for PDA derivation and token ownership)
|
|
1043
|
-
* @param payer - Payer for stake account rent (typically paymaster)
|
|
1044
1063
|
* @param amount - Amount of pool tokens to withdraw
|
|
1045
1064
|
* @param userStakeSeedStart - Starting seed for user stake PDA derivation (default: 0)
|
|
1046
1065
|
* @param useReserve - Whether to withdraw from reserve (default: false)
|
|
1047
1066
|
* @param voteAccountAddress - Optional specific validator to withdraw from
|
|
1048
1067
|
* @param minimumLamportsOut - Minimum lamports to receive (slippage protection)
|
|
1049
1068
|
* @param validatorComparator - Optional comparator for validator selection
|
|
1069
|
+
* @param allowPartial - If true, returns partial results instead of throwing when not enough stake available
|
|
1050
1070
|
*/
|
|
1051
1071
|
export async function withdrawStakeWithSession(
|
|
1052
1072
|
connection: Connection,
|
|
1053
1073
|
stakePoolAddress: PublicKey,
|
|
1054
1074
|
signerOrSession: PublicKey,
|
|
1055
1075
|
userPubkey: PublicKey,
|
|
1056
|
-
payer: PublicKey,
|
|
1057
1076
|
amount: number,
|
|
1058
1077
|
userStakeSeedStart: number = 0,
|
|
1059
1078
|
useReserve = false,
|
|
1060
1079
|
voteAccountAddress?: PublicKey,
|
|
1061
1080
|
minimumLamportsOut: number = 0,
|
|
1062
1081
|
validatorComparator?: (_a: ValidatorAccount, _b: ValidatorAccount) => number,
|
|
1082
|
+
allowPartial = false,
|
|
1063
1083
|
) {
|
|
1064
|
-
const stakePoolAccount = await getStakePoolAccount(connection, stakePoolAddress)
|
|
1065
1084
|
const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint)
|
|
1085
|
+
|
|
1086
|
+
// First fetch: get stake pool to know other account addresses
|
|
1087
|
+
const stakePoolAccount = await getStakePoolAccount(connection, stakePoolAddress)
|
|
1066
1088
|
const stakePool = stakePoolAccount.account.data
|
|
1067
1089
|
const poolTokens = solToLamports(amount)
|
|
1068
1090
|
const poolAmount = new BN(poolTokens)
|
|
1069
1091
|
|
|
1070
1092
|
const poolTokenAccount = getAssociatedTokenAddressSync(stakePool.poolMint, userPubkey)
|
|
1071
|
-
|
|
1093
|
+
|
|
1094
|
+
// Second fetch: get ALL remaining data in parallel
|
|
1095
|
+
const [tokenAccount, stakeAccountRentExemption, validatorListAcc, stakeMinimumDelegationResponse] = await Promise.all([
|
|
1096
|
+
getAccount(connection, poolTokenAccount),
|
|
1097
|
+
connection.getMinimumBalanceForRentExemption(StakeProgram.space),
|
|
1098
|
+
connection.getAccountInfo(stakePool.validatorList),
|
|
1099
|
+
connection.getStakeMinimumDelegation(),
|
|
1100
|
+
])
|
|
1101
|
+
|
|
1102
|
+
// Pre-fetch data to avoid duplicate RPC calls in prepareWithdrawAccounts
|
|
1103
|
+
const prefetchedData: PrepareWithdrawPrefetchedData = {
|
|
1104
|
+
validatorListData: validatorListAcc?.data ?? null,
|
|
1105
|
+
minBalanceForRentExemption: stakeAccountRentExemption,
|
|
1106
|
+
stakeMinimumDelegation: Number(stakeMinimumDelegationResponse.value),
|
|
1107
|
+
}
|
|
1072
1108
|
|
|
1073
1109
|
if (tokenAccount.amount < poolTokens) {
|
|
1074
1110
|
throw new Error(
|
|
@@ -1087,10 +1123,9 @@ export async function withdrawStakeWithSession(
|
|
|
1087
1123
|
stakePoolAddress,
|
|
1088
1124
|
)
|
|
1089
1125
|
|
|
1090
|
-
const stakeAccountRentExemption = await connection.getMinimumBalanceForRentExemption(StakeProgram.space)
|
|
1091
|
-
|
|
1092
1126
|
// Determine which stake accounts to withdraw from
|
|
1093
1127
|
const withdrawAccounts: WithdrawAccount[] = []
|
|
1128
|
+
let partialRemainingAmount: BN | undefined
|
|
1094
1129
|
|
|
1095
1130
|
if (useReserve) {
|
|
1096
1131
|
withdrawAccounts.push({
|
|
@@ -1133,16 +1168,33 @@ export async function withdrawStakeWithSession(
|
|
|
1133
1168
|
})
|
|
1134
1169
|
} else {
|
|
1135
1170
|
// Get the list of accounts to withdraw from automatically
|
|
1136
|
-
|
|
1137
|
-
|
|
1171
|
+
if (allowPartial) {
|
|
1172
|
+
const result = await prepareWithdrawAccounts(
|
|
1138
1173
|
connection,
|
|
1139
1174
|
stakePool,
|
|
1140
1175
|
stakePoolAddress,
|
|
1141
1176
|
poolAmount,
|
|
1142
1177
|
validatorComparator,
|
|
1143
1178
|
poolTokenAccount.equals(stakePool.managerFeeAccount),
|
|
1144
|
-
|
|
1145
|
-
|
|
1179
|
+
true,
|
|
1180
|
+
prefetchedData,
|
|
1181
|
+
)
|
|
1182
|
+
withdrawAccounts.push(...result.withdrawAccounts)
|
|
1183
|
+
partialRemainingAmount = result.remainingAmount
|
|
1184
|
+
} else {
|
|
1185
|
+
withdrawAccounts.push(
|
|
1186
|
+
...(await prepareWithdrawAccounts(
|
|
1187
|
+
connection,
|
|
1188
|
+
stakePool,
|
|
1189
|
+
stakePoolAddress,
|
|
1190
|
+
poolAmount,
|
|
1191
|
+
validatorComparator,
|
|
1192
|
+
poolTokenAccount.equals(stakePool.managerFeeAccount),
|
|
1193
|
+
undefined,
|
|
1194
|
+
prefetchedData,
|
|
1195
|
+
)),
|
|
1196
|
+
)
|
|
1197
|
+
}
|
|
1146
1198
|
}
|
|
1147
1199
|
|
|
1148
1200
|
const instructions: TransactionInstruction[] = []
|
|
@@ -1169,7 +1221,7 @@ export async function withdrawStakeWithSession(
|
|
|
1169
1221
|
stakeAccountPubkeys.push(stakeReceiverPubkey)
|
|
1170
1222
|
userStakeSeeds.push(userStakeSeed)
|
|
1171
1223
|
|
|
1172
|
-
// The on-chain program creates the stake account PDA and rent is
|
|
1224
|
+
// The on-chain program creates the stake account PDA and rent is funded from reserve.
|
|
1173
1225
|
instructions.push(
|
|
1174
1226
|
StakePoolInstruction.withdrawStakeWithSession({
|
|
1175
1227
|
programId: stakePoolProgramId,
|
|
@@ -1184,7 +1236,7 @@ export async function withdrawStakeWithSession(
|
|
|
1184
1236
|
poolMint: stakePool.poolMint,
|
|
1185
1237
|
tokenProgramId: stakePool.tokenProgramId,
|
|
1186
1238
|
programSigner,
|
|
1187
|
-
|
|
1239
|
+
reserveStake: stakePool.reserveStake,
|
|
1188
1240
|
poolTokensIn: withdrawAccount.poolAmount.toNumber(),
|
|
1189
1241
|
minimumLamportsOut,
|
|
1190
1242
|
userStakeSeed,
|
|
@@ -1197,6 +1249,7 @@ export async function withdrawStakeWithSession(
|
|
|
1197
1249
|
instructions,
|
|
1198
1250
|
stakeAccountPubkeys,
|
|
1199
1251
|
userStakeSeeds,
|
|
1252
|
+
remainingPoolTokens: partialRemainingAmount ? lamportsToSol(partialRemainingAmount) : 0,
|
|
1200
1253
|
}
|
|
1201
1254
|
}
|
|
1202
1255
|
|
|
@@ -1329,7 +1382,7 @@ export async function increaseValidatorStake(
|
|
|
1329
1382
|
connection: Connection,
|
|
1330
1383
|
stakePoolAddress: PublicKey,
|
|
1331
1384
|
validatorVote: PublicKey,
|
|
1332
|
-
lamports:
|
|
1385
|
+
lamports: AmountInput,
|
|
1333
1386
|
ephemeralStakeSeed?: number,
|
|
1334
1387
|
) {
|
|
1335
1388
|
const stakePool = await getStakePoolAccount(connection, stakePoolAddress)
|
|
@@ -1427,7 +1480,7 @@ export async function decreaseValidatorStake(
|
|
|
1427
1480
|
connection: Connection,
|
|
1428
1481
|
stakePoolAddress: PublicKey,
|
|
1429
1482
|
validatorVote: PublicKey,
|
|
1430
|
-
lamports:
|
|
1483
|
+
lamports: AmountInput,
|
|
1431
1484
|
ephemeralStakeSeed?: number,
|
|
1432
1485
|
) {
|
|
1433
1486
|
const stakePool = await getStakePoolAccount(connection, stakePoolAddress)
|