spl_stake_pool/
instruction.rs

1//! Instruction types
2
3// Remove the following `allow` when `Redelegate` is removed, required to avoid
4// warnings from uses of deprecated types during trait derivations.
5#![allow(deprecated)]
6#![allow(clippy::too_many_arguments)]
7
8use {
9    crate::{
10        find_deposit_authority_program_address, find_ephemeral_stake_program_address,
11        find_stake_program_address, find_transient_stake_program_address,
12        find_withdraw_authority_program_address,
13        inline_mpl_token_metadata::{self, pda::find_metadata_account},
14        state::{Fee, FeeType, StakePool, ValidatorList, ValidatorStakeInfo},
15        MAX_VALIDATORS_TO_UPDATE,
16    },
17    borsh::{BorshDeserialize, BorshSchema, BorshSerialize},
18    solana_program::{
19        instruction::{AccountMeta, Instruction},
20        program_error::ProgramError,
21        pubkey::Pubkey,
22        stake,
23        stake_history::Epoch,
24        system_program, sysvar,
25    },
26    std::num::NonZeroU32,
27};
28
29/// Defines which validator vote account is set during the
30/// `SetPreferredValidator` instruction
31#[repr(C)]
32#[derive(Clone, Debug, PartialEq, BorshSerialize, BorshDeserialize, BorshSchema)]
33pub enum PreferredValidatorType {
34    /// Set preferred validator for deposits
35    Deposit,
36    /// Set preferred validator for withdraws
37    Withdraw,
38}
39
40/// Defines which authority to update in the `SetFundingAuthority`
41/// instruction
42#[repr(C)]
43#[derive(Clone, Debug, PartialEq, BorshSerialize, BorshDeserialize, BorshSchema)]
44pub enum FundingType {
45    /// Sets the stake deposit authority
46    StakeDeposit,
47    /// Sets the SOL deposit authority
48    SolDeposit,
49    /// Sets the SOL withdraw authority
50    SolWithdraw,
51}
52
53/// Instructions supported by the `StakePool` program.
54#[repr(C)]
55#[derive(Clone, Debug, PartialEq, BorshSerialize, BorshDeserialize)]
56pub enum StakePoolInstruction {
57    ///   Initializes a new `StakePool`.
58    ///
59    ///   0. `[w]` New `StakePool` to create.
60    ///   1. `[s]` Manager
61    ///   2. `[]` Staker
62    ///   3. `[]` Stake pool withdraw authority
63    ///   4. `[w]` Uninitialized validator stake list storage account
64    ///   5. `[]` Reserve stake account must be initialized, have zero balance,
65    ///      and staker / withdrawer authority set to pool withdraw authority.
66    ///   6. `[]` Pool token mint. Must have zero supply, owned by withdraw
67    ///      authority.
68    ///   7. `[]` Pool account to deposit the generated fee for manager.
69    ///   8. `[]` Token program id
70    ///   9. `[]` (Optional) Deposit authority that must sign all deposits.
71    ///      Defaults to the program address generated using
72    ///      `find_deposit_authority_program_address`, making deposits
73    ///      permissionless.
74    Initialize {
75        /// Fee assessed as percentage of perceived rewards
76        fee: Fee,
77        /// Fee charged per withdrawal as percentage of withdrawal
78        withdrawal_fee: Fee,
79        /// Fee charged per deposit as percentage of deposit
80        deposit_fee: Fee,
81        /// Percentage [0-100] of `deposit_fee` that goes to referrer
82        referral_fee: u8,
83        /// Maximum expected number of validators
84        max_validators: u32,
85    },
86
87    ///   (Staker only) Adds stake account delegated to validator to the pool's
88    ///   list of managed validators.
89    ///
90    ///   The stake account will have the rent-exempt amount plus
91    ///   `max(
92    ///     crate::MINIMUM_ACTIVE_STAKE,
93    ///     solana_program::stake::tools::get_minimum_delegation()
94    ///   )`.
95    ///   It is funded from the stake pool reserve.
96    ///
97    ///   0. `[w]` Stake pool
98    ///   1. `[s]` Staker
99    ///   2. `[w]` Reserve stake account
100    ///   3. `[]` Stake pool withdraw authority
101    ///   4. `[w]` Validator stake list storage account
102    ///   5. `[w]` Stake account to add to the pool
103    ///   6. `[]` Validator this stake account will be delegated to
104    ///   7. `[]` Rent sysvar
105    ///   8. `[]` Clock sysvar
106    ///   9. '[]' Stake history sysvar
107    ///  10. '[]' Stake config sysvar
108    ///  11. `[]` System program
109    ///  12. `[]` Stake program
110    ///
111    ///  User data: optional non-zero `u32` seed used for generating the
112    ///  validator stake address
113    AddValidatorToPool(u32),
114
115    ///   (Staker only) Removes validator from the pool, deactivating its stake
116    ///
117    ///   Only succeeds if the validator stake account has the minimum of
118    ///   `max(crate::MINIMUM_ACTIVE_STAKE,
119    /// solana_program::stake::tools::get_minimum_delegation())`.   plus the
120    /// rent-exempt amount.
121    ///
122    ///   0. `[w]` Stake pool
123    ///   1. `[s]` Staker
124    ///   2. `[]` Stake pool withdraw authority
125    ///   3. `[w]` Validator stake list storage account
126    ///   4. `[w]` Stake account to remove from the pool
127    ///   5. `[w]` Transient stake account, to deactivate if necessary
128    ///   6. `[]` Sysvar clock
129    ///   7. `[]` Stake program id,
130    RemoveValidatorFromPool,
131
132    /// NOTE: This instruction has been deprecated since version 0.7.0. Please
133    /// use `DecreaseValidatorStakeWithReserve` instead.
134    ///
135    /// (Staker only) Decrease active stake on a validator, eventually moving it
136    /// to the reserve
137    ///
138    /// Internally, this instruction splits a validator stake account into its
139    /// corresponding transient stake account and deactivates it.
140    ///
141    /// In order to rebalance the pool without taking custody, the staker needs
142    /// a way of reducing the stake on a stake account. This instruction splits
143    /// some amount of stake, up to the total activated stake, from the
144    /// canonical validator stake account, into its "transient" stake
145    /// account.
146    ///
147    /// The instruction only succeeds if the transient stake account does not
148    /// exist. The amount of lamports to move must be at least rent-exemption
149    /// plus `max(crate::MINIMUM_ACTIVE_STAKE,
150    /// solana_program::stake::tools::get_minimum_delegation())`.
151    ///
152    ///  0. `[]` Stake pool
153    ///  1. `[s]` Stake pool staker
154    ///  2. `[]` Stake pool withdraw authority
155    ///  3. `[w]` Validator list
156    ///  4. `[w]` Canonical stake account to split from
157    ///  5. `[w]` Transient stake account to receive split
158    ///  6. `[]` Clock sysvar
159    ///  7. `[]` Rent sysvar
160    ///  8. `[]` System program
161    ///  9. `[]` Stake program
162    DecreaseValidatorStake {
163        /// amount of lamports to split into the transient stake account
164        lamports: u64,
165        /// seed used to create transient stake account
166        transient_stake_seed: u64,
167    },
168
169    /// (Staker only) Increase stake on a validator from the reserve account
170    ///
171    /// Internally, this instruction splits reserve stake into a transient stake
172    /// account and delegate to the appropriate validator.
173    /// `UpdateValidatorListBalance` will do the work of merging once it's
174    /// ready.
175    ///
176    /// This instruction only succeeds if the transient stake account does not
177    /// exist. The minimum amount to move is rent-exemption plus
178    /// `max(crate::MINIMUM_ACTIVE_STAKE,
179    /// solana_program::stake::tools::get_minimum_delegation())`.
180    ///
181    ///  0. `[]` Stake pool
182    ///  1. `[s]` Stake pool staker
183    ///  2. `[]` Stake pool withdraw authority
184    ///  3. `[w]` Validator list
185    ///  4. `[w]` Stake pool reserve stake
186    ///  5. `[w]` Transient stake account
187    ///  6. `[]` Validator stake account
188    ///  7. `[]` Validator vote account to delegate to
189    ///  8. '[]' Clock sysvar
190    ///  9. '[]' Rent sysvar
191    /// 10. `[]` Stake History sysvar
192    /// 11. `[]` Stake Config sysvar
193    /// 12. `[]` System program
194    /// 13. `[]` Stake program
195    ///
196    /// User data: amount of lamports to increase on the given validator.
197    ///
198    /// The actual amount split into the transient stake account is:
199    /// `lamports + stake_rent_exemption`.
200    ///
201    /// The rent-exemption of the stake account is withdrawn back to the
202    /// reserve after it is merged.
203    IncreaseValidatorStake {
204        /// amount of lamports to increase on the given validator
205        lamports: u64,
206        /// seed used to create transient stake account
207        transient_stake_seed: u64,
208    },
209
210    /// (Staker only) Set the preferred deposit or withdraw stake account for
211    /// the stake pool
212    ///
213    /// In order to avoid users abusing the stake pool as a free conversion
214    /// between SOL staked on different validators, the staker can force all
215    /// deposits and/or withdraws to go to one chosen account, or unset that
216    /// account.
217    ///
218    /// 0. `[w]` Stake pool
219    /// 1. `[s]` Stake pool staker
220    /// 2. `[]` Validator list
221    ///
222    /// Fails if the validator is not part of the stake pool.
223    SetPreferredValidator {
224        /// Affected operation (deposit or withdraw)
225        validator_type: PreferredValidatorType,
226        /// Validator vote account that deposits or withdraws must go through,
227        /// unset with None
228        validator_vote_address: Option<Pubkey>,
229    },
230
231    ///  Updates balances of validator and transient stake accounts in the pool
232    ///
233    ///  While going through the pairs of validator and transient stake
234    ///  accounts, if the transient stake is inactive, it is merged into the
235    ///  reserve stake account. If the transient stake is active and has
236    ///  matching credits observed, it is merged into the canonical
237    ///  validator stake account. In all other states, nothing is done, and
238    ///  the balance is simply added to the canonical stake account balance.
239    ///
240    ///  0. `[]` Stake pool
241    ///  1. `[]` Stake pool withdraw authority
242    ///  2. `[w]` Validator stake list storage account
243    ///  3. `[w]` Reserve stake account
244    ///  4. `[]` Sysvar clock
245    ///  5. `[]` Sysvar stake history
246    ///  6. `[]` Stake program
247    ///  7. `..7+2N` [] N pairs of validator and transient stake accounts
248    UpdateValidatorListBalance {
249        /// Index to start updating on the validator list
250        start_index: u32,
251        /// If true, don't try merging transient stake accounts into the reserve
252        /// or validator stake account.  Useful for testing or if a
253        /// particular stake account is in a bad state, but we still
254        /// want to update
255        no_merge: bool,
256    },
257
258    ///   Updates total pool balance based on balances in the reserve and
259    ///   validator list
260    ///
261    ///   0. `[w]` Stake pool
262    ///   1. `[]` Stake pool withdraw authority
263    ///   2. `[w]` Validator stake list storage account
264    ///   3. `[]` Reserve stake account
265    ///   4. `[w]` Account to receive pool fee tokens
266    ///   5. `[w]` Pool mint account
267    ///   6. `[]` Pool token program
268    UpdateStakePoolBalance,
269
270    ///   Cleans up validator stake account entries marked as `ReadyForRemoval`
271    ///
272    ///   0. `[]` Stake pool
273    ///   1. `[w]` Validator stake list storage account
274    CleanupRemovedValidatorEntries,
275
276    ///   Deposit some stake into the pool. The output is a "pool" token
277    ///   representing ownership into the pool. Inputs are converted to the
278    ///   current ratio.
279    ///
280    ///   0. `[w]` Stake pool
281    ///   1. `[w]` Validator stake list storage account
282    ///   2. `[s]/[]` Stake pool deposit authority
283    ///   3. `[]` Stake pool withdraw authority
284    ///   4. `[w]` Stake account to join the pool (withdraw authority for the
285    ///      stake account should be first set to the stake pool deposit
286    ///      authority)
287    ///   5. `[w]` Validator stake account for the stake account to be merged
288    ///      with
289    ///   6. `[w]` Reserve stake account, to withdraw rent exempt reserve
290    ///   7. `[w]` User account to receive pool tokens
291    ///   8. `[w]` Account to receive pool fee tokens
292    ///   9. `[w]` Account to receive a portion of pool fee tokens as referral
293    ///      fees
294    ///   10. `[w]` Pool token mint account
295    ///   11. '[]' Sysvar clock account
296    ///   12. '[]' Sysvar stake history account
297    ///   13. `[]` Pool token program id,
298    ///   14. `[]` Stake program id,
299    DepositStake,
300
301    ///   Withdraw the token from the pool at the current ratio.
302    ///
303    ///   Succeeds if the stake account has enough SOL to cover the desired
304    ///   amount of pool tokens, and if the withdrawal keeps the total
305    ///   staked amount above the minimum of rent-exempt amount plus `max(
306    ///     crate::MINIMUM_ACTIVE_STAKE,
307    ///     solana_program::stake::tools::get_minimum_delegation()
308    ///   )`.
309    ///
310    ///   When allowing withdrawals, the order of priority goes:
311    ///
312    ///   * preferred withdraw validator stake account (if set)
313    ///   * validator stake accounts
314    ///   * transient stake accounts
315    ///   * reserve stake account OR totally remove validator stake accounts
316    ///
317    ///   A user can freely withdraw from a validator stake account, and if they
318    ///   are all at the minimum, then they can withdraw from transient stake
319    ///   accounts, and if they are all at minimum, then they can withdraw from
320    ///   the reserve or remove any validator from the pool.
321    ///
322    ///   0. `[w]` Stake pool
323    ///   1. `[w]` Validator stake list storage account
324    ///   2. `[]` Stake pool withdraw authority
325    ///   3. `[w]` Validator or reserve stake account to split
326    ///   4. `[w]` Uninitialized stake account to receive withdrawal
327    ///   5. `[]` User account to set as a new withdraw authority
328    ///   6. `[s]` User transfer authority, for pool token account
329    ///   7. `[w]` User account with pool tokens to burn from
330    ///   8. `[w]` Account to receive pool fee tokens
331    ///   9. `[w]` Pool token mint account
332    ///  10. `[]` Sysvar clock account (required)
333    ///  11. `[]` Pool token program id
334    ///  12. `[]` Stake program id,
335    ///
336    ///  User data: amount of pool tokens to withdraw
337    WithdrawStake(u64),
338
339    ///  (Manager only) Update manager
340    ///
341    ///  0. `[w]` Stake pool
342    ///  1. `[s]` Manager
343    ///  2. `[s]` New manager
344    ///  3. `[]` New manager fee account
345    SetManager,
346
347    ///  (Manager only) Update fee
348    ///
349    ///  0. `[w]` Stake pool
350    ///  1. `[s]` Manager
351    SetFee {
352        /// Type of fee to update and value to update it to
353        fee: FeeType,
354    },
355
356    ///  (Manager or staker only) Update staker
357    ///
358    ///  0. `[w]` Stake pool
359    ///  1. `[s]` Manager or current staker
360    ///  2. '[]` New staker pubkey
361    SetStaker,
362
363    ///   Deposit SOL directly into the pool's reserve account. The output is a
364    ///   "pool" token representing ownership into the pool. Inputs are
365    ///   converted to the current ratio.
366    ///
367    ///   0. `[w]` Stake pool
368    ///   1. `[]` Stake pool withdraw authority
369    ///   2. `[w]` Reserve stake account, to deposit SOL
370    ///   3. `[s]` Account providing the lamports to be deposited into the pool
371    ///   4. `[w]` User account to receive pool tokens
372    ///   5. `[w]` Account to receive fee tokens
373    ///   6. `[w]` Account to receive a portion of fee as referral fees
374    ///   7. `[w]` Pool token mint account
375    ///   8. `[]` System program account
376    ///   9. `[]` Token program id
377    ///  10. `[s]` (Optional) Stake pool sol deposit authority.
378    DepositSol(u64),
379
380    ///  (Manager only) Update SOL deposit, stake deposit, or SOL withdrawal
381    /// authority.
382    ///
383    ///  0. `[w]` Stake pool
384    ///  1. `[s]` Manager
385    ///  2. '[]` New authority pubkey or none
386    SetFundingAuthority(FundingType),
387
388    ///   Withdraw SOL directly from the pool's reserve account. Fails if the
389    ///   reserve does not have enough SOL.
390    ///
391    ///   0. `[w]` Stake pool
392    ///   1. `[]` Stake pool withdraw authority
393    ///   2. `[s]` User transfer authority, for pool token account
394    ///   3. `[w]` User account to burn pool tokens
395    ///   4. `[w]` Reserve stake account, to withdraw SOL
396    ///   5. `[w]` Account receiving the lamports from the reserve, must be a
397    ///      system account
398    ///   6. `[w]` Account to receive pool fee tokens
399    ///   7. `[w]` Pool token mint account
400    ///   8. '[]' Clock sysvar
401    ///   9. '[]' Stake history sysvar
402    ///  10. `[]` Stake program account
403    ///  11. `[]` Token program id
404    ///  12. `[s]` (Optional) Stake pool sol withdraw authority
405    WithdrawSol(u64),
406
407    /// Create token metadata for the stake-pool token in the
408    /// metaplex-token program
409    /// 0. `[]` Stake pool
410    /// 1. `[s]` Manager
411    /// 2. `[]` Stake pool withdraw authority
412    /// 3. `[]` Pool token mint account
413    /// 4. `[s, w]` Payer for creation of token metadata account
414    /// 5. `[w]` Token metadata account
415    /// 6. `[]` Metadata program id
416    /// 7. `[]` System program id
417    CreateTokenMetadata {
418        /// Token name
419        name: String,
420        /// Token symbol e.g. `stkSOL`
421        symbol: String,
422        /// URI of the uploaded metadata of the spl-token
423        uri: String,
424    },
425    /// Update token metadata for the stake-pool token in the
426    /// metaplex-token program
427    ///
428    /// 0. `[]` Stake pool
429    /// 1. `[s]` Manager
430    /// 2. `[]` Stake pool withdraw authority
431    /// 3. `[w]` Token metadata account
432    /// 4. `[]` Metadata program id
433    UpdateTokenMetadata {
434        /// Token name
435        name: String,
436        /// Token symbol e.g. `stkSOL`
437        symbol: String,
438        /// URI of the uploaded metadata of the spl-token
439        uri: String,
440    },
441
442    /// (Staker only) Increase stake on a validator again in an epoch.
443    ///
444    /// Works regardless if the transient stake account exists.
445    ///
446    /// Internally, this instruction splits reserve stake into an ephemeral
447    /// stake account, activates it, then merges or splits it into the
448    /// transient stake account delegated to the appropriate validator.
449    /// `UpdateValidatorListBalance` will do the work of merging once it's
450    /// ready.
451    ///
452    /// The minimum amount to move is rent-exemption plus
453    /// `max(crate::MINIMUM_ACTIVE_STAKE,
454    /// solana_program::stake::tools::get_minimum_delegation())`.
455    ///
456    ///  0. `[]` Stake pool
457    ///  1. `[s]` Stake pool staker
458    ///  2. `[]` Stake pool withdraw authority
459    ///  3. `[w]` Validator list
460    ///  4. `[w]` Stake pool reserve stake
461    ///  5. `[w]` Uninitialized ephemeral stake account to receive stake
462    ///  6. `[w]` Transient stake account
463    ///  7. `[]` Validator stake account
464    ///  8. `[]` Validator vote account to delegate to
465    ///  9. '[]' Clock sysvar
466    /// 10. `[]` Stake History sysvar
467    /// 11. `[]` Stake Config sysvar
468    /// 12. `[]` System program
469    /// 13. `[]` Stake program
470    ///
471    /// User data: amount of lamports to increase on the given validator.
472    ///
473    /// The actual amount split into the transient stake account is:
474    /// `lamports + stake_rent_exemption`.
475    ///
476    /// The rent-exemption of the stake account is withdrawn back to the
477    /// reserve after it is merged.
478    IncreaseAdditionalValidatorStake {
479        /// amount of lamports to increase on the given validator
480        lamports: u64,
481        /// seed used to create transient stake account
482        transient_stake_seed: u64,
483        /// seed used to create ephemeral account.
484        ephemeral_stake_seed: u64,
485    },
486
487    /// (Staker only) Decrease active stake again from a validator, eventually
488    /// moving it to the reserve
489    ///
490    /// Works regardless if the transient stake account already exists.
491    ///
492    /// Internally, this instruction:
493    ///  * withdraws rent-exempt reserve lamports from the reserve into the
494    ///    ephemeral stake
495    ///  * splits a validator stake account into an ephemeral stake account
496    ///  * deactivates the ephemeral account
497    ///  * merges or splits the ephemeral account into the transient stake
498    ///    account delegated to the appropriate validator
499    ///
500    ///  The amount of lamports to move must be at least
501    /// `max(crate::MINIMUM_ACTIVE_STAKE,
502    /// solana_program::stake::tools::get_minimum_delegation())`.
503    ///
504    ///  0. `[]` Stake pool
505    ///  1. `[s]` Stake pool staker
506    ///  2. `[]` Stake pool withdraw authority
507    ///  3. `[w]` Validator list
508    ///  4. `[w]` Reserve stake account, to fund rent exempt reserve
509    ///  5. `[w]` Canonical stake account to split from
510    ///  6. `[w]` Uninitialized ephemeral stake account to receive stake
511    ///  7. `[w]` Transient stake account
512    ///  8. `[]` Clock sysvar
513    ///  9. '[]' Stake history sysvar
514    /// 10. `[]` System program
515    /// 11. `[]` Stake program
516    DecreaseAdditionalValidatorStake {
517        /// amount of lamports to split into the transient stake account
518        lamports: u64,
519        /// seed used to create transient stake account
520        transient_stake_seed: u64,
521        /// seed used to create ephemeral account.
522        ephemeral_stake_seed: u64,
523    },
524
525    /// (Staker only) Decrease active stake on a validator, eventually moving it
526    /// to the reserve
527    ///
528    /// Internally, this instruction:
529    /// * withdraws enough lamports to make the transient account rent-exempt
530    /// * splits from a validator stake account into a transient stake account
531    /// * deactivates the transient stake account
532    ///
533    /// In order to rebalance the pool without taking custody, the staker needs
534    /// a way of reducing the stake on a stake account. This instruction splits
535    /// some amount of stake, up to the total activated stake, from the
536    /// canonical validator stake account, into its "transient" stake
537    /// account.
538    ///
539    /// The instruction only succeeds if the transient stake account does not
540    /// exist. The amount of lamports to move must be at least rent-exemption
541    /// plus `max(crate::MINIMUM_ACTIVE_STAKE,
542    /// solana_program::stake::tools::get_minimum_delegation())`.
543    ///
544    ///  0. `[]` Stake pool
545    ///  1. `[s]` Stake pool staker
546    ///  2. `[]` Stake pool withdraw authority
547    ///  3. `[w]` Validator list
548    ///  4. `[w]` Reserve stake account, to fund rent exempt reserve
549    ///  5. `[w]` Canonical stake account to split from
550    ///  6. `[w]` Transient stake account to receive split
551    ///  7. `[]` Clock sysvar
552    ///  8. '[]' Stake history sysvar
553    ///  9. `[]` System program
554    /// 10. `[]` Stake program
555    DecreaseValidatorStakeWithReserve {
556        /// amount of lamports to split into the transient stake account
557        lamports: u64,
558        /// seed used to create transient stake account
559        transient_stake_seed: u64,
560    },
561
562    /// (Staker only) Redelegate active stake on a validator, eventually moving
563    /// it to another
564    ///
565    /// Internally, this instruction splits a validator stake account into its
566    /// corresponding transient stake account, redelegates it to an ephemeral
567    /// stake account, then merges that stake into the destination transient
568    /// stake account.
569    ///
570    /// In order to rebalance the pool without taking custody, the staker needs
571    /// a way of reducing the stake on a stake account. This instruction splits
572    /// some amount of stake, up to the total activated stake, from the
573    /// canonical validator stake account, into its "transient" stake
574    /// account.
575    ///
576    /// The instruction only succeeds if the source transient stake account and
577    /// ephemeral stake account do not exist.
578    ///
579    /// The amount of lamports to move must be at least rent-exemption plus the
580    /// minimum delegation amount. Rent-exemption plus minimum delegation
581    /// is required for the destination ephemeral stake account.
582    ///
583    /// The rent-exemption for the source transient account comes from the stake
584    /// pool reserve, if needed.
585    ///
586    /// The amount that arrives at the destination validator in the end is
587    /// `redelegate_lamports - rent_exemption` if the destination transient
588    /// account does *not* exist, and `redelegate_lamports` if the destination
589    /// transient account already exists. The `rent_exemption` is not activated
590    /// when creating the destination transient stake account, but if it already
591    /// exists, then the full amount is delegated.
592    ///
593    ///  0. `[]` Stake pool
594    ///  1. `[s]` Stake pool staker
595    ///  2. `[]` Stake pool withdraw authority
596    ///  3. `[w]` Validator list
597    ///  4. `[w]` Reserve stake account, to withdraw rent exempt reserve
598    ///  5. `[w]` Source canonical stake account to split from
599    ///  6. `[w]` Source transient stake account to receive split and be
600    ///     redelegated
601    ///  7. `[w]` Uninitialized ephemeral stake account to receive redelegation
602    ///  8. `[w]` Destination transient stake account to receive ephemeral stake
603    ///     by merge
604    ///  9. `[]` Destination stake account to receive transient stake after
605    ///     activation
606    /// 10. `[]` Destination validator vote account
607    /// 11. `[]` Clock sysvar
608    /// 12. `[]` Stake History sysvar
609    /// 13. `[]` Stake Config sysvar
610    /// 14. `[]` System program
611    /// 15. `[]` Stake program
612    #[deprecated(
613        since = "2.0.0",
614        note = "The stake redelegate instruction used in this will not be enabled."
615    )]
616    Redelegate {
617        /// Amount of lamports to redelegate
618        #[allow(dead_code)] // but it's not
619        lamports: u64,
620        /// Seed used to create source transient stake account
621        #[allow(dead_code)] // but it's not
622        source_transient_stake_seed: u64,
623        /// Seed used to create destination ephemeral account.
624        #[allow(dead_code)] // but it's not
625        ephemeral_stake_seed: u64,
626        /// Seed used to create destination transient stake account. If there is
627        /// already transient stake, this must match the current seed, otherwise
628        /// it can be anything
629        #[allow(dead_code)] // but it's not
630        destination_transient_stake_seed: u64,
631    },
632
633    ///   Deposit some stake into the pool, with a specified slippage
634    ///   constraint. The output is a "pool" token representing ownership
635    ///   into the pool. Inputs are converted at the current ratio.
636    ///
637    ///   0. `[w]` Stake pool
638    ///   1. `[w]` Validator stake list storage account
639    ///   2. `[s]/[]` Stake pool deposit authority
640    ///   3. `[]` Stake pool withdraw authority
641    ///   4. `[w]` Stake account to join the pool (withdraw authority for the
642    ///      stake account should be first set to the stake pool deposit
643    ///      authority)
644    ///   5. `[w]` Validator stake account for the stake account to be merged
645    ///      with
646    ///   6. `[w]` Reserve stake account, to withdraw rent exempt reserve
647    ///   7. `[w]` User account to receive pool tokens
648    ///   8. `[w]` Account to receive pool fee tokens
649    ///   9. `[w]` Account to receive a portion of pool fee tokens as referral
650    ///      fees
651    ///   10. `[w]` Pool token mint account
652    ///   11. '[]' Sysvar clock account
653    ///   12. '[]' Sysvar stake history account
654    ///   13. `[]` Pool token program id,
655    ///   14. `[]` Stake program id,
656    DepositStakeWithSlippage {
657        /// Minimum amount of pool tokens that must be received
658        minimum_pool_tokens_out: u64,
659    },
660
661    ///   Withdraw the token from the pool at the current ratio, specifying a
662    ///   minimum expected output lamport amount.
663    ///
664    ///   Succeeds if the stake account has enough SOL to cover the desired
665    ///   amount of pool tokens, and if the withdrawal keeps the total
666    ///   staked amount above the minimum of rent-exempt amount plus `max(
667    ///     crate::MINIMUM_ACTIVE_STAKE,
668    ///     solana_program::stake::tools::get_minimum_delegation()
669    ///   )`.
670    ///
671    ///   0. `[w]` Stake pool
672    ///   1. `[w]` Validator stake list storage account
673    ///   2. `[]` Stake pool withdraw authority
674    ///   3. `[w]` Validator or reserve stake account to split
675    ///   4. `[w]` Uninitialized stake account to receive withdrawal
676    ///   5. `[]` User account to set as a new withdraw authority
677    ///   6. `[s]` User transfer authority, for pool token account
678    ///   7. `[w]` User account with pool tokens to burn from
679    ///   8. `[w]` Account to receive pool fee tokens
680    ///   9. `[w]` Pool token mint account
681    ///  10. `[]` Sysvar clock account (required)
682    ///  11. `[]` Pool token program id
683    ///  12. `[]` Stake program id,
684    ///
685    ///  User data: amount of pool tokens to withdraw
686    WithdrawStakeWithSlippage {
687        /// Pool tokens to burn in exchange for lamports
688        pool_tokens_in: u64,
689        /// Minimum amount of lamports that must be received
690        minimum_lamports_out: u64,
691    },
692
693    ///   Deposit SOL directly into the pool's reserve account, with a
694    ///   specified slippage constraint. The output is a "pool" token
695    ///   representing ownership into the pool. Inputs are converted at the
696    ///   current ratio.
697    ///
698    ///   0. `[w]` Stake pool
699    ///   1. `[]` Stake pool withdraw authority
700    ///   2. `[w]` Reserve stake account, to deposit SOL
701    ///   3. `[s]` Account providing the lamports to be deposited into the pool
702    ///   4. `[w]` User account to receive pool tokens
703    ///   5. `[w]` Account to receive fee tokens
704    ///   6. `[w]` Account to receive a portion of fee as referral fees
705    ///   7. `[w]` Pool token mint account
706    ///   8. `[]` System program account
707    ///   9. `[]` Token program id
708    ///  10. `[s]` (Optional) Stake pool sol deposit authority.
709    DepositSolWithSlippage {
710        /// Amount of lamports to deposit into the reserve
711        lamports_in: u64,
712        /// Minimum amount of pool tokens that must be received
713        minimum_pool_tokens_out: u64,
714    },
715
716    ///   Withdraw SOL directly from the pool's reserve account. Fails if the
717    ///   reserve does not have enough SOL or if the slippage constraint is not
718    ///   met.
719    ///
720    ///   0. `[w]` Stake pool
721    ///   1. `[]` Stake pool withdraw authority
722    ///   2. `[s]` User transfer authority, for pool token account
723    ///   3. `[w]` User account to burn pool tokens
724    ///   4. `[w]` Reserve stake account, to withdraw SOL
725    ///   5. `[w]` Account receiving the lamports from the reserve, must be a
726    ///      system account
727    ///   6. `[w]` Account to receive pool fee tokens
728    ///   7. `[w]` Pool token mint account
729    ///   8. '[]' Clock sysvar
730    ///   9. '[]' Stake history sysvar
731    ///  10. `[]` Stake program account
732    ///  11. `[]` Token program id
733    ///  12. `[s]` (Optional) Stake pool sol withdraw authority
734    WithdrawSolWithSlippage {
735        /// Pool tokens to burn in exchange for lamports
736        pool_tokens_in: u64,
737        /// Minimum amount of lamports that must be received
738        minimum_lamports_out: u64,
739    },
740}
741
742/// Creates an `Initialize` instruction.
743pub fn initialize(
744    program_id: &Pubkey,
745    stake_pool: &Pubkey,
746    manager: &Pubkey,
747    staker: &Pubkey,
748    stake_pool_withdraw_authority: &Pubkey,
749    validator_list: &Pubkey,
750    reserve_stake: &Pubkey,
751    pool_mint: &Pubkey,
752    manager_pool_account: &Pubkey,
753    token_program_id: &Pubkey,
754    deposit_authority: Option<Pubkey>,
755    fee: Fee,
756    withdrawal_fee: Fee,
757    deposit_fee: Fee,
758    referral_fee: u8,
759    max_validators: u32,
760) -> Instruction {
761    let init_data = StakePoolInstruction::Initialize {
762        fee,
763        withdrawal_fee,
764        deposit_fee,
765        referral_fee,
766        max_validators,
767    };
768    let data = borsh::to_vec(&init_data).unwrap();
769    let mut accounts = vec![
770        AccountMeta::new(*stake_pool, false),
771        AccountMeta::new_readonly(*manager, true),
772        AccountMeta::new_readonly(*staker, false),
773        AccountMeta::new_readonly(*stake_pool_withdraw_authority, false),
774        AccountMeta::new(*validator_list, false),
775        AccountMeta::new_readonly(*reserve_stake, false),
776        AccountMeta::new(*pool_mint, false),
777        AccountMeta::new(*manager_pool_account, false),
778        AccountMeta::new_readonly(*token_program_id, false),
779    ];
780    if let Some(deposit_authority) = deposit_authority {
781        accounts.push(AccountMeta::new_readonly(deposit_authority, true));
782    }
783    Instruction {
784        program_id: *program_id,
785        accounts,
786        data,
787    }
788}
789
790/// Creates `AddValidatorToPool` instruction (add new validator stake account to
791/// the pool)
792pub fn add_validator_to_pool(
793    program_id: &Pubkey,
794    stake_pool: &Pubkey,
795    staker: &Pubkey,
796    reserve: &Pubkey,
797    stake_pool_withdraw: &Pubkey,
798    validator_list: &Pubkey,
799    stake: &Pubkey,
800    validator: &Pubkey,
801    seed: Option<NonZeroU32>,
802) -> Instruction {
803    let accounts = vec![
804        AccountMeta::new(*stake_pool, false),
805        AccountMeta::new_readonly(*staker, true),
806        AccountMeta::new(*reserve, false),
807        AccountMeta::new_readonly(*stake_pool_withdraw, false),
808        AccountMeta::new(*validator_list, false),
809        AccountMeta::new(*stake, false),
810        AccountMeta::new_readonly(*validator, false),
811        AccountMeta::new_readonly(sysvar::rent::id(), false),
812        AccountMeta::new_readonly(sysvar::clock::id(), false),
813        AccountMeta::new_readonly(sysvar::stake_history::id(), false),
814        #[allow(deprecated)]
815        AccountMeta::new_readonly(stake::config::id(), false),
816        AccountMeta::new_readonly(system_program::id(), false),
817        AccountMeta::new_readonly(stake::program::id(), false),
818    ];
819    let data = borsh::to_vec(&StakePoolInstruction::AddValidatorToPool(
820        seed.map(|s| s.get()).unwrap_or(0),
821    ))
822    .unwrap();
823    Instruction {
824        program_id: *program_id,
825        accounts,
826        data,
827    }
828}
829
830/// Creates `RemoveValidatorFromPool` instruction (remove validator stake
831/// account from the pool)
832pub fn remove_validator_from_pool(
833    program_id: &Pubkey,
834    stake_pool: &Pubkey,
835    staker: &Pubkey,
836    stake_pool_withdraw: &Pubkey,
837    validator_list: &Pubkey,
838    stake_account: &Pubkey,
839    transient_stake_account: &Pubkey,
840) -> Instruction {
841    let accounts = vec![
842        AccountMeta::new(*stake_pool, false),
843        AccountMeta::new_readonly(*staker, true),
844        AccountMeta::new_readonly(*stake_pool_withdraw, false),
845        AccountMeta::new(*validator_list, false),
846        AccountMeta::new(*stake_account, false),
847        AccountMeta::new(*transient_stake_account, false),
848        AccountMeta::new_readonly(sysvar::clock::id(), false),
849        AccountMeta::new_readonly(stake::program::id(), false),
850    ];
851    Instruction {
852        program_id: *program_id,
853        accounts,
854        data: borsh::to_vec(&StakePoolInstruction::RemoveValidatorFromPool).unwrap(),
855    }
856}
857
858/// Creates `DecreaseValidatorStake` instruction (rebalance from validator
859/// account to transient account)
860#[deprecated(
861    since = "0.7.0",
862    note = "please use `decrease_validator_stake_with_reserve`"
863)]
864pub fn decrease_validator_stake(
865    program_id: &Pubkey,
866    stake_pool: &Pubkey,
867    staker: &Pubkey,
868    stake_pool_withdraw_authority: &Pubkey,
869    validator_list: &Pubkey,
870    validator_stake: &Pubkey,
871    transient_stake: &Pubkey,
872    lamports: u64,
873    transient_stake_seed: u64,
874) -> Instruction {
875    let accounts = vec![
876        AccountMeta::new_readonly(*stake_pool, false),
877        AccountMeta::new_readonly(*staker, true),
878        AccountMeta::new_readonly(*stake_pool_withdraw_authority, false),
879        AccountMeta::new(*validator_list, false),
880        AccountMeta::new(*validator_stake, false),
881        AccountMeta::new(*transient_stake, false),
882        AccountMeta::new_readonly(sysvar::clock::id(), false),
883        AccountMeta::new_readonly(sysvar::rent::id(), false),
884        AccountMeta::new_readonly(system_program::id(), false),
885        AccountMeta::new_readonly(stake::program::id(), false),
886    ];
887    Instruction {
888        program_id: *program_id,
889        accounts,
890        data: borsh::to_vec(&StakePoolInstruction::DecreaseValidatorStake {
891            lamports,
892            transient_stake_seed,
893        })
894        .unwrap(),
895    }
896}
897
898/// Creates `DecreaseAdditionalValidatorStake` instruction (rebalance from
899/// validator account to transient account)
900pub fn decrease_additional_validator_stake(
901    program_id: &Pubkey,
902    stake_pool: &Pubkey,
903    staker: &Pubkey,
904    stake_pool_withdraw_authority: &Pubkey,
905    validator_list: &Pubkey,
906    reserve_stake: &Pubkey,
907    validator_stake: &Pubkey,
908    ephemeral_stake: &Pubkey,
909    transient_stake: &Pubkey,
910    lamports: u64,
911    transient_stake_seed: u64,
912    ephemeral_stake_seed: u64,
913) -> Instruction {
914    let accounts = vec![
915        AccountMeta::new_readonly(*stake_pool, false),
916        AccountMeta::new_readonly(*staker, true),
917        AccountMeta::new_readonly(*stake_pool_withdraw_authority, false),
918        AccountMeta::new(*validator_list, false),
919        AccountMeta::new(*reserve_stake, false),
920        AccountMeta::new(*validator_stake, false),
921        AccountMeta::new(*ephemeral_stake, false),
922        AccountMeta::new(*transient_stake, false),
923        AccountMeta::new_readonly(sysvar::clock::id(), false),
924        AccountMeta::new_readonly(sysvar::stake_history::id(), false),
925        AccountMeta::new_readonly(system_program::id(), false),
926        AccountMeta::new_readonly(stake::program::id(), false),
927    ];
928    Instruction {
929        program_id: *program_id,
930        accounts,
931        data: borsh::to_vec(&StakePoolInstruction::DecreaseAdditionalValidatorStake {
932            lamports,
933            transient_stake_seed,
934            ephemeral_stake_seed,
935        })
936        .unwrap(),
937    }
938}
939
940/// Creates `DecreaseValidatorStakeWithReserve` instruction (rebalance from
941/// validator account to transient account)
942pub fn decrease_validator_stake_with_reserve(
943    program_id: &Pubkey,
944    stake_pool: &Pubkey,
945    staker: &Pubkey,
946    stake_pool_withdraw_authority: &Pubkey,
947    validator_list: &Pubkey,
948    reserve_stake: &Pubkey,
949    validator_stake: &Pubkey,
950    transient_stake: &Pubkey,
951    lamports: u64,
952    transient_stake_seed: u64,
953) -> Instruction {
954    let accounts = vec![
955        AccountMeta::new_readonly(*stake_pool, false),
956        AccountMeta::new_readonly(*staker, true),
957        AccountMeta::new_readonly(*stake_pool_withdraw_authority, false),
958        AccountMeta::new(*validator_list, false),
959        AccountMeta::new(*reserve_stake, false),
960        AccountMeta::new(*validator_stake, false),
961        AccountMeta::new(*transient_stake, false),
962        AccountMeta::new_readonly(sysvar::clock::id(), false),
963        AccountMeta::new_readonly(sysvar::stake_history::id(), false),
964        AccountMeta::new_readonly(system_program::id(), false),
965        AccountMeta::new_readonly(stake::program::id(), false),
966    ];
967    Instruction {
968        program_id: *program_id,
969        accounts,
970        data: borsh::to_vec(&StakePoolInstruction::DecreaseValidatorStakeWithReserve {
971            lamports,
972            transient_stake_seed,
973        })
974        .unwrap(),
975    }
976}
977
978/// Creates `IncreaseValidatorStake` instruction (rebalance from reserve account
979/// to transient account)
980pub fn increase_validator_stake(
981    program_id: &Pubkey,
982    stake_pool: &Pubkey,
983    staker: &Pubkey,
984    stake_pool_withdraw_authority: &Pubkey,
985    validator_list: &Pubkey,
986    reserve_stake: &Pubkey,
987    transient_stake: &Pubkey,
988    validator_stake: &Pubkey,
989    validator: &Pubkey,
990    lamports: u64,
991    transient_stake_seed: u64,
992) -> Instruction {
993    let accounts = vec![
994        AccountMeta::new_readonly(*stake_pool, false),
995        AccountMeta::new_readonly(*staker, true),
996        AccountMeta::new_readonly(*stake_pool_withdraw_authority, false),
997        AccountMeta::new(*validator_list, false),
998        AccountMeta::new(*reserve_stake, false),
999        AccountMeta::new(*transient_stake, false),
1000        AccountMeta::new_readonly(*validator_stake, false),
1001        AccountMeta::new_readonly(*validator, false),
1002        AccountMeta::new_readonly(sysvar::clock::id(), false),
1003        AccountMeta::new_readonly(sysvar::rent::id(), false),
1004        AccountMeta::new_readonly(sysvar::stake_history::id(), false),
1005        #[allow(deprecated)]
1006        AccountMeta::new_readonly(stake::config::id(), false),
1007        AccountMeta::new_readonly(system_program::id(), false),
1008        AccountMeta::new_readonly(stake::program::id(), false),
1009    ];
1010    Instruction {
1011        program_id: *program_id,
1012        accounts,
1013        data: borsh::to_vec(&StakePoolInstruction::IncreaseValidatorStake {
1014            lamports,
1015            transient_stake_seed,
1016        })
1017        .unwrap(),
1018    }
1019}
1020
1021/// Creates `IncreaseAdditionalValidatorStake` instruction (rebalance from
1022/// reserve account to transient account)
1023pub fn increase_additional_validator_stake(
1024    program_id: &Pubkey,
1025    stake_pool: &Pubkey,
1026    staker: &Pubkey,
1027    stake_pool_withdraw_authority: &Pubkey,
1028    validator_list: &Pubkey,
1029    reserve_stake: &Pubkey,
1030    ephemeral_stake: &Pubkey,
1031    transient_stake: &Pubkey,
1032    validator_stake: &Pubkey,
1033    validator: &Pubkey,
1034    lamports: u64,
1035    transient_stake_seed: u64,
1036    ephemeral_stake_seed: u64,
1037) -> Instruction {
1038    let accounts = vec![
1039        AccountMeta::new_readonly(*stake_pool, false),
1040        AccountMeta::new_readonly(*staker, true),
1041        AccountMeta::new_readonly(*stake_pool_withdraw_authority, false),
1042        AccountMeta::new(*validator_list, false),
1043        AccountMeta::new(*reserve_stake, false),
1044        AccountMeta::new(*ephemeral_stake, false),
1045        AccountMeta::new(*transient_stake, false),
1046        AccountMeta::new_readonly(*validator_stake, false),
1047        AccountMeta::new_readonly(*validator, false),
1048        AccountMeta::new_readonly(sysvar::clock::id(), false),
1049        AccountMeta::new_readonly(sysvar::stake_history::id(), false),
1050        #[allow(deprecated)]
1051        AccountMeta::new_readonly(stake::config::id(), false),
1052        AccountMeta::new_readonly(system_program::id(), false),
1053        AccountMeta::new_readonly(stake::program::id(), false),
1054    ];
1055    Instruction {
1056        program_id: *program_id,
1057        accounts,
1058        data: borsh::to_vec(&StakePoolInstruction::IncreaseAdditionalValidatorStake {
1059            lamports,
1060            transient_stake_seed,
1061            ephemeral_stake_seed,
1062        })
1063        .unwrap(),
1064    }
1065}
1066
1067/// Creates `Redelegate` instruction (rebalance from one validator account to
1068/// another)
1069#[deprecated(
1070    since = "2.0.0",
1071    note = "The stake redelegate instruction used in this will not be enabled."
1072)]
1073pub fn redelegate(
1074    program_id: &Pubkey,
1075    stake_pool: &Pubkey,
1076    staker: &Pubkey,
1077    stake_pool_withdraw_authority: &Pubkey,
1078    validator_list: &Pubkey,
1079    reserve_stake: &Pubkey,
1080    source_validator_stake: &Pubkey,
1081    source_transient_stake: &Pubkey,
1082    ephemeral_stake: &Pubkey,
1083    destination_transient_stake: &Pubkey,
1084    destination_validator_stake: &Pubkey,
1085    validator: &Pubkey,
1086    lamports: u64,
1087    source_transient_stake_seed: u64,
1088    ephemeral_stake_seed: u64,
1089    destination_transient_stake_seed: u64,
1090) -> Instruction {
1091    let accounts = vec![
1092        AccountMeta::new_readonly(*stake_pool, false),
1093        AccountMeta::new_readonly(*staker, true),
1094        AccountMeta::new_readonly(*stake_pool_withdraw_authority, false),
1095        AccountMeta::new(*validator_list, false),
1096        AccountMeta::new(*reserve_stake, false),
1097        AccountMeta::new(*source_validator_stake, false),
1098        AccountMeta::new(*source_transient_stake, false),
1099        AccountMeta::new(*ephemeral_stake, false),
1100        AccountMeta::new(*destination_transient_stake, false),
1101        AccountMeta::new_readonly(*destination_validator_stake, false),
1102        AccountMeta::new_readonly(*validator, false),
1103        AccountMeta::new_readonly(sysvar::clock::id(), false),
1104        AccountMeta::new_readonly(sysvar::stake_history::id(), false),
1105        #[allow(deprecated)]
1106        AccountMeta::new_readonly(stake::config::id(), false),
1107        AccountMeta::new_readonly(system_program::id(), false),
1108        AccountMeta::new_readonly(stake::program::id(), false),
1109    ];
1110    Instruction {
1111        program_id: *program_id,
1112        accounts,
1113        data: borsh::to_vec(&StakePoolInstruction::Redelegate {
1114            lamports,
1115            source_transient_stake_seed,
1116            ephemeral_stake_seed,
1117            destination_transient_stake_seed,
1118        })
1119        .unwrap(),
1120    }
1121}
1122
1123/// Creates `SetPreferredDepositValidator` instruction
1124pub fn set_preferred_validator(
1125    program_id: &Pubkey,
1126    stake_pool_address: &Pubkey,
1127    staker: &Pubkey,
1128    validator_list_address: &Pubkey,
1129    validator_type: PreferredValidatorType,
1130    validator_vote_address: Option<Pubkey>,
1131) -> Instruction {
1132    Instruction {
1133        program_id: *program_id,
1134        accounts: vec![
1135            AccountMeta::new(*stake_pool_address, false),
1136            AccountMeta::new_readonly(*staker, true),
1137            AccountMeta::new_readonly(*validator_list_address, false),
1138        ],
1139        data: borsh::to_vec(&StakePoolInstruction::SetPreferredValidator {
1140            validator_type,
1141            validator_vote_address,
1142        })
1143        .unwrap(),
1144    }
1145}
1146
1147/// Create an `AddValidatorToPool` instruction given an existing stake pool and
1148/// vote account
1149pub fn add_validator_to_pool_with_vote(
1150    program_id: &Pubkey,
1151    stake_pool: &StakePool,
1152    stake_pool_address: &Pubkey,
1153    vote_account_address: &Pubkey,
1154    seed: Option<NonZeroU32>,
1155) -> Instruction {
1156    let pool_withdraw_authority =
1157        find_withdraw_authority_program_address(program_id, stake_pool_address).0;
1158    let (stake_account_address, _) =
1159        find_stake_program_address(program_id, vote_account_address, stake_pool_address, seed);
1160    add_validator_to_pool(
1161        program_id,
1162        stake_pool_address,
1163        &stake_pool.staker,
1164        &stake_pool.reserve_stake,
1165        &pool_withdraw_authority,
1166        &stake_pool.validator_list,
1167        &stake_account_address,
1168        vote_account_address,
1169        seed,
1170    )
1171}
1172
1173/// Create an `RemoveValidatorFromPool` instruction given an existing stake pool
1174/// and vote account
1175pub fn remove_validator_from_pool_with_vote(
1176    program_id: &Pubkey,
1177    stake_pool: &StakePool,
1178    stake_pool_address: &Pubkey,
1179    vote_account_address: &Pubkey,
1180    validator_stake_seed: Option<NonZeroU32>,
1181    transient_stake_seed: u64,
1182) -> Instruction {
1183    let pool_withdraw_authority =
1184        find_withdraw_authority_program_address(program_id, stake_pool_address).0;
1185    let (stake_account_address, _) = find_stake_program_address(
1186        program_id,
1187        vote_account_address,
1188        stake_pool_address,
1189        validator_stake_seed,
1190    );
1191    let (transient_stake_account, _) = find_transient_stake_program_address(
1192        program_id,
1193        vote_account_address,
1194        stake_pool_address,
1195        transient_stake_seed,
1196    );
1197    remove_validator_from_pool(
1198        program_id,
1199        stake_pool_address,
1200        &stake_pool.staker,
1201        &pool_withdraw_authority,
1202        &stake_pool.validator_list,
1203        &stake_account_address,
1204        &transient_stake_account,
1205    )
1206}
1207
1208/// Create an `IncreaseValidatorStake` instruction given an existing stake pool
1209/// and vote account
1210pub fn increase_validator_stake_with_vote(
1211    program_id: &Pubkey,
1212    stake_pool: &StakePool,
1213    stake_pool_address: &Pubkey,
1214    vote_account_address: &Pubkey,
1215    lamports: u64,
1216    validator_stake_seed: Option<NonZeroU32>,
1217    transient_stake_seed: u64,
1218) -> Instruction {
1219    let pool_withdraw_authority =
1220        find_withdraw_authority_program_address(program_id, stake_pool_address).0;
1221    let (transient_stake_address, _) = find_transient_stake_program_address(
1222        program_id,
1223        vote_account_address,
1224        stake_pool_address,
1225        transient_stake_seed,
1226    );
1227    let (validator_stake_address, _) = find_stake_program_address(
1228        program_id,
1229        vote_account_address,
1230        stake_pool_address,
1231        validator_stake_seed,
1232    );
1233
1234    increase_validator_stake(
1235        program_id,
1236        stake_pool_address,
1237        &stake_pool.staker,
1238        &pool_withdraw_authority,
1239        &stake_pool.validator_list,
1240        &stake_pool.reserve_stake,
1241        &transient_stake_address,
1242        &validator_stake_address,
1243        vote_account_address,
1244        lamports,
1245        transient_stake_seed,
1246    )
1247}
1248
1249/// Create an `IncreaseAdditionalValidatorStake` instruction given an existing
1250/// stake pool and vote account
1251pub fn increase_additional_validator_stake_with_vote(
1252    program_id: &Pubkey,
1253    stake_pool: &StakePool,
1254    stake_pool_address: &Pubkey,
1255    vote_account_address: &Pubkey,
1256    lamports: u64,
1257    validator_stake_seed: Option<NonZeroU32>,
1258    transient_stake_seed: u64,
1259    ephemeral_stake_seed: u64,
1260) -> Instruction {
1261    let pool_withdraw_authority =
1262        find_withdraw_authority_program_address(program_id, stake_pool_address).0;
1263    let (ephemeral_stake_address, _) =
1264        find_ephemeral_stake_program_address(program_id, stake_pool_address, ephemeral_stake_seed);
1265    let (transient_stake_address, _) = find_transient_stake_program_address(
1266        program_id,
1267        vote_account_address,
1268        stake_pool_address,
1269        transient_stake_seed,
1270    );
1271    let (validator_stake_address, _) = find_stake_program_address(
1272        program_id,
1273        vote_account_address,
1274        stake_pool_address,
1275        validator_stake_seed,
1276    );
1277
1278    increase_additional_validator_stake(
1279        program_id,
1280        stake_pool_address,
1281        &stake_pool.staker,
1282        &pool_withdraw_authority,
1283        &stake_pool.validator_list,
1284        &stake_pool.reserve_stake,
1285        &ephemeral_stake_address,
1286        &transient_stake_address,
1287        &validator_stake_address,
1288        vote_account_address,
1289        lamports,
1290        transient_stake_seed,
1291        ephemeral_stake_seed,
1292    )
1293}
1294
1295/// Create a `DecreaseValidatorStake` instruction given an existing stake pool
1296/// and vote account
1297pub fn decrease_validator_stake_with_vote(
1298    program_id: &Pubkey,
1299    stake_pool: &StakePool,
1300    stake_pool_address: &Pubkey,
1301    vote_account_address: &Pubkey,
1302    lamports: u64,
1303    validator_stake_seed: Option<NonZeroU32>,
1304    transient_stake_seed: u64,
1305) -> Instruction {
1306    let pool_withdraw_authority =
1307        find_withdraw_authority_program_address(program_id, stake_pool_address).0;
1308    let (validator_stake_address, _) = find_stake_program_address(
1309        program_id,
1310        vote_account_address,
1311        stake_pool_address,
1312        validator_stake_seed,
1313    );
1314    let (transient_stake_address, _) = find_transient_stake_program_address(
1315        program_id,
1316        vote_account_address,
1317        stake_pool_address,
1318        transient_stake_seed,
1319    );
1320    decrease_validator_stake_with_reserve(
1321        program_id,
1322        stake_pool_address,
1323        &stake_pool.staker,
1324        &pool_withdraw_authority,
1325        &stake_pool.validator_list,
1326        &stake_pool.reserve_stake,
1327        &validator_stake_address,
1328        &transient_stake_address,
1329        lamports,
1330        transient_stake_seed,
1331    )
1332}
1333
1334/// Create a `IncreaseAdditionalValidatorStake` instruction given an existing
1335/// stake pool, validator list and vote account
1336pub fn increase_additional_validator_stake_with_list(
1337    program_id: &Pubkey,
1338    stake_pool: &StakePool,
1339    validator_list: &ValidatorList,
1340    stake_pool_address: &Pubkey,
1341    vote_account_address: &Pubkey,
1342    lamports: u64,
1343    ephemeral_stake_seed: u64,
1344) -> Result<Instruction, ProgramError> {
1345    let validator_info = validator_list
1346        .find(vote_account_address)
1347        .ok_or(ProgramError::InvalidInstructionData)?;
1348    let transient_stake_seed = u64::from(validator_info.transient_seed_suffix);
1349    let validator_stake_seed = NonZeroU32::new(validator_info.validator_seed_suffix.into());
1350    Ok(increase_additional_validator_stake_with_vote(
1351        program_id,
1352        stake_pool,
1353        stake_pool_address,
1354        vote_account_address,
1355        lamports,
1356        validator_stake_seed,
1357        transient_stake_seed,
1358        ephemeral_stake_seed,
1359    ))
1360}
1361
1362/// Create a `DecreaseAdditionalValidatorStake` instruction given an existing
1363/// stake pool, validator list and vote account
1364pub fn decrease_additional_validator_stake_with_list(
1365    program_id: &Pubkey,
1366    stake_pool: &StakePool,
1367    validator_list: &ValidatorList,
1368    stake_pool_address: &Pubkey,
1369    vote_account_address: &Pubkey,
1370    lamports: u64,
1371    ephemeral_stake_seed: u64,
1372) -> Result<Instruction, ProgramError> {
1373    let validator_info = validator_list
1374        .find(vote_account_address)
1375        .ok_or(ProgramError::InvalidInstructionData)?;
1376    let transient_stake_seed = u64::from(validator_info.transient_seed_suffix);
1377    let validator_stake_seed = NonZeroU32::new(validator_info.validator_seed_suffix.into());
1378    Ok(decrease_additional_validator_stake_with_vote(
1379        program_id,
1380        stake_pool,
1381        stake_pool_address,
1382        vote_account_address,
1383        lamports,
1384        validator_stake_seed,
1385        transient_stake_seed,
1386        ephemeral_stake_seed,
1387    ))
1388}
1389
1390/// Create a `DecreaseAdditionalValidatorStake` instruction given an existing
1391/// stake pool and vote account
1392pub fn decrease_additional_validator_stake_with_vote(
1393    program_id: &Pubkey,
1394    stake_pool: &StakePool,
1395    stake_pool_address: &Pubkey,
1396    vote_account_address: &Pubkey,
1397    lamports: u64,
1398    validator_stake_seed: Option<NonZeroU32>,
1399    transient_stake_seed: u64,
1400    ephemeral_stake_seed: u64,
1401) -> Instruction {
1402    let pool_withdraw_authority =
1403        find_withdraw_authority_program_address(program_id, stake_pool_address).0;
1404    let (validator_stake_address, _) = find_stake_program_address(
1405        program_id,
1406        vote_account_address,
1407        stake_pool_address,
1408        validator_stake_seed,
1409    );
1410    let (ephemeral_stake_address, _) =
1411        find_ephemeral_stake_program_address(program_id, stake_pool_address, ephemeral_stake_seed);
1412    let (transient_stake_address, _) = find_transient_stake_program_address(
1413        program_id,
1414        vote_account_address,
1415        stake_pool_address,
1416        transient_stake_seed,
1417    );
1418    decrease_additional_validator_stake(
1419        program_id,
1420        stake_pool_address,
1421        &stake_pool.staker,
1422        &pool_withdraw_authority,
1423        &stake_pool.validator_list,
1424        &stake_pool.reserve_stake,
1425        &validator_stake_address,
1426        &ephemeral_stake_address,
1427        &transient_stake_address,
1428        lamports,
1429        transient_stake_seed,
1430        ephemeral_stake_seed,
1431    )
1432}
1433
1434/// Creates `UpdateValidatorListBalance` instruction (update validator stake
1435/// account balances)
1436#[deprecated(
1437    since = "1.1.0",
1438    note = "please use `update_validator_list_balance_chunk`"
1439)]
1440pub fn update_validator_list_balance(
1441    program_id: &Pubkey,
1442    stake_pool: &Pubkey,
1443    stake_pool_withdraw_authority: &Pubkey,
1444    validator_list_address: &Pubkey,
1445    reserve_stake: &Pubkey,
1446    validator_list: &ValidatorList,
1447    validator_vote_accounts: &[Pubkey],
1448    start_index: u32,
1449    no_merge: bool,
1450) -> Instruction {
1451    let mut accounts = vec![
1452        AccountMeta::new_readonly(*stake_pool, false),
1453        AccountMeta::new_readonly(*stake_pool_withdraw_authority, false),
1454        AccountMeta::new(*validator_list_address, false),
1455        AccountMeta::new(*reserve_stake, false),
1456        AccountMeta::new_readonly(sysvar::clock::id(), false),
1457        AccountMeta::new_readonly(sysvar::stake_history::id(), false),
1458        AccountMeta::new_readonly(stake::program::id(), false),
1459    ];
1460    accounts.append(
1461        &mut validator_vote_accounts
1462            .iter()
1463            .flat_map(|vote_account_address| {
1464                let validator_stake_info = validator_list.find(vote_account_address);
1465                if let Some(validator_stake_info) = validator_stake_info {
1466                    let (validator_stake_account, _) = find_stake_program_address(
1467                        program_id,
1468                        vote_account_address,
1469                        stake_pool,
1470                        NonZeroU32::new(validator_stake_info.validator_seed_suffix.into()),
1471                    );
1472                    let (transient_stake_account, _) = find_transient_stake_program_address(
1473                        program_id,
1474                        vote_account_address,
1475                        stake_pool,
1476                        validator_stake_info.transient_seed_suffix.into(),
1477                    );
1478                    vec![
1479                        AccountMeta::new(validator_stake_account, false),
1480                        AccountMeta::new(transient_stake_account, false),
1481                    ]
1482                } else {
1483                    vec![]
1484                }
1485            })
1486            .collect::<Vec<AccountMeta>>(),
1487    );
1488    Instruction {
1489        program_id: *program_id,
1490        accounts,
1491        data: borsh::to_vec(&StakePoolInstruction::UpdateValidatorListBalance {
1492            start_index,
1493            no_merge,
1494        })
1495        .unwrap(),
1496    }
1497}
1498
1499/// Creates an `UpdateValidatorListBalance` instruction (update validator stake
1500/// account balances) to update `validator_list[start_index..start_index +
1501/// len]`.
1502///
1503/// Returns `Err(ProgramError::InvalidInstructionData)` if:
1504/// - `start_index..start_index + len` is out of bounds for
1505///   `validator_list.validators`
1506pub fn update_validator_list_balance_chunk(
1507    program_id: &Pubkey,
1508    stake_pool: &Pubkey,
1509    stake_pool_withdraw_authority: &Pubkey,
1510    validator_list_address: &Pubkey,
1511    reserve_stake: &Pubkey,
1512    validator_list: &ValidatorList,
1513    len: usize,
1514    start_index: usize,
1515    no_merge: bool,
1516) -> Result<Instruction, ProgramError> {
1517    let mut accounts = vec![
1518        AccountMeta::new_readonly(*stake_pool, false),
1519        AccountMeta::new_readonly(*stake_pool_withdraw_authority, false),
1520        AccountMeta::new(*validator_list_address, false),
1521        AccountMeta::new(*reserve_stake, false),
1522        AccountMeta::new_readonly(sysvar::clock::id(), false),
1523        AccountMeta::new_readonly(sysvar::stake_history::id(), false),
1524        AccountMeta::new_readonly(stake::program::id(), false),
1525    ];
1526    let validator_list_subslice = validator_list
1527        .validators
1528        .get(start_index..start_index.saturating_add(len))
1529        .ok_or(ProgramError::InvalidInstructionData)?;
1530    accounts.extend(validator_list_subslice.iter().flat_map(
1531        |ValidatorStakeInfo {
1532             vote_account_address,
1533             validator_seed_suffix,
1534             transient_seed_suffix,
1535             ..
1536         }| {
1537            let (validator_stake_account, _) = find_stake_program_address(
1538                program_id,
1539                vote_account_address,
1540                stake_pool,
1541                NonZeroU32::new((*validator_seed_suffix).into()),
1542            );
1543            let (transient_stake_account, _) = find_transient_stake_program_address(
1544                program_id,
1545                vote_account_address,
1546                stake_pool,
1547                (*transient_seed_suffix).into(),
1548            );
1549            [
1550                AccountMeta::new(validator_stake_account, false),
1551                AccountMeta::new(transient_stake_account, false),
1552            ]
1553        },
1554    ));
1555    Ok(Instruction {
1556        program_id: *program_id,
1557        accounts,
1558        data: borsh::to_vec(&StakePoolInstruction::UpdateValidatorListBalance {
1559            start_index: start_index.try_into().unwrap(),
1560            no_merge,
1561        })
1562        .unwrap(),
1563    })
1564}
1565
1566/// Creates `UpdateValidatorListBalance` instruction (update validator stake
1567/// account balances)
1568///
1569/// Returns `None` if all validators in the given chunk has already been updated
1570/// for this epoch, returns the required instruction otherwise.
1571pub fn update_stale_validator_list_balance_chunk(
1572    program_id: &Pubkey,
1573    stake_pool: &Pubkey,
1574    stake_pool_withdraw_authority: &Pubkey,
1575    validator_list_address: &Pubkey,
1576    reserve_stake: &Pubkey,
1577    validator_list: &ValidatorList,
1578    len: usize,
1579    start_index: usize,
1580    no_merge: bool,
1581    current_epoch: Epoch,
1582) -> Result<Option<Instruction>, ProgramError> {
1583    let validator_list_subslice = validator_list
1584        .validators
1585        .get(start_index..start_index.saturating_add(len))
1586        .ok_or(ProgramError::InvalidInstructionData)?;
1587    if validator_list_subslice.iter().all(|info| {
1588        let last_update_epoch: u64 = info.last_update_epoch.into();
1589        last_update_epoch >= current_epoch
1590    }) {
1591        return Ok(None);
1592    }
1593    update_validator_list_balance_chunk(
1594        program_id,
1595        stake_pool,
1596        stake_pool_withdraw_authority,
1597        validator_list_address,
1598        reserve_stake,
1599        validator_list,
1600        len,
1601        start_index,
1602        no_merge,
1603    )
1604    .map(Some)
1605}
1606
1607/// Creates `UpdateStakePoolBalance` instruction (pool balance from the stake
1608/// account list balances)
1609pub fn update_stake_pool_balance(
1610    program_id: &Pubkey,
1611    stake_pool: &Pubkey,
1612    withdraw_authority: &Pubkey,
1613    validator_list_storage: &Pubkey,
1614    reserve_stake: &Pubkey,
1615    manager_fee_account: &Pubkey,
1616    stake_pool_mint: &Pubkey,
1617    token_program_id: &Pubkey,
1618) -> Instruction {
1619    let accounts = vec![
1620        AccountMeta::new(*stake_pool, false),
1621        AccountMeta::new_readonly(*withdraw_authority, false),
1622        AccountMeta::new(*validator_list_storage, false),
1623        AccountMeta::new_readonly(*reserve_stake, false),
1624        AccountMeta::new(*manager_fee_account, false),
1625        AccountMeta::new(*stake_pool_mint, false),
1626        AccountMeta::new_readonly(*token_program_id, false),
1627    ];
1628    Instruction {
1629        program_id: *program_id,
1630        accounts,
1631        data: borsh::to_vec(&StakePoolInstruction::UpdateStakePoolBalance).unwrap(),
1632    }
1633}
1634
1635/// Creates `CleanupRemovedValidatorEntries` instruction (removes entries from
1636/// the validator list)
1637pub fn cleanup_removed_validator_entries(
1638    program_id: &Pubkey,
1639    stake_pool: &Pubkey,
1640    validator_list_storage: &Pubkey,
1641) -> Instruction {
1642    let accounts = vec![
1643        AccountMeta::new_readonly(*stake_pool, false),
1644        AccountMeta::new(*validator_list_storage, false),
1645    ];
1646    Instruction {
1647        program_id: *program_id,
1648        accounts,
1649        data: borsh::to_vec(&StakePoolInstruction::CleanupRemovedValidatorEntries).unwrap(),
1650    }
1651}
1652
1653/// Creates all `UpdateValidatorListBalance` and `UpdateStakePoolBalance`
1654/// instructions for fully updating a stake pool each epoch
1655pub fn update_stake_pool(
1656    program_id: &Pubkey,
1657    stake_pool: &StakePool,
1658    validator_list: &ValidatorList,
1659    stake_pool_address: &Pubkey,
1660    no_merge: bool,
1661) -> (Vec<Instruction>, Vec<Instruction>) {
1662    let (withdraw_authority, _) =
1663        find_withdraw_authority_program_address(program_id, stake_pool_address);
1664
1665    let update_list_instructions = validator_list
1666        .validators
1667        .chunks(MAX_VALIDATORS_TO_UPDATE)
1668        .enumerate()
1669        .map(|(i, chunk)| {
1670            // unwrap-safety: chunk len and offset are derived
1671            update_validator_list_balance_chunk(
1672                program_id,
1673                stake_pool_address,
1674                &withdraw_authority,
1675                &stake_pool.validator_list,
1676                &stake_pool.reserve_stake,
1677                validator_list,
1678                chunk.len(),
1679                i.saturating_mul(MAX_VALIDATORS_TO_UPDATE),
1680                no_merge,
1681            )
1682            .unwrap()
1683        })
1684        .collect();
1685
1686    let final_instructions = vec![
1687        update_stake_pool_balance(
1688            program_id,
1689            stake_pool_address,
1690            &withdraw_authority,
1691            &stake_pool.validator_list,
1692            &stake_pool.reserve_stake,
1693            &stake_pool.manager_fee_account,
1694            &stake_pool.pool_mint,
1695            &stake_pool.token_program_id,
1696        ),
1697        cleanup_removed_validator_entries(
1698            program_id,
1699            stake_pool_address,
1700            &stake_pool.validator_list,
1701        ),
1702    ];
1703    (update_list_instructions, final_instructions)
1704}
1705
1706/// Creates the `UpdateValidatorListBalance` instructions only for validators on
1707/// `validator_list` that have not been updated for this epoch, and the
1708/// `UpdateStakePoolBalance` instruction for fully updating the stake pool.
1709///
1710/// Basically same as [`update_stake_pool`], but skips validators that are
1711/// already updated for this epoch
1712pub fn update_stale_stake_pool(
1713    program_id: &Pubkey,
1714    stake_pool: &StakePool,
1715    validator_list: &ValidatorList,
1716    stake_pool_address: &Pubkey,
1717    no_merge: bool,
1718    current_epoch: Epoch,
1719) -> (Vec<Instruction>, Vec<Instruction>) {
1720    let (withdraw_authority, _) =
1721        find_withdraw_authority_program_address(program_id, stake_pool_address);
1722
1723    let update_list_instructions = validator_list
1724        .validators
1725        .chunks(MAX_VALIDATORS_TO_UPDATE)
1726        .enumerate()
1727        .filter_map(|(i, chunk)| {
1728            // unwrap-safety: chunk len and offset are derived
1729            update_stale_validator_list_balance_chunk(
1730                program_id,
1731                stake_pool_address,
1732                &withdraw_authority,
1733                &stake_pool.validator_list,
1734                &stake_pool.reserve_stake,
1735                validator_list,
1736                chunk.len(),
1737                i.saturating_mul(MAX_VALIDATORS_TO_UPDATE),
1738                no_merge,
1739                current_epoch,
1740            )
1741            .unwrap()
1742        })
1743        .collect();
1744
1745    let final_instructions = vec![
1746        update_stake_pool_balance(
1747            program_id,
1748            stake_pool_address,
1749            &withdraw_authority,
1750            &stake_pool.validator_list,
1751            &stake_pool.reserve_stake,
1752            &stake_pool.manager_fee_account,
1753            &stake_pool.pool_mint,
1754            &stake_pool.token_program_id,
1755        ),
1756        cleanup_removed_validator_entries(
1757            program_id,
1758            stake_pool_address,
1759            &stake_pool.validator_list,
1760        ),
1761    ];
1762    (update_list_instructions, final_instructions)
1763}
1764
1765fn deposit_stake_internal(
1766    program_id: &Pubkey,
1767    stake_pool: &Pubkey,
1768    validator_list_storage: &Pubkey,
1769    stake_pool_deposit_authority: Option<&Pubkey>,
1770    stake_pool_withdraw_authority: &Pubkey,
1771    deposit_stake_address: &Pubkey,
1772    deposit_stake_withdraw_authority: &Pubkey,
1773    validator_stake_account: &Pubkey,
1774    reserve_stake_account: &Pubkey,
1775    pool_tokens_to: &Pubkey,
1776    manager_fee_account: &Pubkey,
1777    referrer_pool_tokens_account: &Pubkey,
1778    pool_mint: &Pubkey,
1779    token_program_id: &Pubkey,
1780    minimum_pool_tokens_out: Option<u64>,
1781) -> Vec<Instruction> {
1782    let mut instructions = vec![];
1783    let mut accounts = vec![
1784        AccountMeta::new(*stake_pool, false),
1785        AccountMeta::new(*validator_list_storage, false),
1786    ];
1787    if let Some(stake_pool_deposit_authority) = stake_pool_deposit_authority {
1788        accounts.push(AccountMeta::new_readonly(
1789            *stake_pool_deposit_authority,
1790            true,
1791        ));
1792        instructions.extend_from_slice(&[
1793            stake::instruction::authorize(
1794                deposit_stake_address,
1795                deposit_stake_withdraw_authority,
1796                stake_pool_deposit_authority,
1797                stake::state::StakeAuthorize::Staker,
1798                None,
1799            ),
1800            stake::instruction::authorize(
1801                deposit_stake_address,
1802                deposit_stake_withdraw_authority,
1803                stake_pool_deposit_authority,
1804                stake::state::StakeAuthorize::Withdrawer,
1805                None,
1806            ),
1807        ]);
1808    } else {
1809        let stake_pool_deposit_authority =
1810            find_deposit_authority_program_address(program_id, stake_pool).0;
1811        accounts.push(AccountMeta::new_readonly(
1812            stake_pool_deposit_authority,
1813            false,
1814        ));
1815        instructions.extend_from_slice(&[
1816            stake::instruction::authorize(
1817                deposit_stake_address,
1818                deposit_stake_withdraw_authority,
1819                &stake_pool_deposit_authority,
1820                stake::state::StakeAuthorize::Staker,
1821                None,
1822            ),
1823            stake::instruction::authorize(
1824                deposit_stake_address,
1825                deposit_stake_withdraw_authority,
1826                &stake_pool_deposit_authority,
1827                stake::state::StakeAuthorize::Withdrawer,
1828                None,
1829            ),
1830        ]);
1831    };
1832
1833    accounts.extend_from_slice(&[
1834        AccountMeta::new_readonly(*stake_pool_withdraw_authority, false),
1835        AccountMeta::new(*deposit_stake_address, false),
1836        AccountMeta::new(*validator_stake_account, false),
1837        AccountMeta::new(*reserve_stake_account, false),
1838        AccountMeta::new(*pool_tokens_to, false),
1839        AccountMeta::new(*manager_fee_account, false),
1840        AccountMeta::new(*referrer_pool_tokens_account, false),
1841        AccountMeta::new(*pool_mint, false),
1842        AccountMeta::new_readonly(sysvar::clock::id(), false),
1843        AccountMeta::new_readonly(sysvar::stake_history::id(), false),
1844        AccountMeta::new_readonly(*token_program_id, false),
1845        AccountMeta::new_readonly(stake::program::id(), false),
1846    ]);
1847    instructions.push(
1848        if let Some(minimum_pool_tokens_out) = minimum_pool_tokens_out {
1849            Instruction {
1850                program_id: *program_id,
1851                accounts,
1852                data: borsh::to_vec(&StakePoolInstruction::DepositStakeWithSlippage {
1853                    minimum_pool_tokens_out,
1854                })
1855                .unwrap(),
1856            }
1857        } else {
1858            Instruction {
1859                program_id: *program_id,
1860                accounts,
1861                data: borsh::to_vec(&StakePoolInstruction::DepositStake).unwrap(),
1862            }
1863        },
1864    );
1865    instructions
1866}
1867
1868/// Creates instructions required to deposit into a stake pool, given a stake
1869/// account owned by the user.
1870pub fn deposit_stake(
1871    program_id: &Pubkey,
1872    stake_pool: &Pubkey,
1873    validator_list_storage: &Pubkey,
1874    stake_pool_withdraw_authority: &Pubkey,
1875    deposit_stake_address: &Pubkey,
1876    deposit_stake_withdraw_authority: &Pubkey,
1877    validator_stake_account: &Pubkey,
1878    reserve_stake_account: &Pubkey,
1879    pool_tokens_to: &Pubkey,
1880    manager_fee_account: &Pubkey,
1881    referrer_pool_tokens_account: &Pubkey,
1882    pool_mint: &Pubkey,
1883    token_program_id: &Pubkey,
1884) -> Vec<Instruction> {
1885    deposit_stake_internal(
1886        program_id,
1887        stake_pool,
1888        validator_list_storage,
1889        None,
1890        stake_pool_withdraw_authority,
1891        deposit_stake_address,
1892        deposit_stake_withdraw_authority,
1893        validator_stake_account,
1894        reserve_stake_account,
1895        pool_tokens_to,
1896        manager_fee_account,
1897        referrer_pool_tokens_account,
1898        pool_mint,
1899        token_program_id,
1900        None,
1901    )
1902}
1903
1904/// Creates instructions to deposit into a stake pool with slippage
1905pub fn deposit_stake_with_slippage(
1906    program_id: &Pubkey,
1907    stake_pool: &Pubkey,
1908    validator_list_storage: &Pubkey,
1909    stake_pool_withdraw_authority: &Pubkey,
1910    deposit_stake_address: &Pubkey,
1911    deposit_stake_withdraw_authority: &Pubkey,
1912    validator_stake_account: &Pubkey,
1913    reserve_stake_account: &Pubkey,
1914    pool_tokens_to: &Pubkey,
1915    manager_fee_account: &Pubkey,
1916    referrer_pool_tokens_account: &Pubkey,
1917    pool_mint: &Pubkey,
1918    token_program_id: &Pubkey,
1919    minimum_pool_tokens_out: u64,
1920) -> Vec<Instruction> {
1921    deposit_stake_internal(
1922        program_id,
1923        stake_pool,
1924        validator_list_storage,
1925        None,
1926        stake_pool_withdraw_authority,
1927        deposit_stake_address,
1928        deposit_stake_withdraw_authority,
1929        validator_stake_account,
1930        reserve_stake_account,
1931        pool_tokens_to,
1932        manager_fee_account,
1933        referrer_pool_tokens_account,
1934        pool_mint,
1935        token_program_id,
1936        Some(minimum_pool_tokens_out),
1937    )
1938}
1939
1940/// Creates instructions required to deposit into a stake pool, given a stake
1941/// account owned by the user. The difference with `deposit()` is that a deposit
1942/// authority must sign this instruction, which is required for private pools.
1943pub fn deposit_stake_with_authority(
1944    program_id: &Pubkey,
1945    stake_pool: &Pubkey,
1946    validator_list_storage: &Pubkey,
1947    stake_pool_deposit_authority: &Pubkey,
1948    stake_pool_withdraw_authority: &Pubkey,
1949    deposit_stake_address: &Pubkey,
1950    deposit_stake_withdraw_authority: &Pubkey,
1951    validator_stake_account: &Pubkey,
1952    reserve_stake_account: &Pubkey,
1953    pool_tokens_to: &Pubkey,
1954    manager_fee_account: &Pubkey,
1955    referrer_pool_tokens_account: &Pubkey,
1956    pool_mint: &Pubkey,
1957    token_program_id: &Pubkey,
1958) -> Vec<Instruction> {
1959    deposit_stake_internal(
1960        program_id,
1961        stake_pool,
1962        validator_list_storage,
1963        Some(stake_pool_deposit_authority),
1964        stake_pool_withdraw_authority,
1965        deposit_stake_address,
1966        deposit_stake_withdraw_authority,
1967        validator_stake_account,
1968        reserve_stake_account,
1969        pool_tokens_to,
1970        manager_fee_account,
1971        referrer_pool_tokens_account,
1972        pool_mint,
1973        token_program_id,
1974        None,
1975    )
1976}
1977
1978/// Creates instructions required to deposit into a stake pool with slippage,
1979/// given a stake account owned by the user. The difference with `deposit()` is
1980/// that a deposit authority must sign this instruction, which is required for
1981/// private pools.
1982pub fn deposit_stake_with_authority_and_slippage(
1983    program_id: &Pubkey,
1984    stake_pool: &Pubkey,
1985    validator_list_storage: &Pubkey,
1986    stake_pool_deposit_authority: &Pubkey,
1987    stake_pool_withdraw_authority: &Pubkey,
1988    deposit_stake_address: &Pubkey,
1989    deposit_stake_withdraw_authority: &Pubkey,
1990    validator_stake_account: &Pubkey,
1991    reserve_stake_account: &Pubkey,
1992    pool_tokens_to: &Pubkey,
1993    manager_fee_account: &Pubkey,
1994    referrer_pool_tokens_account: &Pubkey,
1995    pool_mint: &Pubkey,
1996    token_program_id: &Pubkey,
1997    minimum_pool_tokens_out: u64,
1998) -> Vec<Instruction> {
1999    deposit_stake_internal(
2000        program_id,
2001        stake_pool,
2002        validator_list_storage,
2003        Some(stake_pool_deposit_authority),
2004        stake_pool_withdraw_authority,
2005        deposit_stake_address,
2006        deposit_stake_withdraw_authority,
2007        validator_stake_account,
2008        reserve_stake_account,
2009        pool_tokens_to,
2010        manager_fee_account,
2011        referrer_pool_tokens_account,
2012        pool_mint,
2013        token_program_id,
2014        Some(minimum_pool_tokens_out),
2015    )
2016}
2017
2018/// Creates instructions required to deposit SOL directly into a stake pool.
2019fn deposit_sol_internal(
2020    program_id: &Pubkey,
2021    stake_pool: &Pubkey,
2022    stake_pool_withdraw_authority: &Pubkey,
2023    reserve_stake_account: &Pubkey,
2024    lamports_from: &Pubkey,
2025    pool_tokens_to: &Pubkey,
2026    manager_fee_account: &Pubkey,
2027    referrer_pool_tokens_account: &Pubkey,
2028    pool_mint: &Pubkey,
2029    token_program_id: &Pubkey,
2030    sol_deposit_authority: Option<&Pubkey>,
2031    lamports_in: u64,
2032    minimum_pool_tokens_out: Option<u64>,
2033) -> Instruction {
2034    let mut accounts = vec![
2035        AccountMeta::new(*stake_pool, false),
2036        AccountMeta::new_readonly(*stake_pool_withdraw_authority, false),
2037        AccountMeta::new(*reserve_stake_account, false),
2038        AccountMeta::new(*lamports_from, true),
2039        AccountMeta::new(*pool_tokens_to, false),
2040        AccountMeta::new(*manager_fee_account, false),
2041        AccountMeta::new(*referrer_pool_tokens_account, false),
2042        AccountMeta::new(*pool_mint, false),
2043        AccountMeta::new_readonly(system_program::id(), false),
2044        AccountMeta::new_readonly(*token_program_id, false),
2045    ];
2046    if let Some(sol_deposit_authority) = sol_deposit_authority {
2047        accounts.push(AccountMeta::new_readonly(*sol_deposit_authority, true));
2048    }
2049    if let Some(minimum_pool_tokens_out) = minimum_pool_tokens_out {
2050        Instruction {
2051            program_id: *program_id,
2052            accounts,
2053            data: borsh::to_vec(&StakePoolInstruction::DepositSolWithSlippage {
2054                lamports_in,
2055                minimum_pool_tokens_out,
2056            })
2057            .unwrap(),
2058        }
2059    } else {
2060        Instruction {
2061            program_id: *program_id,
2062            accounts,
2063            data: borsh::to_vec(&StakePoolInstruction::DepositSol(lamports_in)).unwrap(),
2064        }
2065    }
2066}
2067
2068/// Creates instruction to deposit SOL directly into a stake pool.
2069pub fn deposit_sol(
2070    program_id: &Pubkey,
2071    stake_pool: &Pubkey,
2072    stake_pool_withdraw_authority: &Pubkey,
2073    reserve_stake_account: &Pubkey,
2074    lamports_from: &Pubkey,
2075    pool_tokens_to: &Pubkey,
2076    manager_fee_account: &Pubkey,
2077    referrer_pool_tokens_account: &Pubkey,
2078    pool_mint: &Pubkey,
2079    token_program_id: &Pubkey,
2080    lamports_in: u64,
2081) -> Instruction {
2082    deposit_sol_internal(
2083        program_id,
2084        stake_pool,
2085        stake_pool_withdraw_authority,
2086        reserve_stake_account,
2087        lamports_from,
2088        pool_tokens_to,
2089        manager_fee_account,
2090        referrer_pool_tokens_account,
2091        pool_mint,
2092        token_program_id,
2093        None,
2094        lamports_in,
2095        None,
2096    )
2097}
2098
2099/// Creates instruction to deposit SOL directly into a stake pool with slippage
2100/// constraint.
2101pub fn deposit_sol_with_slippage(
2102    program_id: &Pubkey,
2103    stake_pool: &Pubkey,
2104    stake_pool_withdraw_authority: &Pubkey,
2105    reserve_stake_account: &Pubkey,
2106    lamports_from: &Pubkey,
2107    pool_tokens_to: &Pubkey,
2108    manager_fee_account: &Pubkey,
2109    referrer_pool_tokens_account: &Pubkey,
2110    pool_mint: &Pubkey,
2111    token_program_id: &Pubkey,
2112    lamports_in: u64,
2113    minimum_pool_tokens_out: u64,
2114) -> Instruction {
2115    deposit_sol_internal(
2116        program_id,
2117        stake_pool,
2118        stake_pool_withdraw_authority,
2119        reserve_stake_account,
2120        lamports_from,
2121        pool_tokens_to,
2122        manager_fee_account,
2123        referrer_pool_tokens_account,
2124        pool_mint,
2125        token_program_id,
2126        None,
2127        lamports_in,
2128        Some(minimum_pool_tokens_out),
2129    )
2130}
2131
2132/// Creates instruction required to deposit SOL directly into a stake pool.
2133/// The difference with `deposit_sol()` is that a deposit
2134/// authority must sign this instruction.
2135pub fn deposit_sol_with_authority(
2136    program_id: &Pubkey,
2137    stake_pool: &Pubkey,
2138    sol_deposit_authority: &Pubkey,
2139    stake_pool_withdraw_authority: &Pubkey,
2140    reserve_stake_account: &Pubkey,
2141    lamports_from: &Pubkey,
2142    pool_tokens_to: &Pubkey,
2143    manager_fee_account: &Pubkey,
2144    referrer_pool_tokens_account: &Pubkey,
2145    pool_mint: &Pubkey,
2146    token_program_id: &Pubkey,
2147    lamports_in: u64,
2148) -> Instruction {
2149    deposit_sol_internal(
2150        program_id,
2151        stake_pool,
2152        stake_pool_withdraw_authority,
2153        reserve_stake_account,
2154        lamports_from,
2155        pool_tokens_to,
2156        manager_fee_account,
2157        referrer_pool_tokens_account,
2158        pool_mint,
2159        token_program_id,
2160        Some(sol_deposit_authority),
2161        lamports_in,
2162        None,
2163    )
2164}
2165
2166/// Creates instruction to deposit SOL directly into a stake pool with slippage
2167/// constraint.
2168pub fn deposit_sol_with_authority_and_slippage(
2169    program_id: &Pubkey,
2170    stake_pool: &Pubkey,
2171    sol_deposit_authority: &Pubkey,
2172    stake_pool_withdraw_authority: &Pubkey,
2173    reserve_stake_account: &Pubkey,
2174    lamports_from: &Pubkey,
2175    pool_tokens_to: &Pubkey,
2176    manager_fee_account: &Pubkey,
2177    referrer_pool_tokens_account: &Pubkey,
2178    pool_mint: &Pubkey,
2179    token_program_id: &Pubkey,
2180    lamports_in: u64,
2181    minimum_pool_tokens_out: u64,
2182) -> Instruction {
2183    deposit_sol_internal(
2184        program_id,
2185        stake_pool,
2186        stake_pool_withdraw_authority,
2187        reserve_stake_account,
2188        lamports_from,
2189        pool_tokens_to,
2190        manager_fee_account,
2191        referrer_pool_tokens_account,
2192        pool_mint,
2193        token_program_id,
2194        Some(sol_deposit_authority),
2195        lamports_in,
2196        Some(minimum_pool_tokens_out),
2197    )
2198}
2199
2200fn withdraw_stake_internal(
2201    program_id: &Pubkey,
2202    stake_pool: &Pubkey,
2203    validator_list_storage: &Pubkey,
2204    stake_pool_withdraw: &Pubkey,
2205    stake_to_split: &Pubkey,
2206    stake_to_receive: &Pubkey,
2207    user_stake_authority: &Pubkey,
2208    user_transfer_authority: &Pubkey,
2209    user_pool_token_account: &Pubkey,
2210    manager_fee_account: &Pubkey,
2211    pool_mint: &Pubkey,
2212    token_program_id: &Pubkey,
2213    pool_tokens_in: u64,
2214    minimum_lamports_out: Option<u64>,
2215) -> Instruction {
2216    let accounts = vec![
2217        AccountMeta::new(*stake_pool, false),
2218        AccountMeta::new(*validator_list_storage, false),
2219        AccountMeta::new_readonly(*stake_pool_withdraw, false),
2220        AccountMeta::new(*stake_to_split, false),
2221        AccountMeta::new(*stake_to_receive, false),
2222        AccountMeta::new_readonly(*user_stake_authority, false),
2223        AccountMeta::new_readonly(*user_transfer_authority, true),
2224        AccountMeta::new(*user_pool_token_account, false),
2225        AccountMeta::new(*manager_fee_account, false),
2226        AccountMeta::new(*pool_mint, false),
2227        AccountMeta::new_readonly(sysvar::clock::id(), false),
2228        AccountMeta::new_readonly(*token_program_id, false),
2229        AccountMeta::new_readonly(stake::program::id(), false),
2230    ];
2231    if let Some(minimum_lamports_out) = minimum_lamports_out {
2232        Instruction {
2233            program_id: *program_id,
2234            accounts,
2235            data: borsh::to_vec(&StakePoolInstruction::WithdrawStakeWithSlippage {
2236                pool_tokens_in,
2237                minimum_lamports_out,
2238            })
2239            .unwrap(),
2240        }
2241    } else {
2242        Instruction {
2243            program_id: *program_id,
2244            accounts,
2245            data: borsh::to_vec(&StakePoolInstruction::WithdrawStake(pool_tokens_in)).unwrap(),
2246        }
2247    }
2248}
2249
2250/// Creates a `WithdrawStake` instruction.
2251pub fn withdraw_stake(
2252    program_id: &Pubkey,
2253    stake_pool: &Pubkey,
2254    validator_list_storage: &Pubkey,
2255    stake_pool_withdraw: &Pubkey,
2256    stake_to_split: &Pubkey,
2257    stake_to_receive: &Pubkey,
2258    user_stake_authority: &Pubkey,
2259    user_transfer_authority: &Pubkey,
2260    user_pool_token_account: &Pubkey,
2261    manager_fee_account: &Pubkey,
2262    pool_mint: &Pubkey,
2263    token_program_id: &Pubkey,
2264    pool_tokens_in: u64,
2265) -> Instruction {
2266    withdraw_stake_internal(
2267        program_id,
2268        stake_pool,
2269        validator_list_storage,
2270        stake_pool_withdraw,
2271        stake_to_split,
2272        stake_to_receive,
2273        user_stake_authority,
2274        user_transfer_authority,
2275        user_pool_token_account,
2276        manager_fee_account,
2277        pool_mint,
2278        token_program_id,
2279        pool_tokens_in,
2280        None,
2281    )
2282}
2283
2284/// Creates a `WithdrawStakeWithSlippage` instruction.
2285pub fn withdraw_stake_with_slippage(
2286    program_id: &Pubkey,
2287    stake_pool: &Pubkey,
2288    validator_list_storage: &Pubkey,
2289    stake_pool_withdraw: &Pubkey,
2290    stake_to_split: &Pubkey,
2291    stake_to_receive: &Pubkey,
2292    user_stake_authority: &Pubkey,
2293    user_transfer_authority: &Pubkey,
2294    user_pool_token_account: &Pubkey,
2295    manager_fee_account: &Pubkey,
2296    pool_mint: &Pubkey,
2297    token_program_id: &Pubkey,
2298    pool_tokens_in: u64,
2299    minimum_lamports_out: u64,
2300) -> Instruction {
2301    withdraw_stake_internal(
2302        program_id,
2303        stake_pool,
2304        validator_list_storage,
2305        stake_pool_withdraw,
2306        stake_to_split,
2307        stake_to_receive,
2308        user_stake_authority,
2309        user_transfer_authority,
2310        user_pool_token_account,
2311        manager_fee_account,
2312        pool_mint,
2313        token_program_id,
2314        pool_tokens_in,
2315        Some(minimum_lamports_out),
2316    )
2317}
2318
2319fn withdraw_sol_internal(
2320    program_id: &Pubkey,
2321    stake_pool: &Pubkey,
2322    stake_pool_withdraw_authority: &Pubkey,
2323    user_transfer_authority: &Pubkey,
2324    pool_tokens_from: &Pubkey,
2325    reserve_stake_account: &Pubkey,
2326    lamports_to: &Pubkey,
2327    manager_fee_account: &Pubkey,
2328    pool_mint: &Pubkey,
2329    token_program_id: &Pubkey,
2330    sol_withdraw_authority: Option<&Pubkey>,
2331    pool_tokens_in: u64,
2332    minimum_lamports_out: Option<u64>,
2333) -> Instruction {
2334    let mut accounts = vec![
2335        AccountMeta::new(*stake_pool, false),
2336        AccountMeta::new_readonly(*stake_pool_withdraw_authority, false),
2337        AccountMeta::new_readonly(*user_transfer_authority, true),
2338        AccountMeta::new(*pool_tokens_from, false),
2339        AccountMeta::new(*reserve_stake_account, false),
2340        AccountMeta::new(*lamports_to, false),
2341        AccountMeta::new(*manager_fee_account, false),
2342        AccountMeta::new(*pool_mint, false),
2343        AccountMeta::new_readonly(sysvar::clock::id(), false),
2344        AccountMeta::new_readonly(sysvar::stake_history::id(), false),
2345        AccountMeta::new_readonly(stake::program::id(), false),
2346        AccountMeta::new_readonly(*token_program_id, false),
2347    ];
2348    if let Some(sol_withdraw_authority) = sol_withdraw_authority {
2349        accounts.push(AccountMeta::new_readonly(*sol_withdraw_authority, true));
2350    }
2351    if let Some(minimum_lamports_out) = minimum_lamports_out {
2352        Instruction {
2353            program_id: *program_id,
2354            accounts,
2355            data: borsh::to_vec(&StakePoolInstruction::WithdrawSolWithSlippage {
2356                pool_tokens_in,
2357                minimum_lamports_out,
2358            })
2359            .unwrap(),
2360        }
2361    } else {
2362        Instruction {
2363            program_id: *program_id,
2364            accounts,
2365            data: borsh::to_vec(&StakePoolInstruction::WithdrawSol(pool_tokens_in)).unwrap(),
2366        }
2367    }
2368}
2369
2370/// Creates instruction required to withdraw SOL directly from a stake pool.
2371pub fn withdraw_sol(
2372    program_id: &Pubkey,
2373    stake_pool: &Pubkey,
2374    stake_pool_withdraw_authority: &Pubkey,
2375    user_transfer_authority: &Pubkey,
2376    pool_tokens_from: &Pubkey,
2377    reserve_stake_account: &Pubkey,
2378    lamports_to: &Pubkey,
2379    manager_fee_account: &Pubkey,
2380    pool_mint: &Pubkey,
2381    token_program_id: &Pubkey,
2382    pool_tokens_in: u64,
2383) -> Instruction {
2384    withdraw_sol_internal(
2385        program_id,
2386        stake_pool,
2387        stake_pool_withdraw_authority,
2388        user_transfer_authority,
2389        pool_tokens_from,
2390        reserve_stake_account,
2391        lamports_to,
2392        manager_fee_account,
2393        pool_mint,
2394        token_program_id,
2395        None,
2396        pool_tokens_in,
2397        None,
2398    )
2399}
2400
2401/// Creates instruction required to withdraw SOL directly from a stake pool with
2402/// slippage constraints.
2403pub fn withdraw_sol_with_slippage(
2404    program_id: &Pubkey,
2405    stake_pool: &Pubkey,
2406    stake_pool_withdraw_authority: &Pubkey,
2407    user_transfer_authority: &Pubkey,
2408    pool_tokens_from: &Pubkey,
2409    reserve_stake_account: &Pubkey,
2410    lamports_to: &Pubkey,
2411    manager_fee_account: &Pubkey,
2412    pool_mint: &Pubkey,
2413    token_program_id: &Pubkey,
2414    pool_tokens_in: u64,
2415    minimum_lamports_out: u64,
2416) -> Instruction {
2417    withdraw_sol_internal(
2418        program_id,
2419        stake_pool,
2420        stake_pool_withdraw_authority,
2421        user_transfer_authority,
2422        pool_tokens_from,
2423        reserve_stake_account,
2424        lamports_to,
2425        manager_fee_account,
2426        pool_mint,
2427        token_program_id,
2428        None,
2429        pool_tokens_in,
2430        Some(minimum_lamports_out),
2431    )
2432}
2433
2434/// Creates instruction required to withdraw SOL directly from a stake pool.
2435/// The difference with `withdraw_sol()` is that the sol withdraw authority
2436/// must sign this instruction.
2437pub fn withdraw_sol_with_authority(
2438    program_id: &Pubkey,
2439    stake_pool: &Pubkey,
2440    sol_withdraw_authority: &Pubkey,
2441    stake_pool_withdraw_authority: &Pubkey,
2442    user_transfer_authority: &Pubkey,
2443    pool_tokens_from: &Pubkey,
2444    reserve_stake_account: &Pubkey,
2445    lamports_to: &Pubkey,
2446    manager_fee_account: &Pubkey,
2447    pool_mint: &Pubkey,
2448    token_program_id: &Pubkey,
2449    pool_tokens_in: u64,
2450) -> Instruction {
2451    withdraw_sol_internal(
2452        program_id,
2453        stake_pool,
2454        stake_pool_withdraw_authority,
2455        user_transfer_authority,
2456        pool_tokens_from,
2457        reserve_stake_account,
2458        lamports_to,
2459        manager_fee_account,
2460        pool_mint,
2461        token_program_id,
2462        Some(sol_withdraw_authority),
2463        pool_tokens_in,
2464        None,
2465    )
2466}
2467
2468/// Creates instruction required to withdraw SOL directly from a stake pool with
2469/// a slippage constraint.
2470/// The difference with `withdraw_sol()` is that the sol withdraw authority
2471/// must sign this instruction.
2472pub fn withdraw_sol_with_authority_and_slippage(
2473    program_id: &Pubkey,
2474    stake_pool: &Pubkey,
2475    sol_withdraw_authority: &Pubkey,
2476    stake_pool_withdraw_authority: &Pubkey,
2477    user_transfer_authority: &Pubkey,
2478    pool_tokens_from: &Pubkey,
2479    reserve_stake_account: &Pubkey,
2480    lamports_to: &Pubkey,
2481    manager_fee_account: &Pubkey,
2482    pool_mint: &Pubkey,
2483    token_program_id: &Pubkey,
2484    pool_tokens_in: u64,
2485    minimum_lamports_out: u64,
2486) -> Instruction {
2487    withdraw_sol_internal(
2488        program_id,
2489        stake_pool,
2490        stake_pool_withdraw_authority,
2491        user_transfer_authority,
2492        pool_tokens_from,
2493        reserve_stake_account,
2494        lamports_to,
2495        manager_fee_account,
2496        pool_mint,
2497        token_program_id,
2498        Some(sol_withdraw_authority),
2499        pool_tokens_in,
2500        Some(minimum_lamports_out),
2501    )
2502}
2503
2504/// Creates a `SetManager` instruction.
2505pub fn set_manager(
2506    program_id: &Pubkey,
2507    stake_pool: &Pubkey,
2508    manager: &Pubkey,
2509    new_manager: &Pubkey,
2510    new_fee_receiver: &Pubkey,
2511) -> Instruction {
2512    let accounts = vec![
2513        AccountMeta::new(*stake_pool, false),
2514        AccountMeta::new_readonly(*manager, true),
2515        AccountMeta::new_readonly(*new_manager, true),
2516        AccountMeta::new_readonly(*new_fee_receiver, false),
2517    ];
2518    Instruction {
2519        program_id: *program_id,
2520        accounts,
2521        data: borsh::to_vec(&StakePoolInstruction::SetManager).unwrap(),
2522    }
2523}
2524
2525/// Creates a `SetFee` instruction.
2526pub fn set_fee(
2527    program_id: &Pubkey,
2528    stake_pool: &Pubkey,
2529    manager: &Pubkey,
2530    fee: FeeType,
2531) -> Instruction {
2532    let accounts = vec![
2533        AccountMeta::new(*stake_pool, false),
2534        AccountMeta::new_readonly(*manager, true),
2535    ];
2536    Instruction {
2537        program_id: *program_id,
2538        accounts,
2539        data: borsh::to_vec(&StakePoolInstruction::SetFee { fee }).unwrap(),
2540    }
2541}
2542
2543/// Creates a `SetStaker` instruction.
2544pub fn set_staker(
2545    program_id: &Pubkey,
2546    stake_pool: &Pubkey,
2547    set_staker_authority: &Pubkey,
2548    new_staker: &Pubkey,
2549) -> Instruction {
2550    let accounts = vec![
2551        AccountMeta::new(*stake_pool, false),
2552        AccountMeta::new_readonly(*set_staker_authority, true),
2553        AccountMeta::new_readonly(*new_staker, false),
2554    ];
2555    Instruction {
2556        program_id: *program_id,
2557        accounts,
2558        data: borsh::to_vec(&StakePoolInstruction::SetStaker).unwrap(),
2559    }
2560}
2561
2562/// Creates a `SetFundingAuthority` instruction.
2563pub fn set_funding_authority(
2564    program_id: &Pubkey,
2565    stake_pool: &Pubkey,
2566    manager: &Pubkey,
2567    new_sol_deposit_authority: Option<&Pubkey>,
2568    funding_type: FundingType,
2569) -> Instruction {
2570    let mut accounts = vec![
2571        AccountMeta::new(*stake_pool, false),
2572        AccountMeta::new_readonly(*manager, true),
2573    ];
2574    if let Some(auth) = new_sol_deposit_authority {
2575        accounts.push(AccountMeta::new_readonly(*auth, false))
2576    }
2577    Instruction {
2578        program_id: *program_id,
2579        accounts,
2580        data: borsh::to_vec(&StakePoolInstruction::SetFundingAuthority(funding_type)).unwrap(),
2581    }
2582}
2583
2584/// Creates an instruction to update metadata in the mpl token metadata program
2585/// account for the pool token
2586pub fn update_token_metadata(
2587    program_id: &Pubkey,
2588    stake_pool: &Pubkey,
2589    manager: &Pubkey,
2590    pool_mint: &Pubkey,
2591    name: String,
2592    symbol: String,
2593    uri: String,
2594) -> Instruction {
2595    let (stake_pool_withdraw_authority, _) =
2596        find_withdraw_authority_program_address(program_id, stake_pool);
2597    let (token_metadata, _) = find_metadata_account(pool_mint);
2598
2599    let accounts = vec![
2600        AccountMeta::new_readonly(*stake_pool, false),
2601        AccountMeta::new_readonly(*manager, true),
2602        AccountMeta::new_readonly(stake_pool_withdraw_authority, false),
2603        AccountMeta::new(token_metadata, false),
2604        AccountMeta::new_readonly(inline_mpl_token_metadata::id(), false),
2605    ];
2606
2607    Instruction {
2608        program_id: *program_id,
2609        accounts,
2610        data: borsh::to_vec(&StakePoolInstruction::UpdateTokenMetadata { name, symbol, uri })
2611            .unwrap(),
2612    }
2613}
2614
2615/// Creates an instruction to create metadata using the mpl token metadata
2616/// program for the pool token
2617pub fn create_token_metadata(
2618    program_id: &Pubkey,
2619    stake_pool: &Pubkey,
2620    manager: &Pubkey,
2621    pool_mint: &Pubkey,
2622    payer: &Pubkey,
2623    name: String,
2624    symbol: String,
2625    uri: String,
2626) -> Instruction {
2627    let (stake_pool_withdraw_authority, _) =
2628        find_withdraw_authority_program_address(program_id, stake_pool);
2629    let (token_metadata, _) = find_metadata_account(pool_mint);
2630
2631    let accounts = vec![
2632        AccountMeta::new_readonly(*stake_pool, false),
2633        AccountMeta::new_readonly(*manager, true),
2634        AccountMeta::new_readonly(stake_pool_withdraw_authority, false),
2635        AccountMeta::new_readonly(*pool_mint, false),
2636        AccountMeta::new(*payer, true),
2637        AccountMeta::new(token_metadata, false),
2638        AccountMeta::new_readonly(inline_mpl_token_metadata::id(), false),
2639        AccountMeta::new_readonly(system_program::id(), false),
2640    ];
2641
2642    Instruction {
2643        program_id: *program_id,
2644        accounts,
2645        data: borsh::to_vec(&StakePoolInstruction::CreateTokenMetadata { name, symbol, uri })
2646            .unwrap(),
2647    }
2648}