substreams_solana_program_instructions/token_instruction_2022.rs
1//! Instruction types
2
3#![allow(deprecated)] // needed to avoid deprecation warning when generating serde implementation for TokenInstruction
4
5use anyhow::anyhow;
6use {
7 substreams::{errors::Error},
8 num_enum::{IntoPrimitive, TryFromPrimitive},
9 crate::{transfer_fee_instruction::TransferFeeInstruction},
10 std::{
11 convert::{TryFrom, TryInto},
12 mem::size_of,
13 },
14};
15
16#[cfg(feature = "serde-traits")]
17use {
18 crate::serialization::coption_fromstr,
19 serde::{Deserialize, Serialize},
20 serde_with::{As, DisplayFromStr},
21};
22use crate::option::COption;
23use crate::pubkey::{Pubkey, PUBKEY_BYTES};
24
25/// Minimum number of multisignature signers (min N)
26pub const MIN_SIGNERS: usize = 1;
27/// Maximum number of multisignature signers (max N)
28pub const MAX_SIGNERS: usize = 11;
29/// Serialized length of a u16, for unpacking
30const U16_BYTES: usize = 2;
31/// Serialized length of a u64, for unpacking
32const U64_BYTES: usize = 8;
33
34/// Instructions supported by the token program.
35#[repr(C)]
36#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
37#[cfg_attr(
38 feature = "serde-traits",
39 serde(rename_all_fields = "camelCase", rename_all = "camelCase")
40)]
41#[derive(Clone, Debug, PartialEq)]
42pub enum TokenInstruction<'a> {
43 /// Initializes a new mint and optionally deposits all the newly minted
44 /// tokens in an account.
45 ///
46 /// The `InitializeMint` instruction requires no signers and MUST be
47 /// included within the same Transaction as the system program's
48 /// `CreateAccount` instruction that creates the account being initialized.
49 /// Otherwise another party can acquire ownership of the uninitialized
50 /// account.
51 ///
52 /// All extensions must be initialized before calling this instruction.
53 ///
54 /// Accounts expected by this instruction:
55 ///
56 /// 0. `[writable]` The mint to initialize.
57 /// 1. `[]` Rent sysvar
58 ///
59 InitializeMint {
60 /// Number of base 10 digits to the right of the decimal place.
61 decimals: u8,
62 /// The authority/multisignature to mint tokens.
63 #[cfg_attr(feature = "serde-traits", serde(with = "As::<DisplayFromStr>"))]
64 mint_authority: Pubkey,
65 /// The freeze authority/multisignature of the mint.
66 #[cfg_attr(feature = "serde-traits", serde(with = "coption_fromstr"))]
67 freeze_authority: COption<Pubkey>,
68 },
69 /// Initializes a new account to hold tokens. If this account is associated
70 /// with the native mint then the token balance of the initialized account
71 /// will be equal to the amount of SOL in the account. If this account is
72 /// associated with another mint, that mint must be initialized before this
73 /// command can succeed.
74 ///
75 /// The `InitializeAccount` instruction requires no signers and MUST be
76 /// included within the same Transaction as the system program's
77 /// `CreateAccount` instruction that creates the account being initialized.
78 /// Otherwise another party can acquire ownership of the uninitialized
79 /// account.
80 ///
81 /// Accounts expected by this instruction:
82 ///
83 /// 0. `[writable]` The account to initialize.
84 /// 1. `[]` The mint this account will be associated with.
85 /// 2. `[]` The new account's owner/multisignature.
86 /// 3. `[]` Rent sysvar
87 InitializeAccount,
88 /// Initializes a multisignature account with N provided signers.
89 ///
90 /// Multisignature accounts can used in place of any single owner/delegate
91 /// accounts in any token instruction that require an owner/delegate to be
92 /// present. The variant field represents the number of signers (M)
93 /// required to validate this multisignature account.
94 ///
95 /// The `InitializeMultisig` instruction requires no signers and MUST be
96 /// included within the same Transaction as the system program's
97 /// `CreateAccount` instruction that creates the account being initialized.
98 /// Otherwise another party can acquire ownership of the uninitialized
99 /// account.
100 ///
101 /// Accounts expected by this instruction:
102 ///
103 /// 0. `[writable]` The multisignature account to initialize.
104 /// 1. `[]` Rent sysvar
105 /// 2. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <=
106 /// 11.
107 InitializeMultisig {
108 /// The number of signers (M) required to validate this multisignature
109 /// account.
110 m: u8,
111 },
112 /// NOTE This instruction is deprecated in favor of `TransferChecked` or
113 /// `TransferCheckedWithFee`
114 ///
115 /// Transfers tokens from one account to another either directly or via a
116 /// delegate. If this account is associated with the native mint then equal
117 /// amounts of SOL and Tokens will be transferred to the destination
118 /// account.
119 ///
120 /// If either account contains an `TransferFeeAmount` extension, this will fail.
121 /// Mints with the `TransferFeeConfig` extension are required in order to assess the fee.
122 ///
123 /// Accounts expected by this instruction:
124 ///
125 /// * Single owner/delegate
126 /// 0. `[writable]` The source account.
127 /// 1. `[writable]` The destination account.
128 /// 2. `[signer]` The source account's owner/delegate.
129 ///
130 /// * Multisignature owner/delegate
131 /// 0. `[writable]` The source account.
132 /// 1. `[writable]` The destination account.
133 /// 2. `[]` The source account's multisignature owner/delegate.
134 /// 3. ..3+M `[signer]` M signer accounts.
135 #[deprecated(
136 since = "4.0.0",
137 note = "please use `TransferChecked` or `TransferCheckedWithFee` instead"
138 )]
139 Transfer {
140 /// The amount of tokens to transfer.
141 amount: u64,
142 },
143 /// Approves a delegate. A delegate is given the authority over tokens on
144 /// behalf of the source account's owner.
145 ///
146 /// Accounts expected by this instruction:
147 ///
148 /// * Single owner
149 /// 0. `[writable]` The source account.
150 /// 1. `[]` The delegate.
151 /// 2. `[signer]` The source account owner.
152 ///
153 /// * Multisignature owner
154 /// 0. `[writable]` The source account.
155 /// 1. `[]` The delegate.
156 /// 2. `[]` The source account's multisignature owner.
157 /// 3. ..3+M `[signer]` M signer accounts
158 Approve {
159 /// The amount of tokens the delegate is approved for.
160 amount: u64,
161 },
162 /// Revokes the delegate's authority.
163 ///
164 /// Accounts expected by this instruction:
165 ///
166 /// * Single owner
167 /// 0. `[writable]` The source account.
168 /// 1. `[signer]` The source account owner or current delegate.
169 ///
170 /// * Multisignature owner
171 /// 0. `[writable]` The source account.
172 /// 1. `[]` The source account's multisignature owner or current delegate.
173 /// 2. ..2+M `[signer]` M signer accounts
174 Revoke,
175 /// Sets a new authority of a mint or account.
176 ///
177 /// Accounts expected by this instruction:
178 ///
179 /// * Single authority
180 /// 0. `[writable]` The mint or account to change the authority of.
181 /// 1. `[signer]` The current authority of the mint or account.
182 ///
183 /// * Multisignature authority
184 /// 0. `[writable]` The mint or account to change the authority of.
185 /// 1. `[]` The mint's or account's current multisignature authority.
186 /// 2. ..2+M `[signer]` M signer accounts
187 SetAuthority {
188 /// The type of authority to update.
189 authority_type: AuthorityType,
190 /// The new authority
191 #[cfg_attr(feature = "serde-traits", serde(with = "coption_fromstr"))]
192 new_authority: COption<Pubkey>,
193 },
194 /// Mints new tokens to an account. The native mint does not support
195 /// minting.
196 ///
197 /// Accounts expected by this instruction:
198 ///
199 /// * Single authority
200 /// 0. `[writable]` The mint.
201 /// 1. `[writable]` The account to mint tokens to.
202 /// 2. `[signer]` The mint's minting authority.
203 ///
204 /// * Multisignature authority
205 /// 0. `[writable]` The mint.
206 /// 1. `[writable]` The account to mint tokens to.
207 /// 2. `[]` The mint's multisignature mint-tokens authority.
208 /// 3. ..3+M `[signer]` M signer accounts.
209 MintTo {
210 /// The amount of new tokens to mint.
211 amount: u64,
212 },
213 /// Burns tokens by removing them from an account. `Burn` does not support
214 /// accounts associated with the native mint, use `CloseAccount` instead.
215 ///
216 /// Accounts expected by this instruction:
217 ///
218 /// * Single owner/delegate
219 /// 0. `[writable]` The account to burn from.
220 /// 1. `[writable]` The token mint.
221 /// 2. `[signer]` The account's owner/delegate.
222 ///
223 /// * Multisignature owner/delegate
224 /// 0. `[writable]` The account to burn from.
225 /// 1. `[writable]` The token mint.
226 /// 2. `[]` The account's multisignature owner/delegate.
227 /// 3. ..3+M `[signer]` M signer accounts.
228 Burn {
229 /// The amount of tokens to burn.
230 amount: u64,
231 },
232 /// Close an account by transferring all its SOL to the destination account.
233 /// Non-native accounts may only be closed if its token amount is zero.
234 ///
235 /// Accounts with the `TransferFeeAmount` extension may only be closed if the withheld
236 /// amount is zero.
237 ///
238 /// Accounts with the `ConfidentialTransfer` extension may only be closed if the pending and
239 /// available balance ciphertexts are empty. Use
240 /// `ConfidentialTransferInstruction::ApplyPendingBalance` and
241 /// `ConfidentialTransferInstruction::EmptyAccount` to empty these ciphertexts.
242 ///
243 /// Accounts with the `ConfidentialTransferFee` extension may only be closed if the withheld
244 /// amount ciphertext is empty. Use
245 /// `ConfidentialTransferFeeInstruction::HarvestWithheldTokensToMint` to empty this ciphertext.
246 ///
247 /// Mints may be closed if they have the `MintCloseAuthority` extension and their token
248 /// supply is zero
249 ///
250 /// Accounts
251 ///
252 /// Accounts expected by this instruction:
253 ///
254 /// * Single owner
255 /// 0. `[writable]` The account to close.
256 /// 1. `[writable]` The destination account.
257 /// 2. `[signer]` The account's owner.
258 ///
259 /// * Multisignature owner
260 /// 0. `[writable]` The account to close.
261 /// 1. `[writable]` The destination account.
262 /// 2. `[]` The account's multisignature owner.
263 /// 3. ..3+M `[signer]` M signer accounts.
264 CloseAccount,
265 /// Freeze an Initialized account using the Mint's freeze_authority (if
266 /// set).
267 ///
268 /// Accounts expected by this instruction:
269 ///
270 /// * Single owner
271 /// 0. `[writable]` The account to freeze.
272 /// 1. `[]` The token mint.
273 /// 2. `[signer]` The mint freeze authority.
274 ///
275 /// * Multisignature owner
276 /// 0. `[writable]` The account to freeze.
277 /// 1. `[]` The token mint.
278 /// 2. `[]` The mint's multisignature freeze authority.
279 /// 3. ..3+M `[signer]` M signer accounts.
280 FreezeAccount,
281 /// Thaw a Frozen account using the Mint's freeze_authority (if set).
282 ///
283 /// Accounts expected by this instruction:
284 ///
285 /// * Single owner
286 /// 0. `[writable]` The account to freeze.
287 /// 1. `[]` The token mint.
288 /// 2. `[signer]` The mint freeze authority.
289 ///
290 /// * Multisignature owner
291 /// 0. `[writable]` The account to freeze.
292 /// 1. `[]` The token mint.
293 /// 2. `[]` The mint's multisignature freeze authority.
294 /// 3. ..3+M `[signer]` M signer accounts.
295 ThawAccount,
296
297 /// Transfers tokens from one account to another either directly or via a
298 /// delegate. If this account is associated with the native mint then equal
299 /// amounts of SOL and Tokens will be transferred to the destination
300 /// account.
301 ///
302 /// This instruction differs from Transfer in that the token mint and
303 /// decimals value is checked by the caller. This may be useful when
304 /// creating transactions offline or within a hardware wallet.
305 ///
306 /// If either account contains an `TransferFeeAmount` extension, the fee is
307 /// withheld in the destination account.
308 ///
309 /// Accounts expected by this instruction:
310 ///
311 /// * Single owner/delegate
312 /// 0. `[writable]` The source account.
313 /// 1. `[]` The token mint.
314 /// 2. `[writable]` The destination account.
315 /// 3. `[signer]` The source account's owner/delegate.
316 ///
317 /// * Multisignature owner/delegate
318 /// 0. `[writable]` The source account.
319 /// 1. `[]` The token mint.
320 /// 2. `[writable]` The destination account.
321 /// 3. `[]` The source account's multisignature owner/delegate.
322 /// 4. ..4+M `[signer]` M signer accounts.
323 TransferChecked {
324 /// The amount of tokens to transfer.
325 amount: u64,
326 /// Expected number of base 10 digits to the right of the decimal place.
327 decimals: u8,
328 },
329 /// Approves a delegate. A delegate is given the authority over tokens on
330 /// behalf of the source account's owner.
331 ///
332 /// This instruction differs from Approve in that the token mint and
333 /// decimals value is checked by the caller. This may be useful when
334 /// creating transactions offline or within a hardware wallet.
335 ///
336 /// Accounts expected by this instruction:
337 ///
338 /// * Single owner
339 /// 0. `[writable]` The source account.
340 /// 1. `[]` The token mint.
341 /// 2. `[]` The delegate.
342 /// 3. `[signer]` The source account owner.
343 ///
344 /// * Multisignature owner
345 /// 0. `[writable]` The source account.
346 /// 1. `[]` The token mint.
347 /// 2. `[]` The delegate.
348 /// 3. `[]` The source account's multisignature owner.
349 /// 4. ..4+M `[signer]` M signer accounts
350 ApproveChecked {
351 /// The amount of tokens the delegate is approved for.
352 amount: u64,
353 /// Expected number of base 10 digits to the right of the decimal place.
354 decimals: u8,
355 },
356 /// Mints new tokens to an account. The native mint does not support
357 /// minting.
358 ///
359 /// This instruction differs from MintTo in that the decimals value is
360 /// checked by the caller. This may be useful when creating transactions
361 /// offline or within a hardware wallet.
362 ///
363 /// Accounts expected by this instruction:
364 ///
365 /// * Single authority
366 /// 0. `[writable]` The mint.
367 /// 1. `[writable]` The account to mint tokens to.
368 /// 2. `[signer]` The mint's minting authority.
369 ///
370 /// * Multisignature authority
371 /// 0. `[writable]` The mint.
372 /// 1. `[writable]` The account to mint tokens to.
373 /// 2. `[]` The mint's multisignature mint-tokens authority.
374 /// 3. ..3+M `[signer]` M signer accounts.
375 MintToChecked {
376 /// The amount of new tokens to mint.
377 amount: u64,
378 /// Expected number of base 10 digits to the right of the decimal place.
379 decimals: u8,
380 },
381 /// Burns tokens by removing them from an account. `BurnChecked` does not
382 /// support accounts associated with the native mint, use `CloseAccount`
383 /// instead.
384 ///
385 /// This instruction differs from Burn in that the decimals value is checked
386 /// by the caller. This may be useful when creating transactions offline or
387 /// within a hardware wallet.
388 ///
389 /// Accounts expected by this instruction:
390 ///
391 /// * Single owner/delegate
392 /// 0. `[writable]` The account to burn from.
393 /// 1. `[writable]` The token mint.
394 /// 2. `[signer]` The account's owner/delegate.
395 ///
396 /// * Multisignature owner/delegate
397 /// 0. `[writable]` The account to burn from.
398 /// 1. `[writable]` The token mint.
399 /// 2. `[]` The account's multisignature owner/delegate.
400 /// 3. ..3+M `[signer]` M signer accounts.
401 BurnChecked {
402 /// The amount of tokens to burn.
403 amount: u64,
404 /// Expected number of base 10 digits to the right of the decimal place.
405 decimals: u8,
406 },
407 /// Like InitializeAccount, but the owner pubkey is passed via instruction data
408 /// rather than the accounts list. This variant may be preferable when using
409 /// Cross Program Invocation from an instruction that does not need the owner's
410 /// `AccountInfo` otherwise.
411 ///
412 /// Accounts expected by this instruction:
413 ///
414 /// 0. `[writable]` The account to initialize.
415 /// 1. `[]` The mint this account will be associated with.
416 /// 2. `[]` Rent sysvar
417 InitializeAccount2 {
418 /// The new account's owner/multisignature.
419 #[cfg_attr(feature = "serde-traits", serde(with = "As::<DisplayFromStr>"))]
420 owner: Pubkey,
421 },
422 /// Given a wrapped / native token account (a token account containing SOL)
423 /// updates its amount field based on the account's underlying `lamports`.
424 /// This is useful if a non-wrapped SOL account uses `system_instruction::transfer`
425 /// to move lamports to a wrapped token account, and needs to have its token
426 /// `amount` field updated.
427 ///
428 /// Accounts expected by this instruction:
429 ///
430 /// 0. `[writable]` The native token account to sync with its underlying lamports.
431 SyncNative,
432 /// Like InitializeAccount2, but does not require the Rent sysvar to be provided
433 ///
434 /// Accounts expected by this instruction:
435 ///
436 /// 0. `[writable]` The account to initialize.
437 /// 1. `[]` The mint this account will be associated with.
438 InitializeAccount3 {
439 /// The new account's owner/multisignature.
440 #[cfg_attr(feature = "serde-traits", serde(with = "As::<DisplayFromStr>"))]
441 owner: Pubkey,
442 },
443 /// Like InitializeMultisig, but does not require the Rent sysvar to be provided
444 ///
445 /// Accounts expected by this instruction:
446 ///
447 /// 0. `[writable]` The multisignature account to initialize.
448 /// 1. ..1+N. `[]` The signer accounts, must equal to N where 1 <= N <=
449 /// 11.
450 InitializeMultisig2 {
451 /// The number of signers (M) required to validate this multisignature
452 /// account.
453 m: u8,
454 },
455 /// Like InitializeMint, but does not require the Rent sysvar to be provided
456 ///
457 /// Accounts expected by this instruction:
458 ///
459 /// 0. `[writable]` The mint to initialize.
460 ///
461 InitializeMint2 {
462 /// Number of base 10 digits to the right of the decimal place.
463 decimals: u8,
464 /// The authority/multisignature to mint tokens.
465 #[cfg_attr(feature = "serde-traits", serde(with = "As::<DisplayFromStr>"))]
466 mint_authority: Pubkey,
467 /// The freeze authority/multisignature of the mint.
468 #[cfg_attr(feature = "serde-traits", serde(with = "coption_fromstr"))]
469 freeze_authority: COption<Pubkey>,
470 },
471 /// Gets the required size of an account for the given mint as a little-endian
472 /// `u64`.
473 ///
474 /// Return data can be fetched using `sol_get_return_data` and deserializing
475 /// the return data as a little-endian `u64`.
476 ///
477 /// Accounts expected by this instruction:
478 ///
479 /// 0. `[]` The mint to calculate for
480 GetAccountDataSize {
481 /// Additional extension types to include in the returned account size
482 extension_types: Vec<ExtensionType>,
483 },
484 /// Initialize the Immutable Owner extension for the given token account
485 ///
486 /// Fails if the account has already been initialized, so must be called before
487 /// `InitializeAccount`.
488 ///
489 /// Accounts expected by this instruction:
490 ///
491 /// 0. `[writable]` The account to initialize.
492 ///
493 /// Data expected by this instruction:
494 /// None
495 ///
496 InitializeImmutableOwner,
497 /// Convert an Amount of tokens to a UiAmount `string`, using the given mint.
498 ///
499 /// Fails on an invalid mint.
500 ///
501 /// Return data can be fetched using `sol_get_return_data` and deserialized with
502 /// `String::from_utf8`.
503 ///
504 /// Accounts expected by this instruction:
505 ///
506 /// 0. `[]` The mint to calculate for
507 AmountToUiAmount {
508 /// The amount of tokens to convert.
509 amount: u64,
510 },
511 /// Convert a UiAmount of tokens to a little-endian `u64` raw Amount, using the given mint.
512 ///
513 /// Return data can be fetched using `sol_get_return_data` and deserializing
514 /// the return data as a little-endian `u64`.
515 ///
516 /// Accounts expected by this instruction:
517 ///
518 /// 0. `[]` The mint to calculate for
519 UiAmountToAmount {
520 /// The ui_amount of tokens to convert.
521 ui_amount: &'a str,
522 },
523 /// Initialize the close account authority on a new mint.
524 ///
525 /// Fails if the mint has already been initialized, so must be called before
526 /// `InitializeMint`.
527 ///
528 /// The mint must have exactly enough space allocated for the base mint (82
529 /// bytes), plus 83 bytes of padding, 1 byte reserved for the account type,
530 /// then space required for this extension, plus any others.
531 ///
532 /// Accounts expected by this instruction:
533 ///
534 /// 0. `[writable]` The mint to initialize.
535 InitializeMintCloseAuthority {
536 /// Authority that must sign the `CloseAccount` instruction on a mint
537 #[cfg_attr(feature = "serde-traits", serde(with = "coption_fromstr"))]
538 close_authority: COption<Pubkey>,
539 },
540 /// The common instruction prefix for Transfer Fee extension instructions.
541 ///
542 /// See `extension::transfer_fee::instruction::TransferFeeInstruction` for
543 /// further details about the extended instructions that share this instruction prefix
544 TransferFeeExtension(TransferFeeInstruction),
545 /// The common instruction prefix for Confidential Transfer extension instructions.
546 ///
547 /// See `extension::confidential_transfer::instruction::ConfidentialTransferInstruction` for
548 /// further details about the extended instructions that share this instruction prefix
549 ConfidentialTransferExtension,
550 /// The common instruction prefix for Default Account State extension instructions.
551 ///
552 /// See `extension::default_account_state::instruction::DefaultAccountStateInstruction` for
553 /// further details about the extended instructions that share this instruction prefix
554 DefaultAccountStateExtension,
555 /// Check to see if a token account is large enough for a list of ExtensionTypes, and if not,
556 /// use reallocation to increase the data size.
557 ///
558 /// Accounts expected by this instruction:
559 ///
560 /// * Single owner
561 /// 0. `[writable]` The account to reallocate.
562 /// 1. `[signer, writable]` The payer account to fund reallocation
563 /// 2. `[]` System program for reallocation funding
564 /// 3. `[signer]` The account's owner.
565 ///
566 /// * Multisignature owner
567 /// 0. `[writable]` The account to reallocate.
568 /// 1. `[signer, writable]` The payer account to fund reallocation
569 /// 2. `[]` System program for reallocation funding
570 /// 3. `[]` The account's multisignature owner/delegate.
571 /// 4. ..4+M `[signer]` M signer accounts.
572 ///
573 Reallocate {
574 /// New extension types to include in the reallocated account
575 extension_types: Vec<ExtensionType>,
576 },
577 /// The common instruction prefix for Memo Transfer account extension instructions.
578 ///
579 /// See `extension::memo_transfer::instruction::RequiredMemoTransfersInstruction` for
580 /// further details about the extended instructions that share this instruction prefix
581 MemoTransferExtension,
582 /// Creates the native mint.
583 ///
584 /// This instruction only needs to be invoked once after deployment and is permissionless,
585 /// Wrapped SOL (`native_mint::id()`) will not be available until this instruction is
586 /// successfully executed.
587 ///
588 /// Accounts expected by this instruction:
589 ///
590 /// 0. `[writeable,signer]` Funding account (must be a system account)
591 /// 1. `[writable]` The native mint address
592 /// 2. `[]` System program for mint account funding
593 ///
594 CreateNativeMint,
595 /// Initialize the non transferable extension for the given mint account
596 ///
597 /// Fails if the account has already been initialized, so must be called before
598 /// `InitializeMint`.
599 ///
600 /// Accounts expected by this instruction:
601 ///
602 /// 0. `[writable]` The mint account to initialize.
603 ///
604 /// Data expected by this instruction:
605 /// None
606 ///
607 InitializeNonTransferableMint,
608 /// The common instruction prefix for Interest Bearing extension instructions.
609 ///
610 /// See `extension::interest_bearing_mint::instruction::InterestBearingMintInstruction` for
611 /// further details about the extended instructions that share this instruction prefix
612 InterestBearingMintExtension,
613 /// The common instruction prefix for CPI Guard account extension instructions.
614 ///
615 /// See `extension::cpi_guard::instruction::CpiGuardInstruction` for
616 /// further details about the extended instructions that share this instruction prefix
617 CpiGuardExtension,
618 /// Initialize the permanent delegate on a new mint.
619 ///
620 /// Fails if the mint has already been initialized, so must be called before
621 /// `InitializeMint`.
622 ///
623 /// The mint must have exactly enough space allocated for the base mint (82
624 /// bytes), plus 83 bytes of padding, 1 byte reserved for the account type,
625 /// then space required for this extension, plus any others.
626 ///
627 /// Accounts expected by this instruction:
628 ///
629 /// 0. `[writable]` The mint to initialize.
630 ///
631 /// Data expected by this instruction:
632 /// Pubkey for the permanent delegate
633 ///
634 InitializePermanentDelegate {
635 /// Authority that may sign for `Transfer`s and `Burn`s on any account
636 #[cfg_attr(feature = "serde-traits", serde(with = "As::<DisplayFromStr>"))]
637 delegate: Pubkey,
638 },
639 /// The common instruction prefix for transfer hook extension instructions.
640 ///
641 /// See `extension::transfer_hook::instruction::TransferHookInstruction`
642 /// for further details about the extended instructions that share this instruction
643 /// prefix
644 TransferHookExtension,
645 /// The common instruction prefix for the confidential transfer fee extension instructions.
646 ///
647 /// See `extension::confidential_transfer_fee::instruction::ConfidentialTransferFeeInstruction`
648 /// for further details about the extended instructions that share this instruction prefix
649 ConfidentialTransferFeeExtension,
650 /// This instruction is to be used to rescue SOLs sent to any TokenProgram
651 /// owned account by sending them to any other account, leaving behind only
652 /// lamports for rent exemption.
653 ///
654 /// 0. `[writable]` Source Account owned by the token program
655 /// 1. `[writable]` Destination account
656 /// 2. `[signer]` Authority
657 /// 3. ..2+M `[signer]` M signer accounts.
658 WithdrawExcessLamports,
659 /// The common instruction prefix for metadata pointer extension instructions.
660 ///
661 /// See `extension::metadata_pointer::instruction::MetadataPointerInstruction`
662 /// for further details about the extended instructions that share this instruction
663 /// prefix
664 MetadataPointerExtension,
665}
666impl<'a> TokenInstruction<'a> {
667 /// Unpacks a byte buffer into a [TokenInstruction](enum.TokenInstruction.html).
668 pub fn unpack(input: &'a [u8]) -> Result<Self, Error> {
669
670 let (&tag, rest) = input.split_first().ok_or(anyhow!("Invalid Instruction"))?;
671 Ok(match tag {
672 0 => {
673 let (&decimals, rest) = rest.split_first().ok_or(anyhow!("Invalid Instruction - 0"))?;
674 let (mint_authority, rest) = Self::unpack_pubkey(rest)?;
675 let (freeze_authority, _rest) = Self::unpack_pubkey_option(rest)?;
676 Self::InitializeMint {
677 mint_authority,
678 freeze_authority,
679 decimals,
680 }
681 }
682 1 => Self::InitializeAccount,
683 2 => {
684 let &m = rest.first().ok_or(anyhow!("Invalid Instruction - 2"))?;
685 Self::InitializeMultisig { m }
686 }
687 3 | 4 | 7 | 8 => {
688 let amount = rest
689 .get(..U64_BYTES)
690 .and_then(|slice| slice.try_into().ok())
691 .map(u64::from_le_bytes)
692 .ok_or(anyhow!("Invalid Instruction - 3 | 4 | 7 | 8"))?;
693 match tag {
694 #[allow(deprecated)]
695 3 => Self::Transfer { amount },
696 4 => Self::Approve { amount },
697 7 => Self::MintTo { amount },
698 8 => Self::Burn { amount },
699 _ => unreachable!(),
700 }
701 }
702 5 => Self::Revoke,
703 6 => {
704 let (authority_type, rest) = rest
705 .split_first()
706 .ok_or_else(|| anyhow!("Invalid Instruction - 6"))
707 .and_then(|(&t, rest)| Ok((AuthorityType::from(t)?, rest)))?;
708 let (new_authority, _rest) = Self::unpack_pubkey_option(rest)?;
709
710 Self::SetAuthority {
711 authority_type,
712 new_authority,
713 }
714 }
715 9 => Self::CloseAccount,
716 10 => Self::FreezeAccount,
717 11 => Self::ThawAccount,
718 12 => {
719 let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
720 Self::TransferChecked { amount, decimals }
721 }
722 13 => {
723 let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
724 Self::ApproveChecked { amount, decimals }
725 }
726 14 => {
727 let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
728 Self::MintToChecked { amount, decimals }
729 }
730 15 => {
731 let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
732 Self::BurnChecked { amount, decimals }
733 }
734 16 => {
735 let (owner, _rest) = Self::unpack_pubkey(rest)?;
736 Self::InitializeAccount2 { owner }
737 }
738 17 => Self::SyncNative,
739 18 => {
740 let (owner, _rest) = Self::unpack_pubkey(rest)?;
741 Self::InitializeAccount3 { owner }
742 }
743 19 => {
744 let &m = rest.first().ok_or(anyhow!("Invalid Instruction - 19"))?;
745 Self::InitializeMultisig2 { m }
746 }
747 20 => {
748 let (&decimals, rest) = rest.split_first().ok_or(anyhow!("Invalid Instruction - 20"))?;
749 let (mint_authority, rest) = Self::unpack_pubkey(rest)?;
750 let (freeze_authority, _rest) = Self::unpack_pubkey_option(rest)?;
751 Self::InitializeMint2 {
752 mint_authority,
753 freeze_authority,
754 decimals,
755 }
756 }
757 21 => {
758 let mut extension_types = vec![];
759 for chunk in rest.chunks(size_of::<ExtensionType>()) {
760 extension_types.push(chunk.try_into()?);
761 }
762 Self::GetAccountDataSize { extension_types }
763 }
764 22 => Self::InitializeImmutableOwner,
765 23 => {
766 let (amount, _rest) = Self::unpack_u64(rest)?;
767 Self::AmountToUiAmount { amount }
768 }
769 24 => {
770 let ui_amount = std::str::from_utf8(rest).map_err(|_| anyhow!("Invalid Instruction - 24"))?;
771 Self::UiAmountToAmount { ui_amount }
772 }
773 25 => {
774 let (close_authority, _rest) = Self::unpack_pubkey_option(rest)?;
775 Self::InitializeMintCloseAuthority { close_authority }
776 }
777 26 => {
778 let (instruction, _rest) = TransferFeeInstruction::unpack(rest)?;
779 Self::TransferFeeExtension(instruction)
780 }
781 27 => Self::ConfidentialTransferExtension,
782 28 => Self::DefaultAccountStateExtension,
783 29 => {
784 let mut extension_types = vec![];
785 for chunk in rest.chunks(size_of::<ExtensionType>()) {
786 extension_types.push(chunk.try_into()?);
787 }
788 Self::Reallocate { extension_types }
789 }
790 30 => Self::MemoTransferExtension,
791 31 => Self::CreateNativeMint,
792 32 => Self::InitializeNonTransferableMint,
793 33 => Self::InterestBearingMintExtension,
794 34 => Self::CpiGuardExtension,
795 35 => {
796 let (delegate, _rest) = Self::unpack_pubkey(rest)?;
797 Self::InitializePermanentDelegate { delegate }
798 }
799 36 => Self::TransferHookExtension,
800 37 => Self::ConfidentialTransferFeeExtension,
801 38 => Self::WithdrawExcessLamports,
802 39 => Self::MetadataPointerExtension,
803 _ => return Err(anyhow!("Invalid Instruction - unpack didn't match any tag value: {}", tag)),
804 })
805 }
806
807
808 pub(crate) fn unpack_pubkey(input: &[u8]) -> Result<(Pubkey, &[u8]), Error> {
809 let pk = input
810 .get(..PUBKEY_BYTES)
811 .and_then(|x| Pubkey::try_from(x).ok())
812 .ok_or(anyhow!("Unable to unpack pubkey from bytes"))?;
813 Ok((pk, &input[PUBKEY_BYTES..]))
814 }
815
816 pub(crate) fn unpack_pubkey_option(
817 input: &[u8],
818 ) -> Result<(COption<Pubkey>, &[u8]), Error> {
819 match input.split_first() {
820 Option::Some((&0, rest)) => Ok((COption::None, rest)),
821 Option::Some((&1, rest)) => {
822 let (pk, rest) = Self::unpack_pubkey(rest)?;
823 Ok((COption::Some(pk), rest))
824 }
825 _ => Err(anyhow!("unable to unpack pubkey option")),
826 }
827 }
828
829
830 pub(crate) fn unpack_u16(input: &[u8]) -> Result<(u16, &[u8]), Error> {
831 let value = input
832 .get(..U16_BYTES)
833 .and_then(|slice| slice.try_into().ok())
834 .map(u16::from_le_bytes)
835 .ok_or(anyhow!("Unable to unpack u16"))?;
836 Ok((value, &input[U16_BYTES..]))
837 }
838
839 pub(crate) fn unpack_u64(input: &[u8]) -> Result<(u64, &[u8]), Error> {
840 let value = input
841 .get(..U64_BYTES)
842 .and_then(|slice| slice.try_into().ok())
843 .map(u64::from_le_bytes)
844 .ok_or(anyhow!("Unable to unpack u64"))?;
845 Ok((value, &input[U64_BYTES..]))
846 }
847
848 pub(crate) fn unpack_amount_decimals(input: &[u8]) -> Result<(u64, u8, &[u8]), Error> {
849 let (amount, rest) = Self::unpack_u64(input)?;
850 let (&decimals, rest) = rest.split_first().ok_or(anyhow!("Unable to unpack amount decimals"))?;
851 Ok((amount, decimals, rest))
852 }
853}
854
855/// Specifies the authority type for SetAuthority instructions
856#[repr(u8)]
857#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
858#[cfg_attr(feature = "serde-traits", serde(rename_all = "camelCase"))]
859#[derive(Clone, Debug, PartialEq)]
860pub enum AuthorityType {
861 /// Authority to mint new tokens
862 MintTokens,
863 /// Authority to freeze any account associated with the Mint
864 FreezeAccount,
865 /// Owner of a given token account
866 AccountOwner,
867 /// Authority to close a token account
868 CloseAccount,
869 /// Authority to set the transfer fee
870 TransferFeeConfig,
871 /// Authority to withdraw withheld tokens from a mint
872 WithheldWithdraw,
873 /// Authority to close a mint account
874 CloseMint,
875 /// Authority to set the interest rate
876 InterestRate,
877 /// Authority to transfer or burn any tokens for a mint
878 PermanentDelegate,
879 /// Authority to update confidential transfer mint and aprove accounts for confidential
880 /// transfers
881 ConfidentialTransferMint,
882 /// Authority to set the transfer hook program id
883 TransferHookProgramId,
884 /// Authority to set the withdraw withheld authority encryption key
885 ConfidentialTransferFeeConfig,
886 /// Authority to set the metadata address
887 MetadataPointer,
888}
889
890impl AuthorityType {
891 fn from(index: u8) -> Result<Self, Error> {
892 match index {
893 0 => Ok(AuthorityType::MintTokens),
894 1 => Ok(AuthorityType::FreezeAccount),
895 2 => Ok(AuthorityType::AccountOwner),
896 3 => Ok(AuthorityType::CloseAccount),
897 4 => Ok(AuthorityType::TransferFeeConfig),
898 5 => Ok(AuthorityType::WithheldWithdraw),
899 6 => Ok(AuthorityType::CloseMint),
900 7 => Ok(AuthorityType::InterestRate),
901 8 => Ok(AuthorityType::PermanentDelegate),
902 9 => Ok(AuthorityType::ConfidentialTransferMint),
903 10 => Ok(AuthorityType::TransferHookProgramId),
904 11 => Ok(AuthorityType::ConfidentialTransferFeeConfig),
905 12 => Ok(AuthorityType::MetadataPointer),
906 _ => Err(anyhow!("Invalid Instruction - Invalid AuthorityType with index {}", index)),
907 }
908 }
909}
910
911
912/// Extensions that can be applied to mints or accounts. Mint extensions must only be
913/// applied to mint accounts, and account extensions must only be applied to token holding
914/// accounts.
915#[repr(u16)]
916#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
917#[cfg_attr(feature = "serde-traits", serde(rename_all = "camelCase"))]
918#[derive(Clone, Copy, Debug, PartialEq, TryFromPrimitive, IntoPrimitive)]
919pub enum ExtensionType {
920 /// Used as padding if the account size would otherwise be 355, same as a multisig
921 Uninitialized,
922 /// Includes transfer fee rate info and accompanying authorities to withdraw and set the fee
923 TransferFeeConfig,
924 /// Includes withheld transfer fees
925 TransferFeeAmount,
926 /// Includes an optional mint close authority
927 MintCloseAuthority,
928 /// Auditor configuration for confidential transfers
929 ConfidentialTransferMint,
930 /// State for confidential transfers
931 ConfidentialTransferAccount,
932 /// Specifies the default Account::state for new Accounts
933 DefaultAccountState,
934 /// Indicates that the Account owner authority cannot be changed
935 ImmutableOwner,
936 /// Require inbound transfers to have memo
937 MemoTransfer,
938 /// Indicates that the tokens from this mint can't be transfered
939 NonTransferable,
940 /// Tokens accrue interest over time,
941 InterestBearingConfig,
942 /// Locks privileged token operations from happening via CPI
943 CpiGuard,
944 /// Includes an optional permanent delegate
945 PermanentDelegate,
946 /// Indicates that the tokens in this account belong to a non-transferable mint
947 NonTransferableAccount,
948 /// Mint requires a CPI to a program implementing the "transfer hook" interface
949 TransferHook,
950 /// Indicates that the tokens in this account belong to a mint with a transfer hook
951 TransferHookAccount,
952 /// Includes encrypted withheld fees and the encryption public that they are encrypted under
953 ConfidentialTransferFeeConfig,
954 /// Includes confidential withheld transfer fees
955 ConfidentialTransferFeeAmount,
956 /// Mint contains a pointer to another account (or the same account) that holds metadata
957 MetadataPointer,
958 /// Mint contains token-metadata
959 TokenMetadata,
960 /// Test variable-length mint extension
961 #[cfg(test)]
962 VariableLenMintTest = u16::MAX - 2,
963 /// Padding extension used to make an account exactly Multisig::LEN, used for testing
964 #[cfg(test)]
965 AccountPaddingTest,
966 /// Padding extension used to make a mint exactly Multisig::LEN, used for testing
967 #[cfg(test)]
968 MintPaddingTest,
969}
970impl TryFrom<&[u8]> for ExtensionType {
971 type Error = Error;
972 fn try_from(a: &[u8]) -> Result<Self, Self::Error> {
973 Self::try_from(u16::from_le_bytes(
974 a.try_into().map_err(|_| anyhow!("ExtensionType - Invalid extension type from byte"))?,
975 ))
976 .map_err(|_| anyhow!("ExtensionType - try from - Invalid account data"))
977 }
978}
979impl From<ExtensionType> for [u8; 2] {
980 fn from(a: ExtensionType) -> Self {
981 u16::from(a).to_le_bytes()
982 }
983}