sememe 0.0.0-stage → 0.4.22

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