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