instruction.rs 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292
  1. //! Instruction types
  2. use crate::{check_program_account, error::TokenError};
  3. use solana_program::{
  4. instruction::{AccountMeta, Instruction},
  5. program_error::ProgramError,
  6. program_option::COption,
  7. pubkey::Pubkey,
  8. sysvar,
  9. };
  10. use std::convert::TryInto;
  11. use std::mem::size_of;
  12. /// Minimum number of multisignature signers (min N)
  13. pub const MIN_SIGNERS: usize = 1;
  14. /// Maximum number of multisignature signers (max N)
  15. pub const MAX_SIGNERS: usize = 11;
  16. /// Instructions supported by the token program.
  17. #[repr(C)]
  18. #[derive(Clone, Debug, PartialEq)]
  19. pub enum TokenInstruction {
  20. /// Initializes a new mint and optionally deposits all the newly minted
  21. /// tokens in an account.
  22. ///
  23. /// The `InitializeMint` instruction requires no signers and MUST be
  24. /// included within the same Transaction as the system program's
  25. /// `CreateAccount` instruction that creates the account being initialized.
  26. /// Otherwise another party can acquire ownership of the uninitialized
  27. /// account.
  28. ///
  29. /// Accounts expected by this instruction:
  30. ///
  31. /// 0. `[writable]` The mint to initialize.
  32. /// 1. `[]` Rent sysvar
  33. ///
  34. InitializeMint {
  35. /// Number of base 10 digits to the right of the decimal place.
  36. decimals: u8,
  37. /// The authority/multisignature to mint tokens.
  38. mint_authority: Pubkey,
  39. /// The freeze authority/multisignature of the mint.
  40. freeze_authority: COption<Pubkey>,
  41. },
  42. /// Initializes a new account to hold tokens. If this account is associated
  43. /// with the native mint then the token balance of the initialized account
  44. /// will be equal to the amount of SOL in the account. If this account is
  45. /// associated with another mint, that mint must be initialized before this
  46. /// command can succeed.
  47. ///
  48. /// The `InitializeAccount` instruction requires no signers and MUST be
  49. /// included within the same Transaction as the system program's
  50. /// `CreateAccount` instruction that creates the account being initialized.
  51. /// Otherwise another party can acquire ownership of the uninitialized
  52. /// account.
  53. ///
  54. /// Accounts expected by this instruction:
  55. ///
  56. /// 0. `[writable]` The account to initialize.
  57. /// 1. `[]` The mint this account will be associated with.
  58. /// 2. `[]` The new account's owner/multisignature.
  59. /// 3. `[]` Rent sysvar
  60. InitializeAccount,
  61. /// Initializes a multisignature account with N provided signers.
  62. ///
  63. /// Multisignature accounts can used in place of any single owner/delegate
  64. /// accounts in any token instruction that require an owner/delegate to be
  65. /// present. The variant field represents the number of signers (M)
  66. /// required to validate this multisignature account.
  67. ///
  68. /// The `InitializeMultisig` instruction requires no signers and MUST be
  69. /// included within the same Transaction as the system program's
  70. /// `CreateAccount` instruction that creates the account being initialized.
  71. /// Otherwise another party can acquire ownership of the uninitialized
  72. /// account.
  73. ///
  74. /// Accounts expected by this instruction:
  75. ///
  76. /// 0. `[writable]` The multisignature account to initialize.
  77. /// 1. `[]` Rent sysvar
  78. /// 2. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <=
  79. /// 11.
  80. InitializeMultisig {
  81. /// The number of signers (M) required to validate this multisignature
  82. /// account.
  83. m: u8,
  84. },
  85. /// Transfers tokens from one account to another either directly or via a
  86. /// delegate. If this account is associated with the native mint then equal
  87. /// amounts of SOL and Tokens will be transferred to the destination
  88. /// account.
  89. ///
  90. /// Accounts expected by this instruction:
  91. ///
  92. /// * Single owner/delegate
  93. /// 0. `[writable]` The source account.
  94. /// 1. `[writable]` The destination account.
  95. /// 2. `[signer]` The source account's owner/delegate.
  96. ///
  97. /// * Multisignature owner/delegate
  98. /// 0. `[writable]` The source account.
  99. /// 1. `[writable]` The destination account.
  100. /// 2. `[]` The source account's multisignature owner/delegate.
  101. /// 3. ..3+M `[signer]` M signer accounts.
  102. Transfer {
  103. /// The amount of tokens to transfer.
  104. amount: u64,
  105. },
  106. /// Approves a delegate. A delegate is given the authority over tokens on
  107. /// behalf of the source account's owner.
  108. ///
  109. /// Accounts expected by this instruction:
  110. ///
  111. /// * Single owner
  112. /// 0. `[writable]` The source account.
  113. /// 1. `[]` The delegate.
  114. /// 2. `[signer]` The source account owner.
  115. ///
  116. /// * Multisignature owner
  117. /// 0. `[writable]` The source account.
  118. /// 1. `[]` The delegate.
  119. /// 2. `[]` The source account's multisignature owner.
  120. /// 3. ..3+M `[signer]` M signer accounts
  121. Approve {
  122. /// The amount of tokens the delegate is approved for.
  123. amount: u64,
  124. },
  125. /// Revokes the delegate's authority.
  126. ///
  127. /// Accounts expected by this instruction:
  128. ///
  129. /// * Single owner
  130. /// 0. `[writable]` The source account.
  131. /// 1. `[signer]` The source account owner.
  132. ///
  133. /// * Multisignature owner
  134. /// 0. `[writable]` The source account.
  135. /// 1. `[]` The source account's multisignature owner.
  136. /// 2. ..2+M `[signer]` M signer accounts
  137. Revoke,
  138. /// Sets a new authority of a mint or account.
  139. ///
  140. /// Accounts expected by this instruction:
  141. ///
  142. /// * Single authority
  143. /// 0. `[writable]` The mint or account to change the authority of.
  144. /// 1. `[signer]` The current authority of the mint or account.
  145. ///
  146. /// * Multisignature authority
  147. /// 0. `[writable]` The mint or account to change the authority of.
  148. /// 1. `[]` The mint's or account's current multisignature authority.
  149. /// 2. ..2+M `[signer]` M signer accounts
  150. SetAuthority {
  151. /// The type of authority to update.
  152. authority_type: AuthorityType,
  153. /// The new authority
  154. new_authority: COption<Pubkey>,
  155. },
  156. /// Mints new tokens to an account. The native mint does not support
  157. /// minting.
  158. ///
  159. /// Accounts expected by this instruction:
  160. ///
  161. /// * Single authority
  162. /// 0. `[writable]` The mint.
  163. /// 1. `[writable]` The account to mint tokens to.
  164. /// 2. `[signer]` The mint's minting authority.
  165. ///
  166. /// * Multisignature authority
  167. /// 0. `[writable]` The mint.
  168. /// 1. `[writable]` The account to mint tokens to.
  169. /// 2. `[]` The mint's multisignature mint-tokens authority.
  170. /// 3. ..3+M `[signer]` M signer accounts.
  171. MintTo {
  172. /// The amount of new tokens to mint.
  173. amount: u64,
  174. },
  175. /// Burns tokens by removing them from an account. `Burn` does not support
  176. /// accounts associated with the native mint, use `CloseAccount` instead.
  177. ///
  178. /// Accounts expected by this instruction:
  179. ///
  180. /// * Single owner/delegate
  181. /// 0. `[writable]` The account to burn from.
  182. /// 1. `[writable]` The token mint.
  183. /// 2. `[signer]` The account's owner/delegate.
  184. ///
  185. /// * Multisignature owner/delegate
  186. /// 0. `[writable]` The account to burn from.
  187. /// 1. `[writable]` The token mint.
  188. /// 2. `[]` The account's multisignature owner/delegate.
  189. /// 3. ..3+M `[signer]` M signer accounts.
  190. Burn {
  191. /// The amount of tokens to burn.
  192. amount: u64,
  193. },
  194. /// Close an account by transferring all its SOL to the destination account.
  195. /// Non-native accounts may only be closed if its token amount is zero.
  196. ///
  197. /// Accounts expected by this instruction:
  198. ///
  199. /// * Single owner
  200. /// 0. `[writable]` The account to close.
  201. /// 1. `[writable]` The destination account.
  202. /// 2. `[signer]` The account's owner.
  203. ///
  204. /// * Multisignature owner
  205. /// 0. `[writable]` The account to close.
  206. /// 1. `[writable]` The destination account.
  207. /// 2. `[]` The account's multisignature owner.
  208. /// 3. ..3+M `[signer]` M signer accounts.
  209. CloseAccount,
  210. /// Freeze an Initialized account using the Mint's freeze_authority (if
  211. /// set).
  212. ///
  213. /// Accounts expected by this instruction:
  214. ///
  215. /// * Single owner
  216. /// 0. `[writable]` The account to freeze.
  217. /// 1. `[]` The token mint.
  218. /// 2. `[signer]` The mint freeze authority.
  219. ///
  220. /// * Multisignature owner
  221. /// 0. `[writable]` The account to freeze.
  222. /// 1. `[]` The token mint.
  223. /// 2. `[]` The mint's multisignature freeze authority.
  224. /// 3. ..3+M `[signer]` M signer accounts.
  225. FreezeAccount,
  226. /// Thaw a Frozen account using the Mint's freeze_authority (if set).
  227. ///
  228. /// Accounts expected by this instruction:
  229. ///
  230. /// * Single owner
  231. /// 0. `[writable]` The account to freeze.
  232. /// 1. `[]` The token mint.
  233. /// 2. `[signer]` The mint freeze authority.
  234. ///
  235. /// * Multisignature owner
  236. /// 0. `[writable]` The account to freeze.
  237. /// 1. `[]` The token mint.
  238. /// 2. `[]` The mint's multisignature freeze authority.
  239. /// 3. ..3+M `[signer]` M signer accounts.
  240. ThawAccount,
  241. /// Transfers tokens from one account to another either directly or via a
  242. /// delegate. If this account is associated with the native mint then equal
  243. /// amounts of SOL and Tokens will be transferred to the destination
  244. /// account.
  245. ///
  246. /// This instruction differs from Transfer in that the token mint and
  247. /// decimals value is checked by the caller. This may be useful when
  248. /// creating transactions offline or within a hardware wallet.
  249. ///
  250. /// Accounts expected by this instruction:
  251. ///
  252. /// * Single owner/delegate
  253. /// 0. `[writable]` The source account.
  254. /// 1. `[]` The token mint.
  255. /// 2. `[writable]` The destination account.
  256. /// 3. `[signer]` The source account's owner/delegate.
  257. ///
  258. /// * Multisignature owner/delegate
  259. /// 0. `[writable]` The source account.
  260. /// 1. `[]` The token mint.
  261. /// 2. `[writable]` The destination account.
  262. /// 3. `[]` The source account's multisignature owner/delegate.
  263. /// 4. ..4+M `[signer]` M signer accounts.
  264. TransferChecked {
  265. /// The amount of tokens to transfer.
  266. amount: u64,
  267. /// Expected number of base 10 digits to the right of the decimal place.
  268. decimals: u8,
  269. },
  270. /// Approves a delegate. A delegate is given the authority over tokens on
  271. /// behalf of the source account's owner.
  272. ///
  273. /// This instruction differs from Approve in that the token mint and
  274. /// decimals value is checked by the caller. This may be useful when
  275. /// creating transactions offline or within a hardware wallet.
  276. ///
  277. /// Accounts expected by this instruction:
  278. ///
  279. /// * Single owner
  280. /// 0. `[writable]` The source account.
  281. /// 1. `[]` The token mint.
  282. /// 2. `[]` The delegate.
  283. /// 3. `[signer]` The source account owner.
  284. ///
  285. /// * Multisignature owner
  286. /// 0. `[writable]` The source account.
  287. /// 1. `[]` The token mint.
  288. /// 2. `[]` The delegate.
  289. /// 3. `[]` The source account's multisignature owner.
  290. /// 4. ..4+M `[signer]` M signer accounts
  291. ApproveChecked {
  292. /// The amount of tokens the delegate is approved for.
  293. amount: u64,
  294. /// Expected number of base 10 digits to the right of the decimal place.
  295. decimals: u8,
  296. },
  297. /// Mints new tokens to an account. The native mint does not support
  298. /// minting.
  299. ///
  300. /// This instruction differs from MintTo in that the decimals value is
  301. /// checked by the caller. This may be useful when creating transactions
  302. /// offline or within a hardware wallet.
  303. ///
  304. /// Accounts expected by this instruction:
  305. ///
  306. /// * Single authority
  307. /// 0. `[writable]` The mint.
  308. /// 1. `[writable]` The account to mint tokens to.
  309. /// 2. `[signer]` The mint's minting authority.
  310. ///
  311. /// * Multisignature authority
  312. /// 0. `[writable]` The mint.
  313. /// 1. `[writable]` The account to mint tokens to.
  314. /// 2. `[]` The mint's multisignature mint-tokens authority.
  315. /// 3. ..3+M `[signer]` M signer accounts.
  316. MintToChecked {
  317. /// The amount of new tokens to mint.
  318. amount: u64,
  319. /// Expected number of base 10 digits to the right of the decimal place.
  320. decimals: u8,
  321. },
  322. /// Burns tokens by removing them from an account. `BurnChecked` does not
  323. /// support accounts associated with the native mint, use `CloseAccount`
  324. /// instead.
  325. ///
  326. /// This instruction differs from Burn in that the decimals value is checked
  327. /// by the caller. This may be useful when creating transactions offline or
  328. /// within a hardware wallet.
  329. ///
  330. /// Accounts expected by this instruction:
  331. ///
  332. /// * Single owner/delegate
  333. /// 0. `[writable]` The account to burn from.
  334. /// 1. `[writable]` The token mint.
  335. /// 2. `[signer]` The account's owner/delegate.
  336. ///
  337. /// * Multisignature owner/delegate
  338. /// 0. `[writable]` The account to burn from.
  339. /// 1. `[writable]` The token mint.
  340. /// 2. `[]` The account's multisignature owner/delegate.
  341. /// 3. ..3+M `[signer]` M signer accounts.
  342. BurnChecked {
  343. /// The amount of tokens to burn.
  344. amount: u64,
  345. /// Expected number of base 10 digits to the right of the decimal place.
  346. decimals: u8,
  347. },
  348. /// Like InitializeAccount, but the owner pubkey is passed via instruction data
  349. /// rather than the accounts list. This variant may be preferable when using
  350. /// Cross Program Invocation from an instruction that does not need the owner's
  351. /// `AccountInfo` otherwise.
  352. ///
  353. /// Accounts expected by this instruction:
  354. ///
  355. /// 0. `[writable]` The account to initialize.
  356. /// 1. `[]` The mint this account will be associated with.
  357. /// 3. `[]` Rent sysvar
  358. InitializeAccount2 {
  359. /// The new account's owner/multisignature.
  360. owner: Pubkey,
  361. },
  362. }
  363. impl TokenInstruction {
  364. /// Unpacks a byte buffer into a [TokenInstruction](enum.TokenInstruction.html).
  365. pub fn unpack(input: &[u8]) -> Result<Self, ProgramError> {
  366. use TokenError::InvalidInstruction;
  367. let (&tag, rest) = input.split_first().ok_or(InvalidInstruction)?;
  368. Ok(match tag {
  369. 0 => {
  370. let (&decimals, rest) = rest.split_first().ok_or(InvalidInstruction)?;
  371. let (mint_authority, rest) = Self::unpack_pubkey(rest)?;
  372. let (freeze_authority, _rest) = Self::unpack_pubkey_option(rest)?;
  373. Self::InitializeMint {
  374. mint_authority,
  375. freeze_authority,
  376. decimals,
  377. }
  378. }
  379. 1 => Self::InitializeAccount,
  380. 2 => {
  381. let &m = rest.get(0).ok_or(InvalidInstruction)?;
  382. Self::InitializeMultisig { m }
  383. }
  384. 3 | 4 | 7 | 8 => {
  385. let amount = rest
  386. .get(..8)
  387. .and_then(|slice| slice.try_into().ok())
  388. .map(u64::from_le_bytes)
  389. .ok_or(InvalidInstruction)?;
  390. match tag {
  391. 3 => Self::Transfer { amount },
  392. 4 => Self::Approve { amount },
  393. 7 => Self::MintTo { amount },
  394. 8 => Self::Burn { amount },
  395. _ => unreachable!(),
  396. }
  397. }
  398. 5 => Self::Revoke,
  399. 6 => {
  400. let (authority_type, rest) = rest
  401. .split_first()
  402. .ok_or_else(|| ProgramError::from(InvalidInstruction))
  403. .and_then(|(&t, rest)| Ok((AuthorityType::from(t)?, rest)))?;
  404. let (new_authority, _rest) = Self::unpack_pubkey_option(rest)?;
  405. Self::SetAuthority {
  406. authority_type,
  407. new_authority,
  408. }
  409. }
  410. 9 => Self::CloseAccount,
  411. 10 => Self::FreezeAccount,
  412. 11 => Self::ThawAccount,
  413. 12 => {
  414. let (amount, rest) = rest.split_at(8);
  415. let amount = amount
  416. .try_into()
  417. .ok()
  418. .map(u64::from_le_bytes)
  419. .ok_or(InvalidInstruction)?;
  420. let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?;
  421. Self::TransferChecked { amount, decimals }
  422. }
  423. 13 => {
  424. let (amount, rest) = rest.split_at(8);
  425. let amount = amount
  426. .try_into()
  427. .ok()
  428. .map(u64::from_le_bytes)
  429. .ok_or(InvalidInstruction)?;
  430. let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?;
  431. Self::ApproveChecked { amount, decimals }
  432. }
  433. 14 => {
  434. let (amount, rest) = rest.split_at(8);
  435. let amount = amount
  436. .try_into()
  437. .ok()
  438. .map(u64::from_le_bytes)
  439. .ok_or(InvalidInstruction)?;
  440. let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?;
  441. Self::MintToChecked { amount, decimals }
  442. }
  443. 15 => {
  444. let (amount, rest) = rest.split_at(8);
  445. let amount = amount
  446. .try_into()
  447. .ok()
  448. .map(u64::from_le_bytes)
  449. .ok_or(InvalidInstruction)?;
  450. let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?;
  451. Self::BurnChecked { amount, decimals }
  452. }
  453. 16 => {
  454. let (owner, _rest) = Self::unpack_pubkey(rest)?;
  455. Self::InitializeAccount2 { owner }
  456. }
  457. _ => return Err(TokenError::InvalidInstruction.into()),
  458. })
  459. }
  460. /// Packs a [TokenInstruction](enum.TokenInstruction.html) into a byte buffer.
  461. pub fn pack(&self) -> Vec<u8> {
  462. let mut buf = Vec::with_capacity(size_of::<Self>());
  463. match self {
  464. &Self::InitializeMint {
  465. ref mint_authority,
  466. ref freeze_authority,
  467. decimals,
  468. } => {
  469. buf.push(0);
  470. buf.push(decimals);
  471. buf.extend_from_slice(mint_authority.as_ref());
  472. Self::pack_pubkey_option(freeze_authority, &mut buf);
  473. }
  474. Self::InitializeAccount => buf.push(1),
  475. &Self::InitializeMultisig { m } => {
  476. buf.push(2);
  477. buf.push(m);
  478. }
  479. &Self::Transfer { amount } => {
  480. buf.push(3);
  481. buf.extend_from_slice(&amount.to_le_bytes());
  482. }
  483. &Self::Approve { amount } => {
  484. buf.push(4);
  485. buf.extend_from_slice(&amount.to_le_bytes());
  486. }
  487. &Self::MintTo { amount } => {
  488. buf.push(7);
  489. buf.extend_from_slice(&amount.to_le_bytes());
  490. }
  491. &Self::Burn { amount } => {
  492. buf.push(8);
  493. buf.extend_from_slice(&amount.to_le_bytes());
  494. }
  495. Self::Revoke => buf.push(5),
  496. Self::SetAuthority {
  497. authority_type,
  498. ref new_authority,
  499. } => {
  500. buf.push(6);
  501. buf.push(authority_type.into());
  502. Self::pack_pubkey_option(new_authority, &mut buf);
  503. }
  504. Self::CloseAccount => buf.push(9),
  505. Self::FreezeAccount => buf.push(10),
  506. Self::ThawAccount => buf.push(11),
  507. &Self::TransferChecked { amount, decimals } => {
  508. buf.push(12);
  509. buf.extend_from_slice(&amount.to_le_bytes());
  510. buf.push(decimals);
  511. }
  512. &Self::ApproveChecked { amount, decimals } => {
  513. buf.push(13);
  514. buf.extend_from_slice(&amount.to_le_bytes());
  515. buf.push(decimals);
  516. }
  517. &Self::MintToChecked { amount, decimals } => {
  518. buf.push(14);
  519. buf.extend_from_slice(&amount.to_le_bytes());
  520. buf.push(decimals);
  521. }
  522. &Self::BurnChecked { amount, decimals } => {
  523. buf.push(15);
  524. buf.extend_from_slice(&amount.to_le_bytes());
  525. buf.push(decimals);
  526. }
  527. &Self::InitializeAccount2 { owner } => {
  528. buf.push(16);
  529. buf.extend_from_slice(owner.as_ref());
  530. }
  531. };
  532. buf
  533. }
  534. fn unpack_pubkey(input: &[u8]) -> Result<(Pubkey, &[u8]), ProgramError> {
  535. if input.len() >= 32 {
  536. let (key, rest) = input.split_at(32);
  537. let pk = Pubkey::new(key);
  538. Ok((pk, rest))
  539. } else {
  540. Err(TokenError::InvalidInstruction.into())
  541. }
  542. }
  543. fn unpack_pubkey_option(input: &[u8]) -> Result<(COption<Pubkey>, &[u8]), ProgramError> {
  544. match input.split_first() {
  545. Option::Some((&0, rest)) => Ok((COption::None, rest)),
  546. Option::Some((&1, rest)) if rest.len() >= 32 => {
  547. let (key, rest) = rest.split_at(32);
  548. let pk = Pubkey::new(key);
  549. Ok((COption::Some(pk), rest))
  550. }
  551. _ => Err(TokenError::InvalidInstruction.into()),
  552. }
  553. }
  554. fn pack_pubkey_option(value: &COption<Pubkey>, buf: &mut Vec<u8>) {
  555. match *value {
  556. COption::Some(ref key) => {
  557. buf.push(1);
  558. buf.extend_from_slice(&key.to_bytes());
  559. }
  560. COption::None => buf.push(0),
  561. }
  562. }
  563. }
  564. /// Specifies the authority type for SetAuthority instructions
  565. #[repr(u8)]
  566. #[derive(Clone, Debug, PartialEq)]
  567. pub enum AuthorityType {
  568. /// Authority to mint new tokens
  569. MintTokens,
  570. /// Authority to freeze any account associated with the Mint
  571. FreezeAccount,
  572. /// Owner of a given token account
  573. AccountOwner,
  574. /// Authority to close a token account
  575. CloseAccount,
  576. }
  577. impl AuthorityType {
  578. fn into(&self) -> u8 {
  579. match self {
  580. AuthorityType::MintTokens => 0,
  581. AuthorityType::FreezeAccount => 1,
  582. AuthorityType::AccountOwner => 2,
  583. AuthorityType::CloseAccount => 3,
  584. }
  585. }
  586. fn from(index: u8) -> Result<Self, ProgramError> {
  587. match index {
  588. 0 => Ok(AuthorityType::MintTokens),
  589. 1 => Ok(AuthorityType::FreezeAccount),
  590. 2 => Ok(AuthorityType::AccountOwner),
  591. 3 => Ok(AuthorityType::CloseAccount),
  592. _ => Err(TokenError::InvalidInstruction.into()),
  593. }
  594. }
  595. }
  596. /// Creates a `InitializeMint` instruction.
  597. pub fn initialize_mint(
  598. token_program_id: &Pubkey,
  599. mint_pubkey: &Pubkey,
  600. mint_authority_pubkey: &Pubkey,
  601. freeze_authority_pubkey: Option<&Pubkey>,
  602. decimals: u8,
  603. ) -> Result<Instruction, ProgramError> {
  604. check_program_account(token_program_id)?;
  605. let freeze_authority = freeze_authority_pubkey.cloned().into();
  606. let data = TokenInstruction::InitializeMint {
  607. mint_authority: *mint_authority_pubkey,
  608. freeze_authority,
  609. decimals,
  610. }
  611. .pack();
  612. let accounts = vec![
  613. AccountMeta::new(*mint_pubkey, false),
  614. AccountMeta::new_readonly(sysvar::rent::id(), false),
  615. ];
  616. Ok(Instruction {
  617. program_id: *token_program_id,
  618. accounts,
  619. data,
  620. })
  621. }
  622. /// Creates a `InitializeAccount` instruction.
  623. pub fn initialize_account(
  624. token_program_id: &Pubkey,
  625. account_pubkey: &Pubkey,
  626. mint_pubkey: &Pubkey,
  627. owner_pubkey: &Pubkey,
  628. ) -> Result<Instruction, ProgramError> {
  629. check_program_account(token_program_id)?;
  630. let data = TokenInstruction::InitializeAccount.pack();
  631. let accounts = vec![
  632. AccountMeta::new(*account_pubkey, false),
  633. AccountMeta::new_readonly(*mint_pubkey, false),
  634. AccountMeta::new_readonly(*owner_pubkey, false),
  635. AccountMeta::new_readonly(sysvar::rent::id(), false),
  636. ];
  637. Ok(Instruction {
  638. program_id: *token_program_id,
  639. accounts,
  640. data,
  641. })
  642. }
  643. /// Creates a `InitializeAccount2` instruction.
  644. pub fn initialize_account2(
  645. token_program_id: &Pubkey,
  646. account_pubkey: &Pubkey,
  647. mint_pubkey: &Pubkey,
  648. owner_pubkey: &Pubkey,
  649. ) -> Result<Instruction, ProgramError> {
  650. check_program_account(token_program_id)?;
  651. let data = TokenInstruction::InitializeAccount2 {
  652. owner: *owner_pubkey,
  653. }
  654. .pack();
  655. let accounts = vec![
  656. AccountMeta::new(*account_pubkey, false),
  657. AccountMeta::new_readonly(*mint_pubkey, false),
  658. AccountMeta::new_readonly(sysvar::rent::id(), false),
  659. ];
  660. Ok(Instruction {
  661. program_id: *token_program_id,
  662. accounts,
  663. data,
  664. })
  665. }
  666. /// Creates a `InitializeMultisig` instruction.
  667. pub fn initialize_multisig(
  668. token_program_id: &Pubkey,
  669. multisig_pubkey: &Pubkey,
  670. signer_pubkeys: &[&Pubkey],
  671. m: u8,
  672. ) -> Result<Instruction, ProgramError> {
  673. check_program_account(token_program_id)?;
  674. if !is_valid_signer_index(m as usize)
  675. || !is_valid_signer_index(signer_pubkeys.len())
  676. || m as usize > signer_pubkeys.len()
  677. {
  678. return Err(ProgramError::MissingRequiredSignature);
  679. }
  680. let data = TokenInstruction::InitializeMultisig { m }.pack();
  681. let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len());
  682. accounts.push(AccountMeta::new(*multisig_pubkey, false));
  683. accounts.push(AccountMeta::new_readonly(sysvar::rent::id(), false));
  684. for signer_pubkey in signer_pubkeys.iter() {
  685. accounts.push(AccountMeta::new_readonly(**signer_pubkey, false));
  686. }
  687. Ok(Instruction {
  688. program_id: *token_program_id,
  689. accounts,
  690. data,
  691. })
  692. }
  693. /// Creates a `Transfer` instruction.
  694. pub fn transfer(
  695. token_program_id: &Pubkey,
  696. source_pubkey: &Pubkey,
  697. destination_pubkey: &Pubkey,
  698. authority_pubkey: &Pubkey,
  699. signer_pubkeys: &[&Pubkey],
  700. amount: u64,
  701. ) -> Result<Instruction, ProgramError> {
  702. check_program_account(token_program_id)?;
  703. let data = TokenInstruction::Transfer { amount }.pack();
  704. let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
  705. accounts.push(AccountMeta::new(*source_pubkey, false));
  706. accounts.push(AccountMeta::new(*destination_pubkey, false));
  707. accounts.push(AccountMeta::new_readonly(
  708. *authority_pubkey,
  709. signer_pubkeys.is_empty(),
  710. ));
  711. for signer_pubkey in signer_pubkeys.iter() {
  712. accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
  713. }
  714. Ok(Instruction {
  715. program_id: *token_program_id,
  716. accounts,
  717. data,
  718. })
  719. }
  720. /// Creates an `Approve` instruction.
  721. pub fn approve(
  722. token_program_id: &Pubkey,
  723. source_pubkey: &Pubkey,
  724. delegate_pubkey: &Pubkey,
  725. owner_pubkey: &Pubkey,
  726. signer_pubkeys: &[&Pubkey],
  727. amount: u64,
  728. ) -> Result<Instruction, ProgramError> {
  729. check_program_account(token_program_id)?;
  730. let data = TokenInstruction::Approve { amount }.pack();
  731. let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
  732. accounts.push(AccountMeta::new(*source_pubkey, false));
  733. accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false));
  734. accounts.push(AccountMeta::new_readonly(
  735. *owner_pubkey,
  736. signer_pubkeys.is_empty(),
  737. ));
  738. for signer_pubkey in signer_pubkeys.iter() {
  739. accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
  740. }
  741. Ok(Instruction {
  742. program_id: *token_program_id,
  743. accounts,
  744. data,
  745. })
  746. }
  747. /// Creates a `Revoke` instruction.
  748. pub fn revoke(
  749. token_program_id: &Pubkey,
  750. source_pubkey: &Pubkey,
  751. owner_pubkey: &Pubkey,
  752. signer_pubkeys: &[&Pubkey],
  753. ) -> Result<Instruction, ProgramError> {
  754. check_program_account(token_program_id)?;
  755. let data = TokenInstruction::Revoke.pack();
  756. let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len());
  757. accounts.push(AccountMeta::new(*source_pubkey, false));
  758. accounts.push(AccountMeta::new_readonly(
  759. *owner_pubkey,
  760. signer_pubkeys.is_empty(),
  761. ));
  762. for signer_pubkey in signer_pubkeys.iter() {
  763. accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
  764. }
  765. Ok(Instruction {
  766. program_id: *token_program_id,
  767. accounts,
  768. data,
  769. })
  770. }
  771. /// Creates a `SetAuthority` instruction.
  772. pub fn set_authority(
  773. token_program_id: &Pubkey,
  774. owned_pubkey: &Pubkey,
  775. new_authority_pubkey: Option<&Pubkey>,
  776. authority_type: AuthorityType,
  777. owner_pubkey: &Pubkey,
  778. signer_pubkeys: &[&Pubkey],
  779. ) -> Result<Instruction, ProgramError> {
  780. check_program_account(token_program_id)?;
  781. let new_authority = new_authority_pubkey.cloned().into();
  782. let data = TokenInstruction::SetAuthority {
  783. authority_type,
  784. new_authority,
  785. }
  786. .pack();
  787. let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
  788. accounts.push(AccountMeta::new(*owned_pubkey, false));
  789. accounts.push(AccountMeta::new_readonly(
  790. *owner_pubkey,
  791. signer_pubkeys.is_empty(),
  792. ));
  793. for signer_pubkey in signer_pubkeys.iter() {
  794. accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
  795. }
  796. Ok(Instruction {
  797. program_id: *token_program_id,
  798. accounts,
  799. data,
  800. })
  801. }
  802. /// Creates a `MintTo` instruction.
  803. pub fn mint_to(
  804. token_program_id: &Pubkey,
  805. mint_pubkey: &Pubkey,
  806. account_pubkey: &Pubkey,
  807. owner_pubkey: &Pubkey,
  808. signer_pubkeys: &[&Pubkey],
  809. amount: u64,
  810. ) -> Result<Instruction, ProgramError> {
  811. check_program_account(token_program_id)?;
  812. let data = TokenInstruction::MintTo { amount }.pack();
  813. let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
  814. accounts.push(AccountMeta::new(*mint_pubkey, false));
  815. accounts.push(AccountMeta::new(*account_pubkey, false));
  816. accounts.push(AccountMeta::new_readonly(
  817. *owner_pubkey,
  818. signer_pubkeys.is_empty(),
  819. ));
  820. for signer_pubkey in signer_pubkeys.iter() {
  821. accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
  822. }
  823. Ok(Instruction {
  824. program_id: *token_program_id,
  825. accounts,
  826. data,
  827. })
  828. }
  829. /// Creates a `Burn` instruction.
  830. pub fn burn(
  831. token_program_id: &Pubkey,
  832. account_pubkey: &Pubkey,
  833. mint_pubkey: &Pubkey,
  834. authority_pubkey: &Pubkey,
  835. signer_pubkeys: &[&Pubkey],
  836. amount: u64,
  837. ) -> Result<Instruction, ProgramError> {
  838. check_program_account(token_program_id)?;
  839. let data = TokenInstruction::Burn { amount }.pack();
  840. let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
  841. accounts.push(AccountMeta::new(*account_pubkey, false));
  842. accounts.push(AccountMeta::new(*mint_pubkey, false));
  843. accounts.push(AccountMeta::new_readonly(
  844. *authority_pubkey,
  845. signer_pubkeys.is_empty(),
  846. ));
  847. for signer_pubkey in signer_pubkeys.iter() {
  848. accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
  849. }
  850. Ok(Instruction {
  851. program_id: *token_program_id,
  852. accounts,
  853. data,
  854. })
  855. }
  856. /// Creates a `CloseAccount` instruction.
  857. pub fn close_account(
  858. token_program_id: &Pubkey,
  859. account_pubkey: &Pubkey,
  860. destination_pubkey: &Pubkey,
  861. owner_pubkey: &Pubkey,
  862. signer_pubkeys: &[&Pubkey],
  863. ) -> Result<Instruction, ProgramError> {
  864. check_program_account(token_program_id)?;
  865. let data = TokenInstruction::CloseAccount.pack();
  866. let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
  867. accounts.push(AccountMeta::new(*account_pubkey, false));
  868. accounts.push(AccountMeta::new(*destination_pubkey, false));
  869. accounts.push(AccountMeta::new_readonly(
  870. *owner_pubkey,
  871. signer_pubkeys.is_empty(),
  872. ));
  873. for signer_pubkey in signer_pubkeys.iter() {
  874. accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
  875. }
  876. Ok(Instruction {
  877. program_id: *token_program_id,
  878. accounts,
  879. data,
  880. })
  881. }
  882. /// Creates a `FreezeAccount` instruction.
  883. pub fn freeze_account(
  884. token_program_id: &Pubkey,
  885. account_pubkey: &Pubkey,
  886. mint_pubkey: &Pubkey,
  887. owner_pubkey: &Pubkey,
  888. signer_pubkeys: &[&Pubkey],
  889. ) -> Result<Instruction, ProgramError> {
  890. check_program_account(token_program_id)?;
  891. let data = TokenInstruction::FreezeAccount.pack();
  892. let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
  893. accounts.push(AccountMeta::new(*account_pubkey, false));
  894. accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
  895. accounts.push(AccountMeta::new_readonly(
  896. *owner_pubkey,
  897. signer_pubkeys.is_empty(),
  898. ));
  899. for signer_pubkey in signer_pubkeys.iter() {
  900. accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
  901. }
  902. Ok(Instruction {
  903. program_id: *token_program_id,
  904. accounts,
  905. data,
  906. })
  907. }
  908. /// Creates a `ThawAccount` instruction.
  909. pub fn thaw_account(
  910. token_program_id: &Pubkey,
  911. account_pubkey: &Pubkey,
  912. mint_pubkey: &Pubkey,
  913. owner_pubkey: &Pubkey,
  914. signer_pubkeys: &[&Pubkey],
  915. ) -> Result<Instruction, ProgramError> {
  916. check_program_account(token_program_id)?;
  917. let data = TokenInstruction::ThawAccount.pack();
  918. let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
  919. accounts.push(AccountMeta::new(*account_pubkey, false));
  920. accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
  921. accounts.push(AccountMeta::new_readonly(
  922. *owner_pubkey,
  923. signer_pubkeys.is_empty(),
  924. ));
  925. for signer_pubkey in signer_pubkeys.iter() {
  926. accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
  927. }
  928. Ok(Instruction {
  929. program_id: *token_program_id,
  930. accounts,
  931. data,
  932. })
  933. }
  934. /// Creates a `TransferChecked` instruction.
  935. #[allow(clippy::too_many_arguments)]
  936. pub fn transfer_checked(
  937. token_program_id: &Pubkey,
  938. source_pubkey: &Pubkey,
  939. mint_pubkey: &Pubkey,
  940. destination_pubkey: &Pubkey,
  941. authority_pubkey: &Pubkey,
  942. signer_pubkeys: &[&Pubkey],
  943. amount: u64,
  944. decimals: u8,
  945. ) -> Result<Instruction, ProgramError> {
  946. check_program_account(token_program_id)?;
  947. let data = TokenInstruction::TransferChecked { amount, decimals }.pack();
  948. let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
  949. accounts.push(AccountMeta::new(*source_pubkey, false));
  950. accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
  951. accounts.push(AccountMeta::new(*destination_pubkey, false));
  952. accounts.push(AccountMeta::new_readonly(
  953. *authority_pubkey,
  954. signer_pubkeys.is_empty(),
  955. ));
  956. for signer_pubkey in signer_pubkeys.iter() {
  957. accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
  958. }
  959. Ok(Instruction {
  960. program_id: *token_program_id,
  961. accounts,
  962. data,
  963. })
  964. }
  965. /// Creates an `ApproveChecked` instruction.
  966. #[allow(clippy::too_many_arguments)]
  967. pub fn approve_checked(
  968. token_program_id: &Pubkey,
  969. source_pubkey: &Pubkey,
  970. mint_pubkey: &Pubkey,
  971. delegate_pubkey: &Pubkey,
  972. owner_pubkey: &Pubkey,
  973. signer_pubkeys: &[&Pubkey],
  974. amount: u64,
  975. decimals: u8,
  976. ) -> Result<Instruction, ProgramError> {
  977. check_program_account(token_program_id)?;
  978. let data = TokenInstruction::ApproveChecked { amount, decimals }.pack();
  979. let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
  980. accounts.push(AccountMeta::new(*source_pubkey, false));
  981. accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
  982. accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false));
  983. accounts.push(AccountMeta::new_readonly(
  984. *owner_pubkey,
  985. signer_pubkeys.is_empty(),
  986. ));
  987. for signer_pubkey in signer_pubkeys.iter() {
  988. accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
  989. }
  990. Ok(Instruction {
  991. program_id: *token_program_id,
  992. accounts,
  993. data,
  994. })
  995. }
  996. /// Creates a `MintToChecked` instruction.
  997. pub fn mint_to_checked(
  998. token_program_id: &Pubkey,
  999. mint_pubkey: &Pubkey,
  1000. account_pubkey: &Pubkey,
  1001. owner_pubkey: &Pubkey,
  1002. signer_pubkeys: &[&Pubkey],
  1003. amount: u64,
  1004. decimals: u8,
  1005. ) -> Result<Instruction, ProgramError> {
  1006. check_program_account(token_program_id)?;
  1007. let data = TokenInstruction::MintToChecked { amount, decimals }.pack();
  1008. let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
  1009. accounts.push(AccountMeta::new(*mint_pubkey, false));
  1010. accounts.push(AccountMeta::new(*account_pubkey, false));
  1011. accounts.push(AccountMeta::new_readonly(
  1012. *owner_pubkey,
  1013. signer_pubkeys.is_empty(),
  1014. ));
  1015. for signer_pubkey in signer_pubkeys.iter() {
  1016. accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
  1017. }
  1018. Ok(Instruction {
  1019. program_id: *token_program_id,
  1020. accounts,
  1021. data,
  1022. })
  1023. }
  1024. /// Creates a `BurnChecked` instruction.
  1025. pub fn burn_checked(
  1026. token_program_id: &Pubkey,
  1027. account_pubkey: &Pubkey,
  1028. mint_pubkey: &Pubkey,
  1029. authority_pubkey: &Pubkey,
  1030. signer_pubkeys: &[&Pubkey],
  1031. amount: u64,
  1032. decimals: u8,
  1033. ) -> Result<Instruction, ProgramError> {
  1034. check_program_account(token_program_id)?;
  1035. let data = TokenInstruction::BurnChecked { amount, decimals }.pack();
  1036. let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
  1037. accounts.push(AccountMeta::new(*account_pubkey, false));
  1038. accounts.push(AccountMeta::new(*mint_pubkey, false));
  1039. accounts.push(AccountMeta::new_readonly(
  1040. *authority_pubkey,
  1041. signer_pubkeys.is_empty(),
  1042. ));
  1043. for signer_pubkey in signer_pubkeys.iter() {
  1044. accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
  1045. }
  1046. Ok(Instruction {
  1047. program_id: *token_program_id,
  1048. accounts,
  1049. data,
  1050. })
  1051. }
  1052. /// Utility function that checks index is between MIN_SIGNERS and MAX_SIGNERS
  1053. pub fn is_valid_signer_index(index: usize) -> bool {
  1054. (MIN_SIGNERS..=MAX_SIGNERS).contains(&index)
  1055. }
  1056. #[cfg(test)]
  1057. mod test {
  1058. use super::*;
  1059. #[test]
  1060. fn test_instruction_packing() {
  1061. let check = TokenInstruction::InitializeMint {
  1062. decimals: 2,
  1063. mint_authority: Pubkey::new(&[1u8; 32]),
  1064. freeze_authority: COption::None,
  1065. };
  1066. let packed = check.pack();
  1067. let mut expect = Vec::from([0u8, 2]);
  1068. expect.extend_from_slice(&[1u8; 32]);
  1069. expect.extend_from_slice(&[0]);
  1070. assert_eq!(packed, expect);
  1071. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1072. assert_eq!(unpacked, check);
  1073. let check = TokenInstruction::InitializeMint {
  1074. decimals: 2,
  1075. mint_authority: Pubkey::new(&[2u8; 32]),
  1076. freeze_authority: COption::Some(Pubkey::new(&[3u8; 32])),
  1077. };
  1078. let packed = check.pack();
  1079. let mut expect = vec![0u8, 2];
  1080. expect.extend_from_slice(&[2u8; 32]);
  1081. expect.extend_from_slice(&[1]);
  1082. expect.extend_from_slice(&[3u8; 32]);
  1083. assert_eq!(packed, expect);
  1084. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1085. assert_eq!(unpacked, check);
  1086. let check = TokenInstruction::InitializeAccount;
  1087. let packed = check.pack();
  1088. let expect = Vec::from([1u8]);
  1089. assert_eq!(packed, expect);
  1090. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1091. assert_eq!(unpacked, check);
  1092. let check = TokenInstruction::InitializeMultisig { m: 1 };
  1093. let packed = check.pack();
  1094. let expect = Vec::from([2u8, 1]);
  1095. assert_eq!(packed, expect);
  1096. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1097. assert_eq!(unpacked, check);
  1098. let check = TokenInstruction::Transfer { amount: 1 };
  1099. let packed = check.pack();
  1100. let expect = Vec::from([3u8, 1, 0, 0, 0, 0, 0, 0, 0]);
  1101. assert_eq!(packed, expect);
  1102. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1103. assert_eq!(unpacked, check);
  1104. let check = TokenInstruction::Approve { amount: 1 };
  1105. let packed = check.pack();
  1106. let expect = Vec::from([4u8, 1, 0, 0, 0, 0, 0, 0, 0]);
  1107. assert_eq!(packed, expect);
  1108. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1109. assert_eq!(unpacked, check);
  1110. let check = TokenInstruction::Revoke;
  1111. let packed = check.pack();
  1112. let expect = Vec::from([5u8]);
  1113. assert_eq!(packed, expect);
  1114. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1115. assert_eq!(unpacked, check);
  1116. let check = TokenInstruction::SetAuthority {
  1117. authority_type: AuthorityType::FreezeAccount,
  1118. new_authority: COption::Some(Pubkey::new(&[4u8; 32])),
  1119. };
  1120. let packed = check.pack();
  1121. let mut expect = Vec::from([6u8, 1]);
  1122. expect.extend_from_slice(&[1]);
  1123. expect.extend_from_slice(&[4u8; 32]);
  1124. assert_eq!(packed, expect);
  1125. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1126. assert_eq!(unpacked, check);
  1127. let check = TokenInstruction::MintTo { amount: 1 };
  1128. let packed = check.pack();
  1129. let expect = Vec::from([7u8, 1, 0, 0, 0, 0, 0, 0, 0]);
  1130. assert_eq!(packed, expect);
  1131. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1132. assert_eq!(unpacked, check);
  1133. let check = TokenInstruction::Burn { amount: 1 };
  1134. let packed = check.pack();
  1135. let expect = Vec::from([8u8, 1, 0, 0, 0, 0, 0, 0, 0]);
  1136. assert_eq!(packed, expect);
  1137. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1138. assert_eq!(unpacked, check);
  1139. let check = TokenInstruction::CloseAccount;
  1140. let packed = check.pack();
  1141. let expect = Vec::from([9u8]);
  1142. assert_eq!(packed, expect);
  1143. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1144. assert_eq!(unpacked, check);
  1145. let check = TokenInstruction::FreezeAccount;
  1146. let packed = check.pack();
  1147. let expect = Vec::from([10u8]);
  1148. assert_eq!(packed, expect);
  1149. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1150. assert_eq!(unpacked, check);
  1151. let check = TokenInstruction::ThawAccount;
  1152. let packed = check.pack();
  1153. let expect = Vec::from([11u8]);
  1154. assert_eq!(packed, expect);
  1155. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1156. assert_eq!(unpacked, check);
  1157. let check = TokenInstruction::TransferChecked {
  1158. amount: 1,
  1159. decimals: 2,
  1160. };
  1161. let packed = check.pack();
  1162. let expect = Vec::from([12u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
  1163. assert_eq!(packed, expect);
  1164. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1165. assert_eq!(unpacked, check);
  1166. let check = TokenInstruction::ApproveChecked {
  1167. amount: 1,
  1168. decimals: 2,
  1169. };
  1170. let packed = check.pack();
  1171. let expect = Vec::from([13u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
  1172. assert_eq!(packed, expect);
  1173. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1174. assert_eq!(unpacked, check);
  1175. let check = TokenInstruction::MintToChecked {
  1176. amount: 1,
  1177. decimals: 2,
  1178. };
  1179. let packed = check.pack();
  1180. let expect = Vec::from([14u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
  1181. assert_eq!(packed, expect);
  1182. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1183. assert_eq!(unpacked, check);
  1184. let check = TokenInstruction::BurnChecked {
  1185. amount: 1,
  1186. decimals: 2,
  1187. };
  1188. let packed = check.pack();
  1189. let expect = Vec::from([15u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
  1190. assert_eq!(packed, expect);
  1191. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1192. assert_eq!(unpacked, check);
  1193. let check = TokenInstruction::InitializeAccount2 {
  1194. owner: Pubkey::new(&[2u8; 32]),
  1195. };
  1196. let packed = check.pack();
  1197. let mut expect = vec![16u8];
  1198. expect.extend_from_slice(&[2u8; 32]);
  1199. assert_eq!(packed, expect);
  1200. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1201. assert_eq!(unpacked, check);
  1202. }
  1203. }