Skip to main content

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