solana_system_interface/
instruction.rs

1//! Instructions and constructors for the system program.
2//!
3//! The system program is responsible for the creation of accounts and [nonce
4//! accounts][na]. It is responsible for transferring lamports from accounts
5//! owned by the system program, including typical user wallet accounts.
6//!
7//! [na]: https://docs.solanalabs.com/implemented-proposals/durable-tx-nonces
8//!
9//! Account creation typically involves three steps: [`allocate`] space,
10//! [`transfer`] lamports for rent, [`assign`] to its owning program. The
11//! [`create_account`] function does all three at once. All new accounts must
12//! contain enough lamports to be [rent exempt], or else the creation
13//! instruction will fail.
14//!
15//! [rent exempt]: https://solana.com/docs/core/accounts#rent-exemption
16//!
17//! The accounts created by the System program can either be user-controlled,
18//! where the secret keys are held outside the blockchain,
19//! or they can be [program derived addresses][pda],
20//! where write access to accounts is granted by an owning program.
21//!
22//! [pda]: https://docs.rs/solana-pubkey/latest/solana_pubkey/struct.Pubkey.html#method.find_program_address
23//!
24//! Most of the functions in this module construct an [`Instruction`], that must
25//! be submitted to the runtime for execution, either via RPC, typically with
26//! [`RpcClient`], or through [cross-program invocation][cpi].
27//!
28//! When invoking through CPI, the [`invoke`] or [`invoke_signed`] instruction
29//! requires all account references to be provided explicitly as [`AccountInfo`]
30//! values. The account references required are specified in the documentation
31//! for the [`SystemInstruction`] variants for each System program instruction,
32//! and these variants are linked from the documentation for their constructors.
33//!
34//! [`RpcClient`]: https://docs.rs/solana-client/latest/solana_client/rpc_client/struct.RpcClient.html
35//! [cpi]: https://docs.rs/solana-cpi/latest/solana_cpi/index.html
36//! [`invoke`]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke.html
37//! [`invoke_signed`]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke_signed.html
38//! [`AccountInfo`]: https://docs.rs/solana-account-info/latest/solana_account_info/struct.AccountInfo.html
39//! [`Instruction`]:
40//! https://docs.rs/solana-instruction/latest/solana_instruction/struct.Instruction.html
41
42use solana_pubkey::Pubkey;
43#[cfg(feature = "bincode")]
44use {
45    crate::program::ID,
46    solana_instruction::{AccountMeta, Instruction},
47};
48
49// Inline some constants to avoid dependencies.
50//
51// Note: replace these inline IDs with the corresponding value from
52// `solana_sdk_ids` once the version is updated to 2.2.0.
53
54#[cfg(feature = "bincode")]
55const RECENT_BLOCKHASHES_ID: Pubkey =
56    Pubkey::from_str_const("SysvarRecentB1ockHashes11111111111111111111");
57
58#[cfg(feature = "bincode")]
59const RENT_ID: Pubkey = Pubkey::from_str_const("SysvarRent111111111111111111111111111111111");
60
61#[cfg(feature = "bincode")]
62#[cfg(test)]
63static_assertions::const_assert_eq!(solana_nonce::state::State::size(), NONCE_STATE_SIZE);
64/// The serialized size of the nonce state.
65#[cfg(feature = "bincode")]
66const NONCE_STATE_SIZE: usize = 80;
67
68/// An instruction to the system program.
69#[cfg_attr(
70    feature = "frozen-abi",
71    solana_frozen_abi_macro::frozen_abi(digest = "8M189WgLE19cw1iYDAFLNJKoAUKyqF9jsKYennJi5BfK"),
72    derive(
73        solana_frozen_abi_macro::AbiExample,
74        solana_frozen_abi_macro::AbiEnumVisitor
75    )
76)]
77#[cfg_attr(
78    feature = "serde",
79    derive(serde_derive::Deserialize, serde_derive::Serialize)
80)]
81#[derive(Clone, Debug, Eq, PartialEq)]
82pub enum SystemInstruction {
83    /// Create a new account
84    ///
85    /// # Account references
86    ///   0. `[WRITE, SIGNER]` Funding account
87    ///   1. `[WRITE, SIGNER]` New account
88    CreateAccount {
89        /// Number of lamports to transfer to the new account
90        lamports: u64,
91
92        /// Number of bytes of memory to allocate
93        space: u64,
94
95        /// Address of program that will own the new account
96        owner: Pubkey,
97    },
98
99    /// Assign account to a program
100    ///
101    /// # Account references
102    ///   0. `[WRITE, SIGNER]` Assigned account public key
103    Assign {
104        /// Owner program account
105        owner: Pubkey,
106    },
107
108    /// Transfer lamports
109    ///
110    /// # Account references
111    ///   0. `[WRITE, SIGNER]` Funding account
112    ///   1. `[WRITE]` Recipient account
113    Transfer { lamports: u64 },
114
115    /// Create a new account at an address derived from a base pubkey and a seed
116    ///
117    /// # Account references
118    ///   0. `[WRITE, SIGNER]` Funding account
119    ///   1. `[WRITE]` Created account
120    ///   2. `[SIGNER]` (optional) Base account; the account matching the base Pubkey below must be
121    ///      provided as a signer, but may be the same as the funding account
122    ///      and provided as account 0
123    CreateAccountWithSeed {
124        /// Base public key
125        base: Pubkey,
126
127        /// String of ASCII chars, no longer than `Pubkey::MAX_SEED_LEN`
128        seed: String,
129
130        /// Number of lamports to transfer to the new account
131        lamports: u64,
132
133        /// Number of bytes of memory to allocate
134        space: u64,
135
136        /// Owner program account address
137        owner: Pubkey,
138    },
139
140    /// Consumes a stored nonce, replacing it with a successor
141    ///
142    /// # Account references
143    ///   0. `[WRITE]` Nonce account
144    ///   1. `[]` RecentBlockhashes sysvar
145    ///   2. `[SIGNER]` Nonce authority
146    AdvanceNonceAccount,
147
148    /// Withdraw funds from a nonce account
149    ///
150    /// # Account references
151    ///   0. `[WRITE]` Nonce account
152    ///   1. `[WRITE]` Recipient account
153    ///   2. `[]` RecentBlockhashes sysvar
154    ///   3. `[]` Rent sysvar
155    ///   4. `[SIGNER]` Nonce authority
156    ///
157    /// The `u64` parameter is the lamports to withdraw, which must leave the
158    /// account balance above the rent exempt reserve or at zero.
159    WithdrawNonceAccount(u64),
160
161    /// Drive state of Uninitialized nonce account to Initialized, setting the nonce value
162    ///
163    /// # Account references
164    ///   0. `[WRITE]` Nonce account
165    ///   1. `[]` RecentBlockhashes sysvar
166    ///   2. `[]` Rent sysvar
167    ///
168    /// The `Pubkey` parameter specifies the entity authorized to execute nonce
169    /// instruction on the account
170    ///
171    /// No signatures are required to execute this instruction, enabling derived
172    /// nonce account addresses
173    InitializeNonceAccount(Pubkey),
174
175    /// Change the entity authorized to execute nonce instructions on the account
176    ///
177    /// # Account references
178    ///   0. `[WRITE]` Nonce account
179    ///   1. `[SIGNER]` Nonce authority
180    ///
181    /// The `Pubkey` parameter identifies the entity to authorize
182    AuthorizeNonceAccount(Pubkey),
183
184    /// Allocate space in a (possibly new) account without funding
185    ///
186    /// # Account references
187    ///   0. `[WRITE, SIGNER]` New account
188    Allocate {
189        /// Number of bytes of memory to allocate
190        space: u64,
191    },
192
193    /// Allocate space for and assign an account at an address
194    /// derived from a base public key and a seed
195    ///
196    /// # Account references
197    ///   0. `[WRITE]` Allocated account
198    ///   1. `[SIGNER]` Base account
199    AllocateWithSeed {
200        /// Base public key
201        base: Pubkey,
202
203        /// String of ASCII chars, no longer than `pubkey::MAX_SEED_LEN`
204        seed: String,
205
206        /// Number of bytes of memory to allocate
207        space: u64,
208
209        /// Owner program account
210        owner: Pubkey,
211    },
212
213    /// Assign account to a program based on a seed
214    ///
215    /// # Account references
216    ///   0. `[WRITE]` Assigned account
217    ///   1. `[SIGNER]` Base account
218    AssignWithSeed {
219        /// Base public key
220        base: Pubkey,
221
222        /// String of ASCII chars, no longer than `pubkey::MAX_SEED_LEN`
223        seed: String,
224
225        /// Owner program account
226        owner: Pubkey,
227    },
228
229    /// Transfer lamports from a derived address
230    ///
231    /// # Account references
232    ///   0. `[WRITE]` Funding account
233    ///   1. `[SIGNER]` Base for funding account
234    ///   2. `[WRITE]` Recipient account
235    TransferWithSeed {
236        /// Amount to transfer
237        lamports: u64,
238
239        /// Seed to use to derive the funding account address
240        from_seed: String,
241
242        /// Owner to use to derive the funding account address
243        from_owner: Pubkey,
244    },
245
246    /// One-time idempotent upgrade of legacy nonce versions in order to bump
247    /// them out of chain blockhash domain.
248    ///
249    /// # Account references
250    ///   0. `[WRITE]` Nonce account
251    UpgradeNonceAccount,
252}
253
254/// Create an account.
255///
256/// This function produces an [`Instruction`] which must be submitted in a
257/// [`Transaction`] or [invoked] to take effect, containing a serialized
258/// [`SystemInstruction::CreateAccount`].
259///
260/// [`Transaction`]: https://docs.rs/solana-sdk/latest/solana_sdk/transaction/struct.Transaction.html
261/// [invoked]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke.html
262///
263/// Account creation typically involves three steps: [`allocate`] space,
264/// [`transfer`] lamports for rent, [`assign`] to its owning program. The
265/// [`create_account`] function does all three at once.
266///
267/// # Required signers
268///
269/// The `from_pubkey` and `to_pubkey` signers must sign the transaction.
270///
271/// # Examples
272///
273/// These examples use a single invocation of
274/// [`SystemInstruction::CreateAccount`] to create a new account, allocate some
275/// space, transfer it the minimum lamports for rent exemption, and assign it to
276/// the system program,
277///
278/// ## Example: client-side RPC
279///
280/// This example submits the instruction from an RPC client.
281/// The `payer` and `new_account` are signers.
282///
283/// ```
284/// # use solana_example_mocks::{solana_sdk, solana_rpc_client};
285/// use solana_rpc_client::rpc_client::RpcClient;
286/// use solana_sdk::{
287///     signature::{Keypair, Signer},
288///     transaction::Transaction,
289/// };
290/// use solana_system_interface::{instruction, program};
291/// use anyhow::Result;
292///
293/// fn create_account(
294///     client: &RpcClient,
295///     payer: &Keypair,
296///     new_account: &Keypair,
297///     space: u64,
298/// ) -> Result<()> {
299///     let rent = client.get_minimum_balance_for_rent_exemption(space.try_into()?)?;
300///     let instr = instruction::create_account(
301///         &payer.pubkey(),
302///         &new_account.pubkey(),
303///         rent,
304///         space,
305///         &program::ID,
306///     );
307///
308///     let blockhash = client.get_latest_blockhash()?;
309///     let tx = Transaction::new_signed_with_payer(
310///         &[instr],
311///         Some(&payer.pubkey()),
312///         &[payer, new_account],
313///         blockhash,
314///     );
315///
316///     let _sig = client.send_and_confirm_transaction(&tx)?;
317///
318///     Ok(())
319/// }
320/// # let payer = Keypair::new();
321/// # let new_account = Keypair::new();
322/// # let client = RpcClient::new(String::new());
323/// # create_account(&client, &payer, &new_account, 0);
324/// #
325/// # Ok::<(), anyhow::Error>(())
326/// ```
327///
328/// ## Example: on-chain program
329///
330/// This example submits the instruction from an on-chain Solana program. The
331/// created account is a [program derived address][pda]. The `payer` and
332/// `new_account_pda` are signers, with `new_account_pda` being signed for
333/// virtually by the program itself via [`invoke_signed`], `payer` being signed
334/// for by the client that submitted the transaction.
335///
336/// [pda]: https://docs.rs/solana-pubkey/latest/solana_pubkey/struct.Pubkey.html#method.find_program_address
337/// [`invoke_signed`]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke_signed.html
338///
339/// ```
340/// use borsh::{BorshDeserialize, BorshSerialize};
341/// use solana_account_info::{next_account_info, AccountInfo};
342/// use solana_cpi::invoke_signed;
343/// use solana_program_entrypoint::entrypoint;
344/// use solana_program_error::ProgramResult;
345/// use solana_pubkey::Pubkey;
346/// use solana_system_interface::{instruction, program};
347/// use solana_sysvar::{rent::Rent, Sysvar};
348///
349/// #[derive(BorshSerialize, BorshDeserialize, Debug)]
350/// pub struct CreateAccountInstruction {
351///     /// The PDA seed used to distinguish the new account from other PDAs
352///     pub new_account_seed: [u8; 16],
353///     /// The PDA bump seed
354///     pub new_account_bump_seed: u8,
355///     /// The amount of space to allocate for `new_account_pda`
356///     pub space: u64,
357/// }
358///
359/// entrypoint!(process_instruction);
360///
361/// fn process_instruction(
362///     program_id: &Pubkey,
363///     accounts: &[AccountInfo],
364///     instruction_data: &[u8],
365/// ) -> ProgramResult {
366///     let instr = CreateAccountInstruction::deserialize(&mut &instruction_data[..])?;
367///
368///     let account_info_iter = &mut accounts.iter();
369///
370///     let payer = next_account_info(account_info_iter)?;
371///     let new_account_pda = next_account_info(account_info_iter)?;
372///     let system_account = next_account_info(account_info_iter)?;
373///
374///     assert!(payer.is_signer);
375///     assert!(payer.is_writable);
376///     // Note that `new_account_pda` is not a signer yet.
377///     // This program will sign for it via `invoke_signed`.
378///     assert!(!new_account_pda.is_signer);
379///     assert!(new_account_pda.is_writable);
380///     assert!(program::check_id(system_account.key));
381///
382///     let new_account_seed = &instr.new_account_seed;
383///     let new_account_bump_seed = instr.new_account_bump_seed;
384///
385///     let rent = Rent::get()?
386///         .minimum_balance(instr.space.try_into().expect("overflow"));
387///
388///     invoke_signed(
389///         &instruction::create_account(
390///             payer.key,
391///             new_account_pda.key,
392///             rent,
393///             instr.space,
394///             &program::ID
395///         ),
396///         &[payer.clone(), new_account_pda.clone()],
397///         &[&[
398///             payer.key.as_ref(),
399///             new_account_seed,
400///             &[new_account_bump_seed],
401///         ]],
402///     )?;
403///
404///     Ok(())
405/// }
406/// ```
407#[cfg(feature = "bincode")]
408pub fn create_account(
409    from_pubkey: &Pubkey,
410    to_pubkey: &Pubkey,
411    lamports: u64,
412    space: u64,
413    owner: &Pubkey,
414) -> Instruction {
415    let account_metas = vec![
416        AccountMeta::new(*from_pubkey, true),
417        AccountMeta::new(*to_pubkey, true),
418    ];
419    Instruction::new_with_bincode(
420        ID,
421        &SystemInstruction::CreateAccount {
422            lamports,
423            space,
424            owner: *owner,
425        },
426        account_metas,
427    )
428}
429
430// we accept `to` as a parameter so that callers do their own error handling when
431//   calling create_with_seed()
432#[cfg(feature = "bincode")]
433pub fn create_account_with_seed(
434    from_pubkey: &Pubkey,
435    to_pubkey: &Pubkey, // must match create_with_seed(base, seed, owner)
436    base: &Pubkey,
437    seed: &str,
438    lamports: u64,
439    space: u64,
440    owner: &Pubkey,
441) -> Instruction {
442    let account_metas = vec![
443        AccountMeta::new(*from_pubkey, true),
444        AccountMeta::new(*to_pubkey, false),
445        AccountMeta::new_readonly(*base, true),
446    ];
447
448    Instruction::new_with_bincode(
449        ID,
450        &SystemInstruction::CreateAccountWithSeed {
451            base: *base,
452            seed: seed.to_string(),
453            lamports,
454            space,
455            owner: *owner,
456        },
457        account_metas,
458    )
459}
460
461/// Assign ownership of an account from the system program.
462///
463/// This function produces an [`Instruction`] which must be submitted in a
464/// [`Transaction`] or [invoked] to take effect, containing a serialized
465/// [`SystemInstruction::Assign`].
466///
467/// [`Transaction`]: https://docs.rs/solana-sdk/latest/solana_sdk/transaction/struct.Transaction.html
468/// [invoked]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke.html
469///
470/// # Required signers
471///
472/// The `pubkey` signer must sign the transaction.
473///
474/// # Examples
475///
476/// These examples allocate space for an account, transfer it the minimum
477/// balance for rent exemption, and assign the account to a program.
478///
479/// ## Example: client-side RPC
480///
481/// This example submits the instructions from an RPC client.
482/// It assigns the account to a provided program account.
483/// The `payer` and `new_account` are signers.
484///
485/// ```
486/// # use solana_example_mocks::{solana_sdk, solana_rpc_client};
487/// use solana_rpc_client::rpc_client::RpcClient;
488/// use solana_pubkey::Pubkey;
489/// use solana_sdk::{
490///     signature::{Keypair, Signer},
491///     transaction::Transaction,
492/// };
493/// use solana_system_interface::instruction;
494/// use anyhow::Result;
495///
496/// fn create_account(
497///     client: &RpcClient,
498///     payer: &Keypair,
499///     new_account: &Keypair,
500///     owning_program: &Pubkey,
501///     space: u64,
502/// ) -> Result<()> {
503///     let rent = client.get_minimum_balance_for_rent_exemption(space.try_into()?)?;
504///
505///     let transfer_instr = instruction::transfer(
506///         &payer.pubkey(),
507///         &new_account.pubkey(),
508///         rent,
509///     );
510///
511///     let allocate_instr = instruction::allocate(
512///         &new_account.pubkey(),
513///         space,
514///     );
515///
516///     let assign_instr = instruction::assign(
517///         &new_account.pubkey(),
518///         owning_program,
519///     );
520///
521///     let blockhash = client.get_latest_blockhash()?;
522///     let tx = Transaction::new_signed_with_payer(
523///         &[transfer_instr, allocate_instr, assign_instr],
524///         Some(&payer.pubkey()),
525///         &[payer, new_account],
526///         blockhash,
527///     );
528///
529///     let _sig = client.send_and_confirm_transaction(&tx)?;
530///
531///     Ok(())
532/// }
533/// # let client = RpcClient::new(String::new());
534/// # let payer = Keypair::new();
535/// # let new_account = Keypair::new();
536/// # let owning_program = Pubkey::new_unique();
537/// # create_account(&client, &payer, &new_account, &owning_program, 1);
538/// #
539/// # Ok::<(), anyhow::Error>(())
540/// ```
541///
542/// ## Example: on-chain program
543///
544/// This example submits the instructions from an on-chain Solana program. The
545/// created account is a [program derived address][pda], funded by `payer`, and
546/// assigned to the running program. The `payer` and `new_account_pda` are
547/// signers, with `new_account_pda` being signed for virtually by the program
548/// itself via [`invoke_signed`], `payer` being signed for by the client that
549/// submitted the transaction.
550///
551/// [pda]: https://docs.rs/solana-pubkey/latest/solana_pubkey/struct.Pubkey.html#method.find_program_address
552/// [`invoke_signed`]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke_signed.html
553///
554/// ```
555/// use borsh::{BorshDeserialize, BorshSerialize};
556/// use solana_account_info::{next_account_info, AccountInfo};
557/// use solana_cpi::invoke_signed;
558/// use solana_program_entrypoint::entrypoint;
559/// use solana_program_error::ProgramResult;
560/// use solana_pubkey::Pubkey;
561/// use solana_system_interface::{instruction, program};
562/// use solana_sysvar::{rent::Rent, Sysvar};
563///
564/// #[derive(BorshSerialize, BorshDeserialize, Debug)]
565/// pub struct CreateAccountInstruction {
566///     /// The PDA seed used to distinguish the new account from other PDAs
567///     pub new_account_seed: [u8; 16],
568///     /// The PDA bump seed
569///     pub new_account_bump_seed: u8,
570///     /// The amount of space to allocate for `new_account_pda`
571///     pub space: u64,
572/// }
573///
574/// entrypoint!(process_instruction);
575///
576/// fn process_instruction(
577///     program_id: &Pubkey,
578///     accounts: &[AccountInfo],
579///     instruction_data: &[u8],
580/// ) -> ProgramResult {
581///     let instr = CreateAccountInstruction::deserialize(&mut &instruction_data[..])?;
582///
583///     let account_info_iter = &mut accounts.iter();
584///
585///     let payer = next_account_info(account_info_iter)?;
586///     let new_account_pda = next_account_info(account_info_iter)?;
587///     let system_account = next_account_info(account_info_iter)?;
588///
589///     assert!(payer.is_signer);
590///     assert!(payer.is_writable);
591///     // Note that `new_account_pda` is not a signer yet.
592///     // This program will sign for it via `invoke_signed`.
593///     assert!(!new_account_pda.is_signer);
594///     assert!(new_account_pda.is_writable);
595///     assert!(program::check_id(system_account.key));
596///
597///     let new_account_seed = &instr.new_account_seed;
598///     let new_account_bump_seed = instr.new_account_bump_seed;
599///
600///     let rent = Rent::get()?
601///         .minimum_balance(instr.space.try_into().expect("overflow"));
602///
603///     invoke_signed(
604///         &instruction::create_account(
605///             payer.key,
606///             new_account_pda.key,
607///             rent,
608///             instr.space,
609///             &program::ID
610///         ),
611///         &[payer.clone(), new_account_pda.clone()],
612///         &[&[
613///             payer.key.as_ref(),
614///             new_account_seed,
615///             &[new_account_bump_seed],
616///         ]],
617///     )?;
618///
619///     Ok(())
620/// }
621/// ```
622#[cfg(feature = "bincode")]
623pub fn assign(pubkey: &Pubkey, owner: &Pubkey) -> Instruction {
624    let account_metas = vec![AccountMeta::new(*pubkey, true)];
625    Instruction::new_with_bincode(
626        ID,
627        &SystemInstruction::Assign { owner: *owner },
628        account_metas,
629    )
630}
631
632#[cfg(feature = "bincode")]
633pub fn assign_with_seed(
634    address: &Pubkey, // must match create_with_seed(base, seed, owner)
635    base: &Pubkey,
636    seed: &str,
637    owner: &Pubkey,
638) -> Instruction {
639    let account_metas = vec![
640        AccountMeta::new(*address, false),
641        AccountMeta::new_readonly(*base, true),
642    ];
643    Instruction::new_with_bincode(
644        ID,
645        &SystemInstruction::AssignWithSeed {
646            base: *base,
647            seed: seed.to_string(),
648            owner: *owner,
649        },
650        account_metas,
651    )
652}
653
654/// Transfer lamports from an account owned by the system program.
655///
656/// This function produces an [`Instruction`] which must be submitted in a
657/// [`Transaction`] or [invoked] to take effect, containing a serialized
658/// [`SystemInstruction::Transfer`].
659///
660/// [`Transaction`]: https://docs.rs/solana-sdk/latest/solana_sdk/transaction/struct.Transaction.html
661/// [invoked]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke.html
662///
663/// # Required signers
664///
665/// The `from_pubkey` signer must sign the transaction.
666///
667/// # Examples
668///
669/// These examples allocate space for an account, transfer it the minimum
670/// balance for rent exemption, and assign the account to a program.
671///
672/// # Example: client-side RPC
673///
674/// This example submits the instructions from an RPC client.
675/// It assigns the account to a provided program account.
676/// The `payer` and `new_account` are signers.
677///
678/// ```
679/// # use solana_example_mocks::{solana_sdk, solana_rpc_client};
680/// use solana_rpc_client::rpc_client::RpcClient;
681/// use solana_pubkey::Pubkey;
682/// use solana_sdk::{
683///     signature::{Keypair, Signer},
684///     transaction::Transaction,
685/// };
686/// use solana_system_interface::instruction;
687/// use anyhow::Result;
688///
689/// fn create_account(
690///     client: &RpcClient,
691///     payer: &Keypair,
692///     new_account: &Keypair,
693///     owning_program: &Pubkey,
694///     space: u64,
695/// ) -> Result<()> {
696///     let rent = client.get_minimum_balance_for_rent_exemption(space.try_into()?)?;
697///
698///     let transfer_instr = instruction::transfer(
699///         &payer.pubkey(),
700///         &new_account.pubkey(),
701///         rent,
702///     );
703///
704///     let allocate_instr = instruction::allocate(
705///         &new_account.pubkey(),
706///         space,
707///     );
708///
709///     let assign_instr = instruction::assign(
710///         &new_account.pubkey(),
711///         owning_program,
712///     );
713///
714///     let blockhash = client.get_latest_blockhash()?;
715///     let tx = Transaction::new_signed_with_payer(
716///         &[transfer_instr, allocate_instr, assign_instr],
717///         Some(&payer.pubkey()),
718///         &[payer, new_account],
719///         blockhash,
720///     );
721///
722///     let _sig = client.send_and_confirm_transaction(&tx)?;
723///
724///     Ok(())
725/// }
726/// # let client = RpcClient::new(String::new());
727/// # let payer = Keypair::new();
728/// # let new_account = Keypair::new();
729/// # let owning_program = Pubkey::new_unique();
730/// # create_account(&client, &payer, &new_account, &owning_program, 1);
731/// #
732/// # Ok::<(), anyhow::Error>(())
733/// ```
734///
735/// ## Example: on-chain program
736///
737/// This example submits the instructions from an on-chain Solana program. The
738/// created account is a [program derived address][pda], funded by `payer`, and
739/// assigned to the running program. The `payer` and `new_account_pda` are
740/// signers, with `new_account_pda` being signed for virtually by the program
741/// itself via [`invoke_signed`], `payer` being signed for by the client that
742/// submitted the transaction.
743///
744/// [pda]: https://docs.rs/solana-pubkey/latest/solana_pubkey/struct.Pubkey.html#method.find_program_address
745/// [`invoke_signed`]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke_signed.html
746///
747/// ```
748/// # use borsh::{BorshDeserialize, BorshSerialize};
749/// use solana_account_info::{next_account_info, AccountInfo};
750/// use solana_cpi::invoke_signed;
751/// use solana_program_entrypoint::entrypoint;
752/// use solana_program_error::ProgramResult;
753/// use solana_pubkey::Pubkey;
754/// use solana_system_interface::{instruction, program};
755/// use solana_sysvar::{rent::Rent, Sysvar};
756///
757/// #[derive(BorshSerialize, BorshDeserialize, Debug)]
758/// # #[borsh(crate = "borsh")]
759/// pub struct CreateAccountInstruction {
760///     /// The PDA seed used to distinguish the new account from other PDAs
761///     pub new_account_seed: [u8; 16],
762///     /// The PDA bump seed
763///     pub new_account_bump_seed: u8,
764///     /// The amount of space to allocate for `new_account_pda`
765///     pub space: u64,
766/// }
767///
768/// entrypoint!(process_instruction);
769///
770/// fn process_instruction(
771///     program_id: &Pubkey,
772///     accounts: &[AccountInfo],
773///     instruction_data: &[u8],
774/// ) -> ProgramResult {
775///     let instr = CreateAccountInstruction::deserialize(&mut &instruction_data[..])?;
776///
777///     let account_info_iter = &mut accounts.iter();
778///
779///     let payer = next_account_info(account_info_iter)?;
780///     let new_account_pda = next_account_info(account_info_iter)?;
781///     let system_account = next_account_info(account_info_iter)?;
782///
783///     assert!(payer.is_signer);
784///     assert!(payer.is_writable);
785///     // Note that `new_account_pda` is not a signer yet.
786///     // This program will sign for it via `invoke_signed`.
787///     assert!(!new_account_pda.is_signer);
788///     assert!(new_account_pda.is_writable);
789///     assert!(program::check_id(system_account.key));
790///
791///     let new_account_seed = &instr.new_account_seed;
792///     let new_account_bump_seed = instr.new_account_bump_seed;
793///
794///     let rent = Rent::get()?
795///         .minimum_balance(instr.space.try_into().expect("overflow"));
796///
797///     invoke_signed(
798///         &instruction::create_account(
799///             payer.key,
800///             new_account_pda.key,
801///             rent,
802///             instr.space,
803///             &program::ID
804///         ),
805///         &[payer.clone(), new_account_pda.clone()],
806///         &[&[
807///             payer.key.as_ref(),
808///             new_account_seed,
809///             &[new_account_bump_seed],
810///         ]],
811///     )?;
812///
813///     Ok(())
814/// }
815/// ```
816#[cfg(feature = "bincode")]
817pub fn transfer(from_pubkey: &Pubkey, to_pubkey: &Pubkey, lamports: u64) -> Instruction {
818    let account_metas = vec![
819        AccountMeta::new(*from_pubkey, true),
820        AccountMeta::new(*to_pubkey, false),
821    ];
822    Instruction::new_with_bincode(ID, &SystemInstruction::Transfer { lamports }, account_metas)
823}
824
825#[cfg(feature = "bincode")]
826pub fn transfer_with_seed(
827    from_pubkey: &Pubkey, // must match create_with_seed(base, seed, owner)
828    from_base: &Pubkey,
829    from_seed: String,
830    from_owner: &Pubkey,
831    to_pubkey: &Pubkey,
832    lamports: u64,
833) -> Instruction {
834    let account_metas = vec![
835        AccountMeta::new(*from_pubkey, false),
836        AccountMeta::new_readonly(*from_base, true),
837        AccountMeta::new(*to_pubkey, false),
838    ];
839    Instruction::new_with_bincode(
840        ID,
841        &SystemInstruction::TransferWithSeed {
842            lamports,
843            from_seed,
844            from_owner: *from_owner,
845        },
846        account_metas,
847    )
848}
849
850/// Allocate space for an account.
851///
852/// This function produces an [`Instruction`] which must be submitted in a
853/// [`Transaction`] or [invoked] to take effect, containing a serialized
854/// [`SystemInstruction::Allocate`].
855///
856/// [`Transaction`]: https://docs.rs/solana-sdk/latest/solana_sdk/transaction/struct.Transaction.html
857/// [invoked]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke.html
858///
859/// The transaction will fail if the account already has size greater than 0,
860/// or if the requested size is greater than [`super::MAX_PERMITTED_DATA_LENGTH`].
861///
862/// # Required signers
863///
864/// The `pubkey` signer must sign the transaction.
865///
866/// # Examples
867///
868/// These examples allocate space for an account, transfer it the minimum
869/// balance for rent exemption, and assign the account to a program.
870///
871/// # Example: client-side RPC
872///
873/// This example submits the instructions from an RPC client.
874/// It assigns the account to a provided program account.
875/// The `payer` and `new_account` are signers.
876///
877/// ```
878/// # use solana_example_mocks::{solana_sdk, solana_rpc_client};
879/// use solana_rpc_client::rpc_client::RpcClient;
880/// use solana_pubkey::Pubkey;
881/// use solana_sdk::{
882///     signature::{Keypair, Signer},
883///     transaction::Transaction,
884/// };
885/// use solana_system_interface::instruction;
886/// use anyhow::Result;
887///
888/// fn create_account(
889///     client: &RpcClient,
890///     payer: &Keypair,
891///     new_account: &Keypair,
892///     owning_program: &Pubkey,
893///     space: u64,
894/// ) -> Result<()> {
895///     let rent = client.get_minimum_balance_for_rent_exemption(space.try_into()?)?;
896///
897///     let transfer_instr = instruction::transfer(
898///         &payer.pubkey(),
899///         &new_account.pubkey(),
900///         rent,
901///     );
902///
903///     let allocate_instr = instruction::allocate(
904///         &new_account.pubkey(),
905///         space,
906///     );
907///
908///     let assign_instr = instruction::assign(
909///         &new_account.pubkey(),
910///         owning_program,
911///     );
912///
913///     let blockhash = client.get_latest_blockhash()?;
914///     let tx = Transaction::new_signed_with_payer(
915///         &[transfer_instr, allocate_instr, assign_instr],
916///         Some(&payer.pubkey()),
917///         &[payer, new_account],
918///         blockhash,
919///     );
920///
921///     let _sig = client.send_and_confirm_transaction(&tx)?;
922///
923///     Ok(())
924/// }
925/// # let client = RpcClient::new(String::new());
926/// # let payer = Keypair::new();
927/// # let new_account = Keypair::new();
928/// # let owning_program = Pubkey::new_unique();
929/// # create_account(&client, &payer, &new_account, &owning_program, 1);
930/// #
931/// # Ok::<(), anyhow::Error>(())
932/// ```
933///
934/// ## Example: on-chain program
935///
936/// This example submits the instructions from an on-chain Solana program. The
937/// created account is a [program derived address][pda], funded by `payer`, and
938/// assigned to the running program. The `payer` and `new_account_pda` are
939/// signers, with `new_account_pda` being signed for virtually by the program
940/// itself via [`invoke_signed`], `payer` being signed for by the client that
941/// submitted the transaction.
942///
943/// [pda]: https://docs.rs/solana-pubkey/latest/solana_pubkey/struct.Pubkey.html#method.find_program_address
944/// [`invoke_signed`]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke_signed.html
945///
946/// ```
947/// use borsh::{BorshDeserialize, BorshSerialize};
948/// use solana_account_info::{next_account_info, AccountInfo};
949/// use solana_cpi::invoke_signed;
950/// use solana_program_entrypoint::entrypoint;
951/// use solana_program_error::ProgramResult;
952/// use solana_pubkey::Pubkey;
953/// use solana_system_interface::{instruction, program};
954/// use solana_sysvar::{rent::Rent, Sysvar};
955///
956/// #[derive(BorshSerialize, BorshDeserialize, Debug)]
957/// pub struct CreateAccountInstruction {
958///     /// The PDA seed used to distinguish the new account from other PDAs
959///     pub new_account_seed: [u8; 16],
960///     /// The PDA bump seed
961///     pub new_account_bump_seed: u8,
962///     /// The amount of space to allocate for `new_account_pda`
963///     pub space: u64,
964/// }
965///
966/// entrypoint!(process_instruction);
967///
968/// fn process_instruction(
969///     program_id: &Pubkey,
970///     accounts: &[AccountInfo],
971///     instruction_data: &[u8],
972/// ) -> ProgramResult {
973///     let instr = CreateAccountInstruction::deserialize(&mut &instruction_data[..])?;
974///
975///     let account_info_iter = &mut accounts.iter();
976///
977///     let payer = next_account_info(account_info_iter)?;
978///     let new_account_pda = next_account_info(account_info_iter)?;
979///     let system_account = next_account_info(account_info_iter)?;
980///
981///     assert!(payer.is_signer);
982///     assert!(payer.is_writable);
983///     // Note that `new_account_pda` is not a signer yet.
984///     // This program will sign for it via `invoke_signed`.
985///     assert!(!new_account_pda.is_signer);
986///     assert!(new_account_pda.is_writable);
987///     assert!(program::check_id(system_account.key));
988///
989///     let new_account_seed = &instr.new_account_seed;
990///     let new_account_bump_seed = instr.new_account_bump_seed;
991///
992///     let rent = Rent::get()?
993///         .minimum_balance(instr.space.try_into().expect("overflow"));
994///
995///     invoke_signed(
996///         &instruction::create_account(
997///             payer.key,
998///             new_account_pda.key,
999///             rent,
1000///             instr.space,
1001///             &program::ID
1002///         ),
1003///         &[payer.clone(), new_account_pda.clone()],
1004///         &[&[
1005///             payer.key.as_ref(),
1006///             new_account_seed,
1007///             &[new_account_bump_seed],
1008///         ]],
1009///     )?;
1010///
1011///     Ok(())
1012/// }
1013/// ```
1014#[cfg(feature = "bincode")]
1015pub fn allocate(pubkey: &Pubkey, space: u64) -> Instruction {
1016    let account_metas = vec![AccountMeta::new(*pubkey, true)];
1017    Instruction::new_with_bincode(ID, &SystemInstruction::Allocate { space }, account_metas)
1018}
1019
1020#[cfg(feature = "bincode")]
1021pub fn allocate_with_seed(
1022    address: &Pubkey, // must match create_with_seed(base, seed, owner)
1023    base: &Pubkey,
1024    seed: &str,
1025    space: u64,
1026    owner: &Pubkey,
1027) -> Instruction {
1028    let account_metas = vec![
1029        AccountMeta::new(*address, false),
1030        AccountMeta::new_readonly(*base, true),
1031    ];
1032    Instruction::new_with_bincode(
1033        ID,
1034        &SystemInstruction::AllocateWithSeed {
1035            base: *base,
1036            seed: seed.to_string(),
1037            space,
1038            owner: *owner,
1039        },
1040        account_metas,
1041    )
1042}
1043
1044/// Transfer lamports from an account owned by the system program to multiple accounts.
1045///
1046/// This function produces a vector of [`Instruction`]s which must be submitted
1047/// in a [`Transaction`] or [invoked] to take effect, containing serialized
1048/// [`SystemInstruction::Transfer`]s.
1049///
1050/// [`Transaction`]: https://docs.rs/solana-sdk/latest/solana_sdk/transaction/struct.Transaction.html
1051/// [invoked]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke.html
1052///
1053/// # Required signers
1054///
1055/// The `from_pubkey` signer must sign the transaction.
1056///
1057/// # Examples
1058///
1059/// ## Example: client-side RPC
1060///
1061/// This example performs multiple transfers in a single transaction.
1062///
1063/// ```
1064/// # use solana_example_mocks::{solana_sdk, solana_rpc_client};
1065/// use solana_rpc_client::rpc_client::RpcClient;
1066/// use solana_pubkey::Pubkey;
1067/// use solana_sdk::{
1068///     signature::{Keypair, Signer},
1069///     transaction::Transaction,
1070/// };
1071/// use solana_system_interface::instruction;
1072/// use anyhow::Result;
1073///
1074/// fn transfer_lamports_to_many(
1075///     client: &RpcClient,
1076///     from: &Keypair,
1077///     to_and_amount: &[(Pubkey, u64)],
1078/// ) -> Result<()> {
1079///     let instrs = instruction::transfer_many(&from.pubkey(), to_and_amount);
1080///
1081///     let blockhash = client.get_latest_blockhash()?;
1082///     let tx = Transaction::new_signed_with_payer(
1083///         &instrs,
1084///         Some(&from.pubkey()),
1085///         &[from],
1086///         blockhash,
1087///     );
1088///
1089///     let _sig = client.send_and_confirm_transaction(&tx)?;
1090///
1091///     Ok(())
1092/// }
1093/// # let from = Keypair::new();
1094/// # let to_and_amount = vec![
1095/// #     (Pubkey::new_unique(), 1_000),
1096/// #     (Pubkey::new_unique(), 2_000),
1097/// #     (Pubkey::new_unique(), 3_000),
1098/// # ];
1099/// # let client = RpcClient::new(String::new());
1100/// # transfer_lamports_to_many(&client, &from, &to_and_amount);
1101/// #
1102/// # Ok::<(), anyhow::Error>(())
1103/// ```
1104///
1105/// ## Example: on-chain program
1106///
1107/// This example makes multiple transfers out of a "bank" account,
1108/// a [program derived address][pda] owned by the calling program.
1109/// This example submits the instructions from an on-chain Solana program. The
1110/// created account is a [program derived address][pda], and it is assigned to
1111/// the running program. The `payer` and `new_account_pda` are signers, with
1112/// `new_account_pda` being signed for virtually by the program itself via
1113/// [`invoke_signed`], `payer` being signed for by the client that submitted the
1114/// transaction.
1115///
1116/// [pda]: https://docs.rs/solana-pubkey/latest/solana_pubkey/struct.Pubkey.html#method.find_program_address
1117/// [`invoke_signed`]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke_signed.html
1118///
1119/// ```
1120/// # use borsh::{BorshDeserialize, BorshSerialize};
1121/// use solana_account_info::{next_account_info, next_account_infos, AccountInfo};
1122/// use solana_cpi::invoke_signed;
1123/// use solana_program_entrypoint::entrypoint;
1124/// use solana_program_error::ProgramResult;
1125/// use solana_pubkey::Pubkey;
1126/// use solana_system_interface::{instruction, program};
1127///
1128/// /// # Accounts
1129/// ///
1130/// /// - 0: bank_pda - writable
1131/// /// - 1: system_program - executable
1132/// /// - *: to - writable
1133/// # #[derive(BorshSerialize, BorshDeserialize, Debug)]
1134/// # #[borsh(crate = "borsh")]
1135/// pub struct TransferLamportsToManyInstruction {
1136///     pub bank_pda_bump_seed: u8,
1137///     pub amount_list: Vec<u64>,
1138/// }
1139///
1140/// entrypoint!(process_instruction);
1141///
1142/// fn process_instruction(
1143///     program_id: &Pubkey,
1144///     accounts: &[AccountInfo],
1145///     instruction_data: &[u8],
1146/// ) -> ProgramResult {
1147///     let instr = TransferLamportsToManyInstruction::deserialize(&mut &instruction_data[..])?;
1148///
1149///     let account_info_iter = &mut accounts.iter();
1150///
1151///     let bank_pda = next_account_info(account_info_iter)?;
1152///     let bank_pda_bump_seed = instr.bank_pda_bump_seed;
1153///     let system_account = next_account_info(account_info_iter)?;
1154///
1155///     assert!(program::check_id(system_account.key));
1156///
1157///     let to_accounts = next_account_infos(account_info_iter, account_info_iter.len())?;
1158///
1159///     for to_account in to_accounts {
1160///          assert!(to_account.is_writable);
1161///          // ... do other verification ...
1162///     }
1163///
1164///     let to_and_amount = to_accounts
1165///         .iter()
1166///         .zip(instr.amount_list.iter())
1167///         .map(|(to, amount)| (*to.key, *amount))
1168///         .collect::<Vec<(Pubkey, u64)>>();
1169///
1170///     let instrs = instruction::transfer_many(bank_pda.key, to_and_amount.as_ref());
1171///
1172///     for instr in instrs {
1173///         invoke_signed(&instr, accounts, &[&[b"bank", &[bank_pda_bump_seed]]])?;
1174///     }
1175///
1176///     Ok(())
1177/// }
1178/// ```
1179#[cfg(feature = "bincode")]
1180pub fn transfer_many(from_pubkey: &Pubkey, to_lamports: &[(Pubkey, u64)]) -> Vec<Instruction> {
1181    to_lamports
1182        .iter()
1183        .map(|(to_pubkey, lamports)| transfer(from_pubkey, to_pubkey, *lamports))
1184        .collect()
1185}
1186
1187#[cfg(feature = "bincode")]
1188pub fn create_nonce_account_with_seed(
1189    from_pubkey: &Pubkey,
1190    nonce_pubkey: &Pubkey,
1191    base: &Pubkey,
1192    seed: &str,
1193    authority: &Pubkey,
1194    lamports: u64,
1195) -> Vec<Instruction> {
1196    vec![
1197        create_account_with_seed(
1198            from_pubkey,
1199            nonce_pubkey,
1200            base,
1201            seed,
1202            lamports,
1203            NONCE_STATE_SIZE as u64,
1204            &ID,
1205        ),
1206        Instruction::new_with_bincode(
1207            ID,
1208            &SystemInstruction::InitializeNonceAccount(*authority),
1209            vec![
1210                AccountMeta::new(*nonce_pubkey, false),
1211                #[allow(deprecated)]
1212                AccountMeta::new_readonly(RECENT_BLOCKHASHES_ID, false),
1213                AccountMeta::new_readonly(RENT_ID, false),
1214            ],
1215        ),
1216    ]
1217}
1218
1219/// Create an account containing a durable transaction nonce.
1220///
1221/// This function produces a vector of [`Instruction`]s which must be submitted
1222/// in a [`Transaction`] or [invoked] to take effect, containing a serialized
1223/// [`SystemInstruction::CreateAccount`] and
1224/// [`SystemInstruction::InitializeNonceAccount`].
1225///
1226/// [`Transaction`]: https://docs.rs/solana-sdk/latest/solana_sdk/transaction/struct.Transaction.html
1227/// [invoked]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke.html
1228///
1229/// A [durable transaction nonce][dtn] is a special account that enables
1230/// execution of transactions that have been signed in the past.
1231///
1232/// Standard Solana transactions include a [recent blockhash][rbh] (sometimes
1233/// referred to as a _[nonce]_). During execution the Solana runtime verifies
1234/// the recent blockhash is approximately less than two minutes old, and that in
1235/// those two minutes no other identical transaction with the same blockhash has
1236/// been executed. These checks prevent accidental replay of transactions.
1237/// Consequently, it is not possible to sign a transaction, wait more than two
1238/// minutes, then successfully execute that transaction.
1239///
1240/// [dtn]: https://docs.solanalabs.com/implemented-proposals/durable-tx-nonces
1241/// [rbh]: https://docs.rs/solana-program/latest/solana_program/message/legacy/struct.Message.html#structfield.recent_blockhash
1242/// [nonce]: https://en.wikipedia.org/wiki/Cryptographic_nonce
1243///
1244/// Durable transaction nonces are an alternative to the standard recent
1245/// blockhash nonce. They are stored in accounts on chain, and every time they
1246/// are used their value is changed to a new value for their next use. The
1247/// runtime verifies that each durable nonce value is only used once, and there
1248/// are no restrictions on how "old" the nonce is. Because they are stored on
1249/// chain and require additional instructions to use, transacting with durable
1250/// transaction nonces is more expensive than with standard transactions.
1251///
1252/// The value of the durable nonce is itself a blockhash and is accessible via
1253/// the [`blockhash`] field of [`nonce::state::Data`], which is deserialized
1254/// from the nonce account data.
1255///
1256/// [`blockhash`]: https://docs.rs/solana-program/latest/solana_program/message/legacy/struct.Message.html#structfield.recent_blockhash
1257/// [`nonce::state::Data`]: https://docs.rs/solana-nonce/latest/solana_nonce/state/struct.Data.html
1258///
1259/// The basic durable transaction nonce lifecycle is
1260///
1261/// 1) Create the nonce account with the `create_nonce_account` instruction.
1262/// 2) Submit specially-formed transactions that include the
1263///    [`advance_nonce_account`] instruction.
1264/// 3) Destroy the nonce account by withdrawing its lamports with the
1265///    [`withdraw_nonce_account`] instruction.
1266///
1267/// Nonce accounts have an associated _authority_ account, which is stored in
1268/// their account data, and can be changed with the [`authorize_nonce_account`]
1269/// instruction. The authority must sign transactions that include the
1270/// `advance_nonce_account`, `authorize_nonce_account` and
1271/// `withdraw_nonce_account` instructions.
1272///
1273/// Nonce accounts are owned by the system program.
1274///
1275/// This constructor creates a [`SystemInstruction::CreateAccount`] instruction
1276/// and a [`SystemInstruction::InitializeNonceAccount`] instruction.
1277///
1278/// # Required signers
1279///
1280/// The `from_pubkey` and `nonce_pubkey` signers must sign the transaction.
1281///
1282/// # Examples
1283///
1284/// Create a nonce account from an off-chain client:
1285///
1286/// ```
1287/// # use solana_example_mocks::solana_keypair;
1288/// # use solana_example_mocks::solana_signer;
1289/// # use solana_example_mocks::solana_rpc_client;
1290/// # use solana_example_mocks::solana_transaction;
1291/// use solana_keypair::Keypair;
1292/// use solana_nonce::state::State;
1293/// use solana_rpc_client::rpc_client::RpcClient;
1294/// use solana_signer::Signer;
1295/// use solana_system_interface::instruction;
1296/// use solana_transaction::Transaction;
1297/// use anyhow::Result;
1298///
1299/// fn submit_create_nonce_account_tx(
1300///     client: &RpcClient,
1301///     payer: &Keypair,
1302/// ) -> Result<()> {
1303///
1304///     let nonce_account = Keypair::new();
1305///
1306///     let nonce_rent = client.get_minimum_balance_for_rent_exemption(State::size())?;
1307///     let instr = instruction::create_nonce_account(
1308///         &payer.pubkey(),
1309///         &nonce_account.pubkey(),
1310///         &payer.pubkey(), // Make the fee payer the nonce account authority
1311///         nonce_rent,
1312///     );
1313///
1314///     let mut tx = Transaction::new_with_payer(&instr, Some(&payer.pubkey()));
1315///
1316///     let blockhash = client.get_latest_blockhash()?;
1317///     tx.try_sign(&[&nonce_account, payer], blockhash)?;
1318///
1319///     client.send_and_confirm_transaction(&tx)?;
1320///
1321///     Ok(())
1322/// }
1323/// #
1324/// # let client = RpcClient::new(String::new());
1325/// # let payer = Keypair::new();
1326/// # submit_create_nonce_account_tx(&client, &payer)?;
1327/// #
1328/// # Ok::<(), anyhow::Error>(())
1329/// ```
1330#[cfg(feature = "bincode")]
1331pub fn create_nonce_account(
1332    from_pubkey: &Pubkey,
1333    nonce_pubkey: &Pubkey,
1334    authority: &Pubkey,
1335    lamports: u64,
1336) -> Vec<Instruction> {
1337    vec![
1338        create_account(
1339            from_pubkey,
1340            nonce_pubkey,
1341            lamports,
1342            NONCE_STATE_SIZE as u64,
1343            &ID,
1344        ),
1345        Instruction::new_with_bincode(
1346            ID,
1347            &SystemInstruction::InitializeNonceAccount(*authority),
1348            vec![
1349                AccountMeta::new(*nonce_pubkey, false),
1350                #[allow(deprecated)]
1351                AccountMeta::new_readonly(RECENT_BLOCKHASHES_ID, false),
1352                AccountMeta::new_readonly(RENT_ID, false),
1353            ],
1354        ),
1355    ]
1356}
1357
1358/// Advance the value of a durable transaction nonce.
1359///
1360/// This function produces an [`Instruction`] which must be submitted in a
1361/// [`Transaction`] or [invoked] to take effect, containing a serialized
1362/// [`SystemInstruction::AdvanceNonceAccount`].
1363///
1364/// [`Transaction`]: https://docs.rs/solana-sdk/latest/solana_sdk/transaction/struct.Transaction.html
1365/// [invoked]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke.html
1366///
1367/// Every transaction that relies on a durable transaction nonce must contain a
1368/// [`SystemInstruction::AdvanceNonceAccount`] instruction as the first
1369/// instruction in the [`Message`], as created by this function. When included
1370/// in the first position, the Solana runtime recognizes the transaction as one
1371/// that relies on a durable transaction nonce and processes it accordingly. The
1372/// [`Message::new_with_nonce`] function can be used to construct a `Message` in
1373/// the correct format without calling `advance_nonce_account` directly.
1374///
1375/// When constructing a transaction that includes an `AdvanceNonceInstruction`
1376/// the [`recent_blockhash`] must be treated differently &mdash; instead of
1377/// setting it to a recent blockhash, the value of the nonce must be retrieved
1378/// and deserialized from the nonce account, and that value specified as the
1379/// "recent blockhash". A nonce account can be deserialized with the
1380/// [`solana_rpc_client_nonce_utils::data_from_account`][dfa] function.
1381///
1382/// For further description of durable transaction nonces see
1383/// [`create_nonce_account`].
1384///
1385/// [`Message`]: https://docs.rs/solana-program/latest/solana_program/message/legacy/struct.Message.html
1386/// [`Message::new_with_nonce`]: https://docs.rs/solana-program/latest/solana_program/message/legacy/struct.Message.html#method.new_with_nonce
1387/// [`recent_blockhash`]: https://docs.rs/solana-program/latest/solana_program/message/legacy/struct.Message.html#structfield.recent_blockhash
1388/// [dfa]: https://docs.rs/solana-rpc-client-nonce-utils/latest/solana_rpc_client_nonce_utils/fn.data_from_account.html
1389///
1390/// # Required signers
1391///
1392/// The `authorized_pubkey` signer must sign the transaction.
1393///
1394/// # Examples
1395///
1396/// Create and sign a transaction with a durable nonce:
1397///
1398/// ```
1399/// # use solana_example_mocks::solana_sdk;
1400/// # use solana_example_mocks::solana_rpc_client;
1401/// # use solana_example_mocks::solana_rpc_client_nonce_utils;
1402/// # use solana_sdk::account::Account;
1403/// use solana_rpc_client::rpc_client::RpcClient;
1404/// use solana_pubkey::Pubkey;
1405/// use solana_sdk::{
1406///     message::Message,
1407///     signature::{Keypair, Signer},
1408///     transaction::Transaction,
1409/// };
1410/// use solana_system_interface::instruction;
1411/// use std::path::Path;
1412/// use anyhow::Result;
1413///
1414/// fn create_transfer_tx_with_nonce(
1415///     client: &RpcClient,
1416///     nonce_account_pubkey: &Pubkey,
1417///     payer: &Keypair,
1418///     receiver: &Pubkey,
1419///     amount: u64,
1420///     tx_path: &Path,
1421/// ) -> Result<()> {
1422///
1423///     let instr_transfer = instruction::transfer(
1424///         &payer.pubkey(),
1425///         receiver,
1426///         amount,
1427///     );
1428///
1429///     // In this example, `payer` is `nonce_account_pubkey`'s authority
1430///     let instr_advance_nonce_account = instruction::advance_nonce_account(
1431///         nonce_account_pubkey,
1432///         &payer.pubkey(),
1433///     );
1434///
1435///     // The `advance_nonce_account` instruction must be the first issued in
1436///     // the transaction.
1437///     let message = Message::new(
1438///         &[
1439///             instr_advance_nonce_account,
1440///             instr_transfer
1441///         ],
1442///         Some(&payer.pubkey()),
1443///     );
1444///
1445///     let mut tx = Transaction::new_unsigned(message);
1446///
1447///     // Sign the tx with nonce_account's `blockhash` instead of the
1448///     // network's latest blockhash.
1449///     # client.set_get_account_response(*nonce_account_pubkey, Account {
1450///     #   lamports: 1,
1451///     #   data: vec![0],
1452///     #   owner: solana_sdk::system_program::ID,
1453///     #   executable: false,
1454///     # });
1455///     let nonce_account = client.get_account(nonce_account_pubkey)?;
1456///     let nonce_data = solana_rpc_client_nonce_utils::data_from_account(&nonce_account)?;
1457///     let blockhash = nonce_data.blockhash();
1458///
1459///     tx.try_sign(&[payer], blockhash)?;
1460///
1461///     // Save the signed transaction locally for later submission.
1462///     save_tx_to_file(&tx_path, &tx)?;
1463///
1464///     Ok(())
1465/// }
1466/// #
1467/// # fn save_tx_to_file(path: &Path, tx: &Transaction) -> Result<()> {
1468/// #     Ok(())
1469/// # }
1470/// #
1471/// # let client = RpcClient::new(String::new());
1472/// # let nonce_account_pubkey = Pubkey::new_unique();
1473/// # let payer = Keypair::new();
1474/// # let receiver = Pubkey::new_unique();
1475/// # create_transfer_tx_with_nonce(&client, &nonce_account_pubkey, &payer, &receiver, 1024, Path::new("new_tx"))?;
1476/// #
1477/// # Ok::<(), anyhow::Error>(())
1478/// ```
1479#[cfg(feature = "bincode")]
1480pub fn advance_nonce_account(nonce_pubkey: &Pubkey, authorized_pubkey: &Pubkey) -> Instruction {
1481    let account_metas = vec![
1482        AccountMeta::new(*nonce_pubkey, false),
1483        #[allow(deprecated)]
1484        AccountMeta::new_readonly(RECENT_BLOCKHASHES_ID, false),
1485        AccountMeta::new_readonly(*authorized_pubkey, true),
1486    ];
1487    Instruction::new_with_bincode(ID, &SystemInstruction::AdvanceNonceAccount, account_metas)
1488}
1489
1490/// Withdraw lamports from a durable transaction nonce account.
1491///
1492/// This function produces an [`Instruction`] which must be submitted in a
1493/// [`Transaction`] or [invoked] to take effect, containing a serialized
1494/// [`SystemInstruction::WithdrawNonceAccount`].
1495///
1496/// [`Transaction`]: https://docs.rs/solana-sdk/latest/solana_sdk/transaction/struct.Transaction.html
1497/// [invoked]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke.html
1498///
1499/// Withdrawing the entire balance of a nonce account will cause the runtime to
1500/// destroy it upon successful completion of the transaction.
1501///
1502/// Otherwise, nonce accounts must maintain a balance greater than or equal to
1503/// the minimum required for [rent exemption]. If the result of this instruction
1504/// would leave the nonce account with a balance less than required for rent
1505/// exemption, but also greater than zero, then the transaction will fail.
1506///
1507/// [rent exemption]: https://solana.com/docs/core/accounts#rent-exemption
1508///
1509/// This constructor creates a [`SystemInstruction::WithdrawNonceAccount`]
1510/// instruction.
1511///
1512/// # Required signers
1513///
1514/// The `authorized_pubkey` signer must sign the transaction.
1515///
1516/// # Examples
1517///
1518/// ```
1519/// # use solana_example_mocks::solana_sdk;
1520/// # use solana_example_mocks::solana_rpc_client;
1521/// use solana_rpc_client::rpc_client::RpcClient;
1522/// use solana_pubkey::Pubkey;
1523/// use solana_sdk::{
1524///     signature::{Keypair, Signer},
1525///     transaction::Transaction,
1526/// };
1527/// use solana_system_interface::instruction;
1528/// use anyhow::Result;
1529///
1530/// fn submit_withdraw_nonce_account_tx(
1531///     client: &RpcClient,
1532///     nonce_account_pubkey: &Pubkey,
1533///     authorized_account: &Keypair,
1534/// ) -> Result<()> {
1535///
1536///     let nonce_balance = client.get_balance(nonce_account_pubkey)?;
1537///
1538///     let instr = instruction::withdraw_nonce_account(
1539///         nonce_account_pubkey,
1540///         &authorized_account.pubkey(),
1541///         &authorized_account.pubkey(),
1542///         nonce_balance,
1543///     );
1544///
1545///     let mut tx = Transaction::new_with_payer(&[instr], Some(&authorized_account.pubkey()));
1546///
1547///     let blockhash = client.get_latest_blockhash()?;
1548///     tx.try_sign(&[authorized_account], blockhash)?;
1549///
1550///     client.send_and_confirm_transaction(&tx)?;
1551///
1552///     Ok(())
1553/// }
1554/// #
1555/// # let client = RpcClient::new(String::new());
1556/// # let nonce_account_pubkey = Pubkey::new_unique();
1557/// # let payer = Keypair::new();
1558/// # submit_withdraw_nonce_account_tx(&client, &nonce_account_pubkey, &payer)?;
1559/// #
1560/// # Ok::<(), anyhow::Error>(())
1561/// ```
1562#[cfg(feature = "bincode")]
1563pub fn withdraw_nonce_account(
1564    nonce_pubkey: &Pubkey,
1565    authorized_pubkey: &Pubkey,
1566    to_pubkey: &Pubkey,
1567    lamports: u64,
1568) -> Instruction {
1569    let account_metas = vec![
1570        AccountMeta::new(*nonce_pubkey, false),
1571        AccountMeta::new(*to_pubkey, false),
1572        #[allow(deprecated)]
1573        AccountMeta::new_readonly(RECENT_BLOCKHASHES_ID, false),
1574        AccountMeta::new_readonly(RENT_ID, false),
1575        AccountMeta::new_readonly(*authorized_pubkey, true),
1576    ];
1577    Instruction::new_with_bincode(
1578        ID,
1579        &SystemInstruction::WithdrawNonceAccount(lamports),
1580        account_metas,
1581    )
1582}
1583
1584/// Change the authority of a durable transaction nonce account.
1585///
1586/// This function produces an [`Instruction`] which must be submitted in a
1587/// [`Transaction`] or [invoked] to take effect, containing a serialized
1588/// [`SystemInstruction::AuthorizeNonceAccount`].
1589///
1590/// [`Transaction`]: https://docs.rs/solana-sdk/latest/solana_sdk/transaction/struct.Transaction.html
1591/// [invoked]: https://docs.rs/solana-cpi/latest/solana_cpi/fn.invoke.html
1592///
1593/// This constructor creates a [`SystemInstruction::AuthorizeNonceAccount`]
1594/// instruction.
1595///
1596/// # Required signers
1597///
1598/// The `authorized_pubkey` signer must sign the transaction.
1599///
1600/// # Examples
1601///
1602/// ```
1603/// # use solana_example_mocks::solana_sdk;
1604/// # use solana_example_mocks::solana_rpc_client;
1605/// use solana_rpc_client::rpc_client::RpcClient;
1606/// use solana_pubkey::Pubkey;
1607/// use solana_sdk::{
1608///     signature::{Keypair, Signer},
1609///     transaction::Transaction,
1610/// };
1611/// use solana_system_interface::instruction;
1612/// use anyhow::Result;
1613///
1614/// fn authorize_nonce_account_tx(
1615///     client: &RpcClient,
1616///     nonce_account_pubkey: &Pubkey,
1617///     authorized_account: &Keypair,
1618///     new_authority_pubkey: &Pubkey,
1619/// ) -> Result<()> {
1620///
1621///     let instr = instruction::authorize_nonce_account(
1622///         nonce_account_pubkey,
1623///         &authorized_account.pubkey(),
1624///         new_authority_pubkey,
1625///     );
1626///
1627///     let mut tx = Transaction::new_with_payer(&[instr], Some(&authorized_account.pubkey()));
1628///
1629///     let blockhash = client.get_latest_blockhash()?;
1630///     tx.try_sign(&[authorized_account], blockhash)?;
1631///
1632///     client.send_and_confirm_transaction(&tx)?;
1633///
1634///     Ok(())
1635/// }
1636/// #
1637/// # let client = RpcClient::new(String::new());
1638/// # let nonce_account_pubkey = Pubkey::new_unique();
1639/// # let payer = Keypair::new();
1640/// # let new_authority_pubkey = Pubkey::new_unique();
1641/// # authorize_nonce_account_tx(&client, &nonce_account_pubkey, &payer, &new_authority_pubkey)?;
1642/// #
1643/// # Ok::<(), anyhow::Error>(())
1644/// ```
1645#[cfg(feature = "bincode")]
1646pub fn authorize_nonce_account(
1647    nonce_pubkey: &Pubkey,
1648    authorized_pubkey: &Pubkey,
1649    new_authority: &Pubkey,
1650) -> Instruction {
1651    let account_metas = vec![
1652        AccountMeta::new(*nonce_pubkey, false),
1653        AccountMeta::new_readonly(*authorized_pubkey, true),
1654    ];
1655    Instruction::new_with_bincode(
1656        ID,
1657        &SystemInstruction::AuthorizeNonceAccount(*new_authority),
1658        account_metas,
1659    )
1660}
1661
1662/// One-time idempotent upgrade of legacy nonce versions in order to bump
1663/// them out of chain blockhash domain.
1664#[cfg(feature = "bincode")]
1665pub fn upgrade_nonce_account(nonce_pubkey: Pubkey) -> Instruction {
1666    let account_metas = vec![AccountMeta::new(nonce_pubkey, /*is_signer:*/ false)];
1667    Instruction::new_with_bincode(ID, &SystemInstruction::UpgradeNonceAccount, account_metas)
1668}
1669
1670#[cfg(feature = "bincode")]
1671#[cfg(test)]
1672mod tests {
1673    use {super::*, solana_sysvar_id::SysvarId};
1674
1675    fn get_keys(instruction: &Instruction) -> Vec<Pubkey> {
1676        instruction.accounts.iter().map(|x| x.pubkey).collect()
1677    }
1678
1679    #[allow(deprecated)]
1680    #[test]
1681    fn test_constants() {
1682        // Ensure that the constants are in sync with the solana program.
1683        assert_eq!(
1684            RECENT_BLOCKHASHES_ID,
1685            solana_sysvar::recent_blockhashes::RecentBlockhashes::id(),
1686        );
1687
1688        // Ensure that the constants are in sync with the solana rent.
1689        assert_eq!(RENT_ID, solana_sysvar::rent::Rent::id());
1690    }
1691
1692    #[test]
1693    fn test_move_many() {
1694        let alice_pubkey = Pubkey::new_unique();
1695        let bob_pubkey = Pubkey::new_unique();
1696        let carol_pubkey = Pubkey::new_unique();
1697        let to_lamports = vec![(bob_pubkey, 1), (carol_pubkey, 2)];
1698
1699        let instructions = transfer_many(&alice_pubkey, &to_lamports);
1700        assert_eq!(instructions.len(), 2);
1701        assert_eq!(get_keys(&instructions[0]), vec![alice_pubkey, bob_pubkey]);
1702        assert_eq!(get_keys(&instructions[1]), vec![alice_pubkey, carol_pubkey]);
1703    }
1704
1705    #[test]
1706    fn test_create_nonce_account() {
1707        let from_pubkey = Pubkey::new_unique();
1708        let nonce_pubkey = Pubkey::new_unique();
1709        let authorized = nonce_pubkey;
1710        let ixs = create_nonce_account(&from_pubkey, &nonce_pubkey, &authorized, 42);
1711        assert_eq!(ixs.len(), 2);
1712        let ix = &ixs[0];
1713        assert_eq!(ix.program_id, crate::program::ID);
1714        let pubkeys: Vec<_> = ix.accounts.iter().map(|am| am.pubkey).collect();
1715        assert!(pubkeys.contains(&from_pubkey));
1716        assert!(pubkeys.contains(&nonce_pubkey));
1717    }
1718}