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