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