1
0

instruction.rs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. //! Instruction types.
  2. use {crate::error::TokenError, pinocchio::program_error::ProgramError};
  3. /// Instructions supported by the token program.
  4. #[repr(u8)]
  5. #[derive(Clone, Debug, PartialEq)]
  6. #[cfg_attr(test, derive(strum_macros::FromRepr, strum_macros::EnumIter))]
  7. pub enum TokenInstruction {
  8. /// Initializes a new mint and optionally deposits all the newly minted
  9. /// tokens in an account.
  10. ///
  11. /// The `InitializeMint` instruction requires no signers and MUST be
  12. /// included within the same Transaction as the system program's
  13. /// `CreateAccount` instruction that creates the account being initialized.
  14. /// Otherwise another party can acquire ownership of the uninitialized
  15. /// account.
  16. ///
  17. /// Accounts expected by this instruction:
  18. ///
  19. /// 0. `[writable]` The mint to initialize.
  20. /// 1. `[]` Rent sysvar.
  21. ///
  22. /// Data expected by this instruction:
  23. ///
  24. /// - `u8` The number of base 10 digits to the right of the decimal place.
  25. /// - `Pubkey` The authority/multisignature to mint tokens.
  26. /// - `Option<Pubkey>` The freeze authority/multisignature of the mint.
  27. InitializeMint,
  28. /// Initializes a new account to hold tokens. If this account is associated
  29. /// with the native mint then the token balance of the initialized account
  30. /// will be equal to the amount of SOL in the account. If this account is
  31. /// associated with another mint, that mint must be initialized before this
  32. /// command can succeed.
  33. ///
  34. /// The [`InitializeAccount`] instruction requires no signers and MUST be
  35. /// included within the same Transaction as the system program's
  36. /// `CreateAccount` instruction that creates the account being initialized.
  37. /// Otherwise another party can acquire ownership of the uninitialized
  38. /// account.
  39. ///
  40. /// Accounts expected by this instruction:
  41. ///
  42. /// 0. `[writable]` The account to initialize.
  43. /// 1. `[]` The mint this account will be associated with.
  44. /// 2. `[]` The new account's owner/multisignature.
  45. /// 3. `[]` Rent sysvar.
  46. InitializeAccount,
  47. /// Initializes a multisignature account with N provided signers.
  48. ///
  49. /// Multisignature accounts can used in place of any single owner/delegate
  50. /// accounts in any token instruction that require an owner/delegate to be
  51. /// present. The variant field represents the number of signers (M)
  52. /// required to validate this multisignature account.
  53. ///
  54. /// The [`InitializeMultisig`] instruction requires no signers and MUST be
  55. /// included within the same Transaction as the system program's
  56. /// `CreateAccount` instruction that creates the account being initialized.
  57. /// Otherwise another party can acquire ownership of the uninitialized
  58. /// account.
  59. ///
  60. /// Accounts expected by this instruction:
  61. ///
  62. /// 0. `[writable]` The multisignature account to initialize.
  63. /// 1. `[]` Rent sysvar.
  64. /// 2. `..+N` `[signer]` The signer accounts, must equal to N where `1 <=
  65. /// N <= 11`.
  66. ///
  67. /// Data expected by this instruction:
  68. ///
  69. /// - `u8` The number of signers (M) required to validate this
  70. /// multisignature account.
  71. InitializeMultisig,
  72. /// Transfers tokens from one account to another either directly or via a
  73. /// delegate. If this account is associated with the native mint then equal
  74. /// amounts of SOL and Tokens will be transferred to the destination
  75. /// account.
  76. ///
  77. /// Accounts expected by this instruction:
  78. ///
  79. /// * Single owner/delegate
  80. /// 0. `[writable]` The source account.
  81. /// 1. `[writable]` The destination account.
  82. /// 2. `[signer]` The source account's owner/delegate.
  83. ///
  84. /// * Multisignature owner/delegate
  85. /// 0. `[writable]` The source account.
  86. /// 1. `[writable]` The destination account.
  87. /// 2. `[]` The source account's multisignature owner/delegate.
  88. /// 3. `..+M` `[signer]` M signer accounts.
  89. ///
  90. /// Data expected by this instruction:
  91. ///
  92. /// - `u64` The amount of tokens to transfer.
  93. Transfer,
  94. /// Approves a delegate. A delegate is given the authority over tokens on
  95. /// behalf of the source account's owner.
  96. ///
  97. /// Accounts expected by this instruction:
  98. ///
  99. /// * Single owner
  100. /// 0. `[writable]` The source account.
  101. /// 1. `[]` The delegate.
  102. /// 2. `[signer]` The source account owner.
  103. ///
  104. /// * Multisignature owner
  105. /// 0. `[writable]` The source account.
  106. /// 1. `[]` The delegate.
  107. /// 2. `[]` The source account's multisignature owner.
  108. /// 3. `..+M` `[signer]` M signer accounts.
  109. ///
  110. /// Data expected by this instruction:
  111. ///
  112. /// - `u64` The amount of tokens the delegate is approved for.
  113. Approve,
  114. /// Revokes the delegate's authority.
  115. ///
  116. /// Accounts expected by this instruction:
  117. ///
  118. /// * Single owner
  119. /// 0. `[writable]` The source account.
  120. /// 1. `[signer]` The source account owner.
  121. ///
  122. /// * Multisignature owner
  123. /// 0. `[writable]` The source account.
  124. /// 1. `[]` The source account's multisignature owner.
  125. /// 2. `..+M` `[signer]` M signer accounts.
  126. Revoke,
  127. /// Sets a new authority of a mint or account.
  128. ///
  129. /// Accounts expected by this instruction:
  130. ///
  131. /// * Single authority
  132. /// 0. `[writable]` The mint or account to change the authority of.
  133. /// 1. `[signer]` The current authority of the mint or account.
  134. ///
  135. /// * Multisignature authority
  136. /// 0. `[writable]` The mint or account to change the authority of.
  137. /// 1. `[]` The mint's or account's current multisignature authority.
  138. /// 2. `..+M` `[signer]` M signer accounts.
  139. ///
  140. /// Data expected by this instruction:
  141. ///
  142. /// - `AuthorityType` The type of authority to update.
  143. /// - `Option<Pubkey>` The new authority.
  144. SetAuthority,
  145. /// Mints new tokens to an account. The native mint does not support
  146. /// minting.
  147. ///
  148. /// Accounts expected by this instruction:
  149. ///
  150. /// * Single authority
  151. /// 0. `[writable]` The mint.
  152. /// 1. `[writable]` The account to mint tokens to.
  153. /// 2. `[signer]` The mint's minting authority.
  154. ///
  155. /// * Multisignature authority
  156. /// 0. `[writable]` The mint.
  157. /// 1. `[writable]` The account to mint tokens to.
  158. /// 2. `[]` The mint's multisignature mint-tokens authority.
  159. /// 3. `..+M` `[signer]` M signer accounts.
  160. ///
  161. /// Data expected by this instruction:
  162. ///
  163. /// - `u64` The amount of new tokens to mint.
  164. MintTo,
  165. /// Burns tokens by removing them from an account. `Burn` does not support
  166. /// accounts associated with the native mint, use `CloseAccount` instead.
  167. ///
  168. /// Accounts expected by this instruction:
  169. ///
  170. /// * Single owner/delegate
  171. /// 0. `[writable]` The account to burn from.
  172. /// 1. `[writable]` The token mint.
  173. /// 2. `[signer]` The account's owner/delegate.
  174. ///
  175. /// * Multisignature owner/delegate
  176. /// 0. `[writable]` The account to burn from.
  177. /// 1. `[writable]` The token mint.
  178. /// 2. `[]` The account's multisignature owner/delegate.
  179. /// 3. `..+M` `[signer]` M signer accounts.
  180. ///
  181. /// Data expected by this instruction:
  182. ///
  183. /// - `u64` The amount of tokens to burn.
  184. Burn,
  185. /// Close an account by transferring all its SOL to the destination account.
  186. /// Non-native accounts may only be closed if its token amount is zero.
  187. ///
  188. /// Accounts expected by this instruction:
  189. ///
  190. /// * Single owner
  191. /// 0. `[writable]` The account to close.
  192. /// 1. `[writable]` The destination account.
  193. /// 2. `[signer]` The account's owner.
  194. ///
  195. /// * Multisignature owner
  196. /// 0. `[writable]` The account to close.
  197. /// 1. `[writable]` The destination account.
  198. /// 2. `[]` The account's multisignature owner.
  199. /// 3. `..+M` `[signer]` M signer accounts.
  200. CloseAccount,
  201. /// Freeze an Initialized account using the Mint's [`freeze_authority`] (if
  202. /// set).
  203. ///
  204. /// Accounts expected by this instruction:
  205. ///
  206. /// * Single owner
  207. /// 0. `[writable]` The account to freeze.
  208. /// 1. `[]` The token mint.
  209. /// 2. `[signer]` The mint freeze authority.
  210. ///
  211. /// * Multisignature owner
  212. /// 0. `[writable]` The account to freeze.
  213. /// 1. `[]` The token mint.
  214. /// 2. `[]` The mint's multisignature freeze authority.
  215. /// 3. `..+M` `[signer]` M signer accounts.
  216. FreezeAccount,
  217. /// Thaw a Frozen account using the Mint's [`freeze_authority`] (if set).
  218. ///
  219. /// Accounts expected by this instruction:
  220. ///
  221. /// * Single owner
  222. /// 0. `[writable]` The account to freeze.
  223. /// 1. `[]` The token mint.
  224. /// 2. `[signer]` The mint freeze authority.
  225. ///
  226. /// * Multisignature owner
  227. /// 0. `[writable]` The account to freeze.
  228. /// 1. `[]` The token mint.
  229. /// 2. `[]` The mint's multisignature freeze authority.
  230. /// 3. `..+M` `[signer]` M signer accounts.
  231. ThawAccount,
  232. /// Transfers tokens from one account to another either directly or via a
  233. /// delegate. If this account is associated with the native mint then equal
  234. /// amounts of SOL and Tokens will be transferred to the destination
  235. /// account.
  236. ///
  237. /// This instruction differs from Transfer in that the token mint and
  238. /// decimals value is checked by the caller. This may be useful when
  239. /// creating transactions offline or within a hardware wallet.
  240. ///
  241. /// Accounts expected by this instruction:
  242. ///
  243. /// * Single owner/delegate
  244. /// 0. `[writable]` The source account.
  245. /// 1. `[]` The token mint.
  246. /// 2. `[writable]` The destination account.
  247. /// 3. `[signer]` The source account's owner/delegate.
  248. ///
  249. /// * Multisignature owner/delegate
  250. /// 0. `[writable]` The source account.
  251. /// 1. `[]` The token mint.
  252. /// 2. `[writable]` The destination account.
  253. /// 3. `[]` The source account's multisignature owner/delegate.
  254. /// 4. `..+M` `[signer]` M signer accounts.
  255. ///
  256. /// Data expected by this instruction:
  257. ///
  258. /// - `u64` The amount of tokens to transfer.
  259. /// - `u8` Expected number of base 10 digits to the right of the decimal
  260. /// place.
  261. TransferChecked,
  262. /// Approves a delegate. A delegate is given the authority over tokens on
  263. /// behalf of the source account's owner.
  264. ///
  265. /// This instruction differs from Approve in that the token mint and
  266. /// decimals value is checked by the caller. This may be useful when
  267. /// creating transactions offline or within a hardware wallet.
  268. ///
  269. /// Accounts expected by this instruction:
  270. ///
  271. /// * Single owner
  272. /// 0. `[writable]` The source account.
  273. /// 1. `[]` The token mint.
  274. /// 2. `[]` The delegate.
  275. /// 3. `[signer]` The source account owner.
  276. ///
  277. /// * Multisignature owner
  278. /// 0. `[writable]` The source account.
  279. /// 1. `[]` The token mint.
  280. /// 2. `[]` The delegate.
  281. /// 3. `[]` The source account's multisignature owner.
  282. /// 4. `..+M` `[signer]` M signer accounts.
  283. ///
  284. /// Data expected by this instruction:
  285. ///
  286. /// - `u64` The amount of tokens the delegate is approved for.
  287. /// - `u8` Expected number of base 10 digits to the right of the decimal
  288. /// place.
  289. ApproveChecked,
  290. /// Mints new tokens to an account. The native mint does not support
  291. /// minting.
  292. ///
  293. /// This instruction differs from [`MintTo`] in that the decimals value is
  294. /// checked by the caller. This may be useful when creating transactions
  295. /// offline or within a hardware wallet.
  296. ///
  297. /// Accounts expected by this instruction:
  298. ///
  299. /// * Single authority
  300. /// 0. `[writable]` The mint.
  301. /// 1. `[writable]` The account to mint tokens to.
  302. /// 2. `[signer]` The mint's minting authority.
  303. ///
  304. /// * Multisignature authority
  305. /// 0. `[writable]` The mint.
  306. /// 1. `[writable]` The account to mint tokens to.
  307. /// 2. `[]` The mint's multisignature mint-tokens authority.
  308. /// 3. `..+M` `[signer]` M signer accounts.
  309. ///
  310. /// Data expected by this instruction:
  311. ///
  312. /// - `u64` The amount of new tokens to mint.
  313. /// - `u8` Expected number of base 10 digits to the right of the decimal
  314. /// place.
  315. MintToChecked,
  316. /// Burns tokens by removing them from an account. [`BurnChecked`] does not
  317. /// support accounts associated with the native mint, use `CloseAccount`
  318. /// instead.
  319. ///
  320. /// This instruction differs from Burn in that the decimals value is checked
  321. /// by the caller. This may be useful when creating transactions offline or
  322. /// within a hardware wallet.
  323. ///
  324. /// Accounts expected by this instruction:
  325. ///
  326. /// * Single owner/delegate
  327. /// 0. `[writable]` The account to burn from.
  328. /// 1. `[writable]` The token mint.
  329. /// 2. `[signer]` The account's owner/delegate.
  330. ///
  331. /// * Multisignature owner/delegate
  332. /// 0. `[writable]` The account to burn from.
  333. /// 1. `[writable]` The token mint.
  334. /// 2. `[]` The account's multisignature owner/delegate.
  335. /// 3. `..+M` `[signer]` M signer accounts.
  336. ///
  337. /// Data expected by this instruction:
  338. ///
  339. /// - `u64` The amount of tokens to burn.
  340. /// - `u8` Expected number of base 10 digits to the right of the decimal
  341. /// place.
  342. BurnChecked,
  343. /// Like [`InitializeAccount`], but the owner pubkey is passed via
  344. /// instruction data rather than the accounts list. This variant may be
  345. /// preferable when using Cross Program Invocation from an instruction
  346. /// that does not need the owner's `AccountInfo` otherwise.
  347. ///
  348. /// Accounts expected by this instruction:
  349. ///
  350. /// 0. `[writable]` The account to initialize.
  351. /// 1. `[]` The mint this account will be associated with.
  352. /// 2. `[]` Rent sysvar.
  353. ///
  354. /// Data expected by this instruction:
  355. ///
  356. /// - `Pubkey` The new account's owner/multisignature.
  357. InitializeAccount2,
  358. /// Given a wrapped / native token account (a token account containing SOL)
  359. /// updates its amount field based on the account's underlying `lamports`.
  360. /// This is useful if a non-wrapped SOL account uses
  361. /// `system_instruction::transfer` to move lamports to a wrapped token
  362. /// account, and needs to have its token `amount` field updated.
  363. ///
  364. /// Accounts expected by this instruction:
  365. ///
  366. /// 0. `[writable]` The native token account to sync with its underlying
  367. /// lamports.
  368. SyncNative,
  369. /// Like [`InitializeAccount2`], but does not require the Rent sysvar to be
  370. /// provided
  371. ///
  372. /// Accounts expected by this instruction:
  373. ///
  374. /// 0. `[writable]` The account to initialize.
  375. /// 1. `[]` The mint this account will be associated with.
  376. ///
  377. /// Data expected by this instruction:
  378. ///
  379. /// - `Pubkey` The new account's owner/multisignature.
  380. InitializeAccount3,
  381. /// Like [`InitializeMultisig`], but does not require the Rent sysvar to be
  382. /// provided
  383. ///
  384. /// Accounts expected by this instruction:
  385. ///
  386. /// 0. `[writable]` The multisignature account to initialize.
  387. /// 1. `..+N` `[signer]` The signer accounts, must equal to N where `1 <=
  388. /// N <= 11`.
  389. ///
  390. /// Data expected by this instruction:
  391. ///
  392. /// - `u8` The number of signers (M) required to validate this
  393. /// multisignature account.
  394. InitializeMultisig2,
  395. /// Like [`InitializeMint`], but does not require the Rent sysvar to be
  396. /// provided
  397. ///
  398. /// Accounts expected by this instruction:
  399. ///
  400. /// 0. `[writable]` The mint to initialize.
  401. ///
  402. /// Data expected by this instruction:
  403. ///
  404. /// - `u8` The number of base 10 digits to the right of the decimal place.
  405. /// - `Pubkey` The authority/multisignature to mint tokens.
  406. /// - `Option<Pubkey>` The freeze authority/multisignature of the mint.
  407. InitializeMint2,
  408. /// Gets the required size of an account for the given mint as a
  409. /// little-endian `u64`.
  410. ///
  411. /// Return data can be fetched using `sol_get_return_data` and deserializing
  412. /// the return data as a little-endian `u64`.
  413. ///
  414. /// Accounts expected by this instruction:
  415. ///
  416. /// 0. `[]` The mint to calculate for.
  417. GetAccountDataSize,
  418. /// Initialize the Immutable Owner extension for the given token account
  419. ///
  420. /// Fails if the account has already been initialized, so must be called
  421. /// before [`InitializeAccount`].
  422. ///
  423. /// No-ops in this version of the program, but is included for compatibility
  424. /// with the Associated Token Account program.
  425. ///
  426. /// Accounts expected by this instruction:
  427. ///
  428. /// 0. `[writable]` The account to initialize.
  429. InitializeImmutableOwner,
  430. /// Convert an Amount of tokens to a `UiAmount` `string`, using the given
  431. /// mint. In this version of the program, the mint can only specify the
  432. /// number of decimals.
  433. ///
  434. /// Fails on an invalid mint.
  435. ///
  436. /// Return data can be fetched using `sol_get_return_data` and deserialized
  437. /// with `String::from_utf8`.
  438. ///
  439. /// Accounts expected by this instruction:
  440. ///
  441. /// 0. `[]` The mint to calculate for
  442. ///
  443. /// Data expected by this instruction:
  444. ///
  445. /// - `u64` The amount of tokens to reformat.
  446. AmountToUiAmount,
  447. /// Convert a `UiAmount` of tokens to a little-endian `u64` raw Amount,
  448. /// using the given mint. In this version of the program, the mint can
  449. /// only specify the number of decimals.
  450. ///
  451. /// Return data can be fetched using `sol_get_return_data` and deserializing
  452. /// the return data as a little-endian `u64`.
  453. ///
  454. /// Accounts expected by this instruction:
  455. ///
  456. /// 0. `[]` The mint to calculate for.
  457. ///
  458. /// Data expected by this instruction:
  459. ///
  460. /// - `&str` The `ui_amount` of tokens to reformat.
  461. UiAmountToAmount,
  462. /// This instruction is to be used to rescue SOL sent to any `TokenProgram`
  463. /// owned account by sending them to any other account, leaving behind only
  464. /// lamports for rent exemption.
  465. ///
  466. /// Accounts expected by this instruction:
  467. ///
  468. /// 0. `[writable]` Source Account owned by the token program
  469. /// 1. `[writable]` Destination account
  470. /// 2. `[signer]` Authority
  471. /// 3. `..+M` `[signer]` M signer accounts.
  472. WithdrawExcessLamports = 38,
  473. /// Executes a batch of instructions. The instructions to be executed are
  474. /// specified in sequence on the instruction data. Each instruction
  475. /// provides:
  476. /// - `u8`: number of accounts
  477. /// - `u8`: instruction data length (includes the discriminator)
  478. /// - `u8`: instruction discriminator
  479. /// - `[u8]`: instruction data
  480. ///
  481. /// Accounts follow a similar pattern, where accounts for each instruction
  482. /// are specified in sequence. Therefore, the number of accounts
  483. /// expected by this instruction is variable, i.e., it depends on the
  484. /// instructions provided.
  485. ///
  486. /// Both the number of accounts and instruction data length are used to
  487. /// identify the slice of accounts and instruction data for each
  488. /// instruction.
  489. ///
  490. /// Note that it is not sound to have a `batch` instruction that contains
  491. /// other `batch` instruction; an error will be raised when this is
  492. /// detected.
  493. Batch = 255,
  494. // Any new variants also need to be added to program-2022 `TokenInstruction`, so that the
  495. // latter remains a superset of this instruction set. New variants also need to be added to
  496. // token/js/src/instructions/types.ts to maintain @solana/spl-token compatibility
  497. }
  498. impl TryFrom<u8> for TokenInstruction {
  499. type Error = ProgramError;
  500. fn try_from(value: u8) -> Result<Self, Self::Error> {
  501. match value {
  502. // SAFETY: `value` is guaranteed to be in the range of the enum variants.
  503. 0..=24 | 38 | 255 => Ok(unsafe { core::mem::transmute::<u8, TokenInstruction>(value) }),
  504. _ => Err(TokenError::InvalidInstruction.into()),
  505. }
  506. }
  507. }
  508. /// Specifies the authority type for `SetAuthority` instructions
  509. #[repr(u8)]
  510. #[derive(Clone, Debug, PartialEq)]
  511. #[cfg_attr(test, derive(strum_macros::FromRepr, strum_macros::EnumIter))]
  512. pub enum AuthorityType {
  513. /// Authority to mint new tokens
  514. MintTokens,
  515. /// Authority to freeze any account associated with the Mint
  516. FreezeAccount,
  517. /// Owner of a given token account
  518. AccountOwner,
  519. /// Authority to close a token account
  520. CloseAccount,
  521. }
  522. impl TryFrom<u8> for AuthorityType {
  523. type Error = ProgramError;
  524. #[inline(always)]
  525. fn try_from(value: u8) -> Result<Self, Self::Error> {
  526. match value {
  527. // SAFETY: `value` is guaranteed to be in the range of the enum variants.
  528. 0..=3 => Ok(unsafe { core::mem::transmute::<u8, AuthorityType>(value) }),
  529. _ => Err(TokenError::InvalidInstruction.into()),
  530. }
  531. }
  532. }
  533. #[cfg(test)]
  534. mod tests {
  535. use {
  536. super::{AuthorityType, TokenInstruction},
  537. strum::IntoEnumIterator,
  538. };
  539. #[test]
  540. fn test_token_instruction_from_u8_exhaustive() {
  541. for variant in TokenInstruction::iter() {
  542. let variant_u8 = variant.clone() as u8;
  543. assert_eq!(
  544. TokenInstruction::from_repr(variant_u8),
  545. Some(TokenInstruction::try_from(variant_u8).unwrap())
  546. );
  547. assert_eq!(TokenInstruction::try_from(variant_u8).unwrap(), variant);
  548. }
  549. }
  550. #[test]
  551. fn test_authority_type_from_u8_exhaustive() {
  552. for variant in AuthorityType::iter() {
  553. let variant_u8 = variant.clone() as u8;
  554. assert_eq!(
  555. AuthorityType::from_repr(variant_u8),
  556. Some(AuthorityType::try_from(variant_u8).unwrap())
  557. );
  558. assert_eq!(AuthorityType::try_from(variant_u8).unwrap(), variant);
  559. }
  560. }
  561. }