instruction.rs 58 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703
  1. //! Instruction types
  2. use {
  3. crate::{check_program_account, error::TokenError},
  4. solana_instruction::{AccountMeta, Instruction},
  5. solana_program_error::ProgramError,
  6. solana_program_option::COption,
  7. solana_pubkey::Pubkey,
  8. solana_sdk_ids::sysvar,
  9. std::{convert::TryInto, mem::size_of},
  10. };
  11. /// Minimum number of multisignature signers (min N)
  12. pub const MIN_SIGNERS: usize = 1;
  13. /// Maximum number of multisignature signers (max N)
  14. pub const MAX_SIGNERS: usize = 11;
  15. /// Serialized length of a `u64`, for unpacking
  16. const U64_BYTES: usize = 8;
  17. /// Instructions supported by the token program.
  18. #[repr(C)]
  19. #[derive(Clone, Debug, PartialEq)]
  20. pub enum TokenInstruction<'a> {
  21. /// Initializes a new mint and optionally deposits all the newly minted
  22. /// tokens in an account.
  23. ///
  24. /// The `InitializeMint` instruction requires no signers and MUST be
  25. /// included within the same Transaction as the system program's
  26. /// `CreateAccount` instruction that creates the account being initialized.
  27. /// Otherwise another party can acquire ownership of the uninitialized
  28. /// account.
  29. ///
  30. /// Accounts expected by this instruction:
  31. ///
  32. /// 0. `[writable]` The mint to initialize.
  33. /// 1. `[]` Rent sysvar
  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
  349. /// instruction data rather than the accounts list. This variant may be
  350. /// preferable when using Cross Program Invocation from an instruction
  351. /// that does not need the owner's `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. /// Given a wrapped / native token account (a token account containing SOL)
  363. /// updates its amount field based on the account's underlying `lamports`.
  364. /// This is useful if a non-wrapped SOL account uses
  365. /// `system_instruction::transfer` to move lamports to a wrapped token
  366. /// account, and needs to have its token `amount` field updated.
  367. ///
  368. /// Accounts expected by this instruction:
  369. ///
  370. /// 0. `[writable]` The native token account to sync with its underlying
  371. /// lamports.
  372. SyncNative,
  373. /// Like [`InitializeAccount2`], but does not require the Rent sysvar to be
  374. /// provided
  375. ///
  376. /// Accounts expected by this instruction:
  377. ///
  378. /// 0. `[writable]` The account to initialize.
  379. /// 1. `[]` The mint this account will be associated with.
  380. InitializeAccount3 {
  381. /// The new account's owner/multisignature.
  382. owner: Pubkey,
  383. },
  384. /// Like [`InitializeMultisig`], but does not require the Rent sysvar to be
  385. /// provided
  386. ///
  387. /// Accounts expected by this instruction:
  388. ///
  389. /// 0. `[writable]` The multisignature account to initialize.
  390. /// 1. ..`1+N` `[]` The signer accounts, must equal to N where `1 <= N <=
  391. /// 11`.
  392. InitializeMultisig2 {
  393. /// The number of signers (M) required to validate this multisignature
  394. /// account.
  395. m: u8,
  396. },
  397. /// Like [`InitializeMint`], but does not require the Rent sysvar to be
  398. /// provided
  399. ///
  400. /// Accounts expected by this instruction:
  401. ///
  402. /// 0. `[writable]` The mint to initialize.
  403. InitializeMint2 {
  404. /// Number of base 10 digits to the right of the decimal place.
  405. decimals: u8,
  406. /// The authority/multisignature to mint tokens.
  407. mint_authority: Pubkey,
  408. /// The freeze authority/multisignature of the mint.
  409. freeze_authority: COption<Pubkey>,
  410. },
  411. /// Gets the required size of an account for the given mint as a
  412. /// little-endian `u64`.
  413. ///
  414. /// Return data can be fetched using `sol_get_return_data` and deserializing
  415. /// the return data as a little-endian `u64`.
  416. ///
  417. /// Accounts expected by this instruction:
  418. ///
  419. /// 0. `[]` The mint to calculate for
  420. GetAccountDataSize, // typically, there's also data, but this program ignores it
  421. /// Initialize the Immutable Owner extension for the given token account
  422. ///
  423. /// Fails if the account has already been initialized, so must be called
  424. /// before `InitializeAccount`.
  425. ///
  426. /// No-ops in this version of the program, but is included for compatibility
  427. /// with the Associated Token Account program.
  428. ///
  429. /// Accounts expected by this instruction:
  430. ///
  431. /// 0. `[writable]` The account to initialize.
  432. ///
  433. /// Data expected by this instruction:
  434. /// None
  435. InitializeImmutableOwner,
  436. /// Convert an Amount of tokens to a `UiAmount` string, using the given
  437. /// mint. In this version of the program, the mint can only specify the
  438. /// number of decimals.
  439. ///
  440. /// Fails on an invalid mint.
  441. ///
  442. /// Return data can be fetched using `sol_get_return_data` and deserialized
  443. /// with `String::from_utf8`.
  444. ///
  445. /// Accounts expected by this instruction:
  446. ///
  447. /// 0. `[]` The mint to calculate for
  448. AmountToUiAmount {
  449. /// The amount of tokens to reformat.
  450. amount: u64,
  451. },
  452. /// Convert a `UiAmount` of tokens to a little-endian `u64` raw Amount,
  453. /// using the given mint. In this version of the program, the mint can
  454. /// only specify the number of decimals.
  455. ///
  456. /// Return data can be fetched using `sol_get_return_data` and deserializing
  457. /// the return data as a little-endian `u64`.
  458. ///
  459. /// Accounts expected by this instruction:
  460. ///
  461. /// 0. `[]` The mint to calculate for
  462. UiAmountToAmount {
  463. /// The `ui_amount` of tokens to reformat.
  464. ui_amount: &'a str,
  465. },
  466. // Any new variants also need to be added to program-2022 `TokenInstruction`, so that the
  467. // latter remains a superset of this instruction set. New variants also need to be added to
  468. // token/js/src/instructions/types.ts to maintain @solana/spl-token compatibility
  469. }
  470. impl<'a> TokenInstruction<'a> {
  471. /// Unpacks a byte buffer into a
  472. /// [`TokenInstruction`](enum.TokenInstruction.html).
  473. pub fn unpack(input: &'a [u8]) -> Result<Self, ProgramError> {
  474. use TokenError::InvalidInstruction;
  475. let (&tag, rest) = input.split_first().ok_or(InvalidInstruction)?;
  476. Ok(match tag {
  477. 0 => {
  478. let (&decimals, rest) = rest.split_first().ok_or(InvalidInstruction)?;
  479. let (mint_authority, rest) = Self::unpack_pubkey(rest)?;
  480. let (freeze_authority, _rest) = Self::unpack_pubkey_option(rest)?;
  481. Self::InitializeMint {
  482. mint_authority,
  483. freeze_authority,
  484. decimals,
  485. }
  486. }
  487. 1 => Self::InitializeAccount,
  488. 2 => {
  489. let &m = rest.first().ok_or(InvalidInstruction)?;
  490. Self::InitializeMultisig { m }
  491. }
  492. 3 | 4 | 7 | 8 => {
  493. let amount = rest
  494. .get(..8)
  495. .and_then(|slice| slice.try_into().ok())
  496. .map(u64::from_le_bytes)
  497. .ok_or(InvalidInstruction)?;
  498. match tag {
  499. 3 => Self::Transfer { amount },
  500. 4 => Self::Approve { amount },
  501. 7 => Self::MintTo { amount },
  502. 8 => Self::Burn { amount },
  503. _ => unreachable!(),
  504. }
  505. }
  506. 5 => Self::Revoke,
  507. 6 => {
  508. let (authority_type, rest) = rest
  509. .split_first()
  510. .ok_or_else(|| ProgramError::from(InvalidInstruction))
  511. .and_then(|(&t, rest)| Ok((AuthorityType::from(t)?, rest)))?;
  512. let (new_authority, _rest) = Self::unpack_pubkey_option(rest)?;
  513. Self::SetAuthority {
  514. authority_type,
  515. new_authority,
  516. }
  517. }
  518. 9 => Self::CloseAccount,
  519. 10 => Self::FreezeAccount,
  520. 11 => Self::ThawAccount,
  521. 12 => {
  522. let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
  523. Self::TransferChecked { amount, decimals }
  524. }
  525. 13 => {
  526. let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
  527. Self::ApproveChecked { amount, decimals }
  528. }
  529. 14 => {
  530. let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
  531. Self::MintToChecked { amount, decimals }
  532. }
  533. 15 => {
  534. let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?;
  535. Self::BurnChecked { amount, decimals }
  536. }
  537. 16 => {
  538. let (owner, _rest) = Self::unpack_pubkey(rest)?;
  539. Self::InitializeAccount2 { owner }
  540. }
  541. 17 => Self::SyncNative,
  542. 18 => {
  543. let (owner, _rest) = Self::unpack_pubkey(rest)?;
  544. Self::InitializeAccount3 { owner }
  545. }
  546. 19 => {
  547. let &m = rest.first().ok_or(InvalidInstruction)?;
  548. Self::InitializeMultisig2 { m }
  549. }
  550. 20 => {
  551. let (&decimals, rest) = rest.split_first().ok_or(InvalidInstruction)?;
  552. let (mint_authority, rest) = Self::unpack_pubkey(rest)?;
  553. let (freeze_authority, _rest) = Self::unpack_pubkey_option(rest)?;
  554. Self::InitializeMint2 {
  555. mint_authority,
  556. freeze_authority,
  557. decimals,
  558. }
  559. }
  560. 21 => Self::GetAccountDataSize,
  561. 22 => Self::InitializeImmutableOwner,
  562. 23 => {
  563. let (amount, _rest) = Self::unpack_u64(rest)?;
  564. Self::AmountToUiAmount { amount }
  565. }
  566. 24 => {
  567. let ui_amount = std::str::from_utf8(rest).map_err(|_| InvalidInstruction)?;
  568. Self::UiAmountToAmount { ui_amount }
  569. }
  570. _ => return Err(TokenError::InvalidInstruction.into()),
  571. })
  572. }
  573. /// Packs a [`TokenInstruction`](enum.TokenInstruction.html) into a byte
  574. /// buffer.
  575. pub fn pack(&self) -> Vec<u8> {
  576. let mut buf = Vec::with_capacity(size_of::<Self>());
  577. match self {
  578. &Self::InitializeMint {
  579. ref mint_authority,
  580. ref freeze_authority,
  581. decimals,
  582. } => {
  583. buf.push(0);
  584. buf.push(decimals);
  585. buf.extend_from_slice(mint_authority.as_ref());
  586. Self::pack_pubkey_option(freeze_authority, &mut buf);
  587. }
  588. Self::InitializeAccount => buf.push(1),
  589. &Self::InitializeMultisig { m } => {
  590. buf.push(2);
  591. buf.push(m);
  592. }
  593. &Self::Transfer { amount } => {
  594. buf.push(3);
  595. buf.extend_from_slice(&amount.to_le_bytes());
  596. }
  597. &Self::Approve { amount } => {
  598. buf.push(4);
  599. buf.extend_from_slice(&amount.to_le_bytes());
  600. }
  601. &Self::MintTo { amount } => {
  602. buf.push(7);
  603. buf.extend_from_slice(&amount.to_le_bytes());
  604. }
  605. &Self::Burn { amount } => {
  606. buf.push(8);
  607. buf.extend_from_slice(&amount.to_le_bytes());
  608. }
  609. Self::Revoke => buf.push(5),
  610. Self::SetAuthority {
  611. authority_type,
  612. ref new_authority,
  613. } => {
  614. buf.push(6);
  615. buf.push(authority_type.into());
  616. Self::pack_pubkey_option(new_authority, &mut buf);
  617. }
  618. Self::CloseAccount => buf.push(9),
  619. Self::FreezeAccount => buf.push(10),
  620. Self::ThawAccount => buf.push(11),
  621. &Self::TransferChecked { amount, decimals } => {
  622. buf.push(12);
  623. buf.extend_from_slice(&amount.to_le_bytes());
  624. buf.push(decimals);
  625. }
  626. &Self::ApproveChecked { amount, decimals } => {
  627. buf.push(13);
  628. buf.extend_from_slice(&amount.to_le_bytes());
  629. buf.push(decimals);
  630. }
  631. &Self::MintToChecked { amount, decimals } => {
  632. buf.push(14);
  633. buf.extend_from_slice(&amount.to_le_bytes());
  634. buf.push(decimals);
  635. }
  636. &Self::BurnChecked { amount, decimals } => {
  637. buf.push(15);
  638. buf.extend_from_slice(&amount.to_le_bytes());
  639. buf.push(decimals);
  640. }
  641. &Self::InitializeAccount2 { owner } => {
  642. buf.push(16);
  643. buf.extend_from_slice(owner.as_ref());
  644. }
  645. &Self::SyncNative => {
  646. buf.push(17);
  647. }
  648. &Self::InitializeAccount3 { owner } => {
  649. buf.push(18);
  650. buf.extend_from_slice(owner.as_ref());
  651. }
  652. &Self::InitializeMultisig2 { m } => {
  653. buf.push(19);
  654. buf.push(m);
  655. }
  656. &Self::InitializeMint2 {
  657. ref mint_authority,
  658. ref freeze_authority,
  659. decimals,
  660. } => {
  661. buf.push(20);
  662. buf.push(decimals);
  663. buf.extend_from_slice(mint_authority.as_ref());
  664. Self::pack_pubkey_option(freeze_authority, &mut buf);
  665. }
  666. &Self::GetAccountDataSize => {
  667. buf.push(21);
  668. }
  669. &Self::InitializeImmutableOwner => {
  670. buf.push(22);
  671. }
  672. &Self::AmountToUiAmount { amount } => {
  673. buf.push(23);
  674. buf.extend_from_slice(&amount.to_le_bytes());
  675. }
  676. Self::UiAmountToAmount { ui_amount } => {
  677. buf.push(24);
  678. buf.extend_from_slice(ui_amount.as_bytes());
  679. }
  680. };
  681. buf
  682. }
  683. fn unpack_pubkey(input: &[u8]) -> Result<(Pubkey, &[u8]), ProgramError> {
  684. if input.len() >= 32 {
  685. let (key, rest) = input.split_at(32);
  686. let pk = Pubkey::try_from(key).map_err(|_| TokenError::InvalidInstruction)?;
  687. Ok((pk, rest))
  688. } else {
  689. Err(TokenError::InvalidInstruction.into())
  690. }
  691. }
  692. fn unpack_pubkey_option(input: &[u8]) -> Result<(COption<Pubkey>, &[u8]), ProgramError> {
  693. match input.split_first() {
  694. Option::Some((&0, rest)) => Ok((COption::None, rest)),
  695. Option::Some((&1, rest)) if rest.len() >= 32 => {
  696. let (key, rest) = rest.split_at(32);
  697. let pk = Pubkey::try_from(key).map_err(|_| TokenError::InvalidInstruction)?;
  698. Ok((COption::Some(pk), rest))
  699. }
  700. _ => Err(TokenError::InvalidInstruction.into()),
  701. }
  702. }
  703. fn pack_pubkey_option(value: &COption<Pubkey>, buf: &mut Vec<u8>) {
  704. match *value {
  705. COption::Some(ref key) => {
  706. buf.push(1);
  707. buf.extend_from_slice(&key.to_bytes());
  708. }
  709. COption::None => buf.push(0),
  710. }
  711. }
  712. fn unpack_u64(input: &[u8]) -> Result<(u64, &[u8]), ProgramError> {
  713. let value = input
  714. .get(..U64_BYTES)
  715. .and_then(|slice| slice.try_into().ok())
  716. .map(u64::from_le_bytes)
  717. .ok_or(TokenError::InvalidInstruction)?;
  718. Ok((value, &input[U64_BYTES..]))
  719. }
  720. fn unpack_amount_decimals(input: &[u8]) -> Result<(u64, u8, &[u8]), ProgramError> {
  721. let (amount, rest) = Self::unpack_u64(input)?;
  722. let (&decimals, rest) = rest.split_first().ok_or(TokenError::InvalidInstruction)?;
  723. Ok((amount, decimals, rest))
  724. }
  725. }
  726. /// Specifies the authority type for `SetAuthority` instructions
  727. #[repr(u8)]
  728. #[derive(Clone, Debug, PartialEq)]
  729. pub enum AuthorityType {
  730. /// Authority to mint new tokens
  731. MintTokens,
  732. /// Authority to freeze any account associated with the Mint
  733. FreezeAccount,
  734. /// Owner of a given token account
  735. AccountOwner,
  736. /// Authority to close a token account
  737. CloseAccount,
  738. }
  739. impl AuthorityType {
  740. fn into(&self) -> u8 {
  741. match self {
  742. AuthorityType::MintTokens => 0,
  743. AuthorityType::FreezeAccount => 1,
  744. AuthorityType::AccountOwner => 2,
  745. AuthorityType::CloseAccount => 3,
  746. }
  747. }
  748. fn from(index: u8) -> Result<Self, ProgramError> {
  749. match index {
  750. 0 => Ok(AuthorityType::MintTokens),
  751. 1 => Ok(AuthorityType::FreezeAccount),
  752. 2 => Ok(AuthorityType::AccountOwner),
  753. 3 => Ok(AuthorityType::CloseAccount),
  754. _ => Err(TokenError::InvalidInstruction.into()),
  755. }
  756. }
  757. }
  758. /// Creates a `InitializeMint` instruction.
  759. pub fn initialize_mint(
  760. token_program_id: &Pubkey,
  761. mint_pubkey: &Pubkey,
  762. mint_authority_pubkey: &Pubkey,
  763. freeze_authority_pubkey: Option<&Pubkey>,
  764. decimals: u8,
  765. ) -> Result<Instruction, ProgramError> {
  766. check_program_account(token_program_id)?;
  767. let freeze_authority = freeze_authority_pubkey.cloned().into();
  768. let data = TokenInstruction::InitializeMint {
  769. mint_authority: *mint_authority_pubkey,
  770. freeze_authority,
  771. decimals,
  772. }
  773. .pack();
  774. let accounts = vec![
  775. AccountMeta::new(*mint_pubkey, false),
  776. AccountMeta::new_readonly(sysvar::rent::id(), false),
  777. ];
  778. Ok(Instruction {
  779. program_id: *token_program_id,
  780. accounts,
  781. data,
  782. })
  783. }
  784. /// Creates a `InitializeMint2` instruction.
  785. pub fn initialize_mint2(
  786. token_program_id: &Pubkey,
  787. mint_pubkey: &Pubkey,
  788. mint_authority_pubkey: &Pubkey,
  789. freeze_authority_pubkey: Option<&Pubkey>,
  790. decimals: u8,
  791. ) -> Result<Instruction, ProgramError> {
  792. check_program_account(token_program_id)?;
  793. let freeze_authority = freeze_authority_pubkey.cloned().into();
  794. let data = TokenInstruction::InitializeMint2 {
  795. mint_authority: *mint_authority_pubkey,
  796. freeze_authority,
  797. decimals,
  798. }
  799. .pack();
  800. let accounts = vec![AccountMeta::new(*mint_pubkey, false)];
  801. Ok(Instruction {
  802. program_id: *token_program_id,
  803. accounts,
  804. data,
  805. })
  806. }
  807. /// Creates a `InitializeAccount` instruction.
  808. pub fn initialize_account(
  809. token_program_id: &Pubkey,
  810. account_pubkey: &Pubkey,
  811. mint_pubkey: &Pubkey,
  812. owner_pubkey: &Pubkey,
  813. ) -> Result<Instruction, ProgramError> {
  814. check_program_account(token_program_id)?;
  815. let data = TokenInstruction::InitializeAccount.pack();
  816. let accounts = vec![
  817. AccountMeta::new(*account_pubkey, false),
  818. AccountMeta::new_readonly(*mint_pubkey, false),
  819. AccountMeta::new_readonly(*owner_pubkey, false),
  820. AccountMeta::new_readonly(sysvar::rent::id(), false),
  821. ];
  822. Ok(Instruction {
  823. program_id: *token_program_id,
  824. accounts,
  825. data,
  826. })
  827. }
  828. /// Creates a `InitializeAccount2` instruction.
  829. pub fn initialize_account2(
  830. token_program_id: &Pubkey,
  831. account_pubkey: &Pubkey,
  832. mint_pubkey: &Pubkey,
  833. owner_pubkey: &Pubkey,
  834. ) -> Result<Instruction, ProgramError> {
  835. check_program_account(token_program_id)?;
  836. let data = TokenInstruction::InitializeAccount2 {
  837. owner: *owner_pubkey,
  838. }
  839. .pack();
  840. let accounts = vec![
  841. AccountMeta::new(*account_pubkey, false),
  842. AccountMeta::new_readonly(*mint_pubkey, false),
  843. AccountMeta::new_readonly(sysvar::rent::id(), false),
  844. ];
  845. Ok(Instruction {
  846. program_id: *token_program_id,
  847. accounts,
  848. data,
  849. })
  850. }
  851. /// Creates a `InitializeAccount3` instruction.
  852. pub fn initialize_account3(
  853. token_program_id: &Pubkey,
  854. account_pubkey: &Pubkey,
  855. mint_pubkey: &Pubkey,
  856. owner_pubkey: &Pubkey,
  857. ) -> Result<Instruction, ProgramError> {
  858. check_program_account(token_program_id)?;
  859. let data = TokenInstruction::InitializeAccount3 {
  860. owner: *owner_pubkey,
  861. }
  862. .pack();
  863. let accounts = vec![
  864. AccountMeta::new(*account_pubkey, false),
  865. AccountMeta::new_readonly(*mint_pubkey, false),
  866. ];
  867. Ok(Instruction {
  868. program_id: *token_program_id,
  869. accounts,
  870. data,
  871. })
  872. }
  873. /// Creates a `InitializeMultisig` instruction.
  874. pub fn initialize_multisig(
  875. token_program_id: &Pubkey,
  876. multisig_pubkey: &Pubkey,
  877. signer_pubkeys: &[&Pubkey],
  878. m: u8,
  879. ) -> Result<Instruction, ProgramError> {
  880. check_program_account(token_program_id)?;
  881. if !is_valid_signer_index(m as usize)
  882. || !is_valid_signer_index(signer_pubkeys.len())
  883. || m as usize > signer_pubkeys.len()
  884. {
  885. return Err(ProgramError::MissingRequiredSignature);
  886. }
  887. let data = TokenInstruction::InitializeMultisig { m }.pack();
  888. let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len());
  889. accounts.push(AccountMeta::new(*multisig_pubkey, false));
  890. accounts.push(AccountMeta::new_readonly(sysvar::rent::id(), false));
  891. for signer_pubkey in signer_pubkeys.iter() {
  892. accounts.push(AccountMeta::new_readonly(**signer_pubkey, false));
  893. }
  894. Ok(Instruction {
  895. program_id: *token_program_id,
  896. accounts,
  897. data,
  898. })
  899. }
  900. /// Creates a `InitializeMultisig2` instruction.
  901. pub fn initialize_multisig2(
  902. token_program_id: &Pubkey,
  903. multisig_pubkey: &Pubkey,
  904. signer_pubkeys: &[&Pubkey],
  905. m: u8,
  906. ) -> Result<Instruction, ProgramError> {
  907. check_program_account(token_program_id)?;
  908. if !is_valid_signer_index(m as usize)
  909. || !is_valid_signer_index(signer_pubkeys.len())
  910. || m as usize > signer_pubkeys.len()
  911. {
  912. return Err(ProgramError::MissingRequiredSignature);
  913. }
  914. let data = TokenInstruction::InitializeMultisig2 { m }.pack();
  915. let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len());
  916. accounts.push(AccountMeta::new(*multisig_pubkey, false));
  917. for signer_pubkey in signer_pubkeys.iter() {
  918. accounts.push(AccountMeta::new_readonly(**signer_pubkey, false));
  919. }
  920. Ok(Instruction {
  921. program_id: *token_program_id,
  922. accounts,
  923. data,
  924. })
  925. }
  926. /// Creates a `Transfer` instruction.
  927. pub fn transfer(
  928. token_program_id: &Pubkey,
  929. source_pubkey: &Pubkey,
  930. destination_pubkey: &Pubkey,
  931. authority_pubkey: &Pubkey,
  932. signer_pubkeys: &[&Pubkey],
  933. amount: u64,
  934. ) -> Result<Instruction, ProgramError> {
  935. check_program_account(token_program_id)?;
  936. let data = TokenInstruction::Transfer { amount }.pack();
  937. let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
  938. accounts.push(AccountMeta::new(*source_pubkey, false));
  939. accounts.push(AccountMeta::new(*destination_pubkey, false));
  940. accounts.push(AccountMeta::new_readonly(
  941. *authority_pubkey,
  942. signer_pubkeys.is_empty(),
  943. ));
  944. for signer_pubkey in signer_pubkeys.iter() {
  945. accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
  946. }
  947. Ok(Instruction {
  948. program_id: *token_program_id,
  949. accounts,
  950. data,
  951. })
  952. }
  953. /// Creates an `Approve` instruction.
  954. pub fn approve(
  955. token_program_id: &Pubkey,
  956. source_pubkey: &Pubkey,
  957. delegate_pubkey: &Pubkey,
  958. owner_pubkey: &Pubkey,
  959. signer_pubkeys: &[&Pubkey],
  960. amount: u64,
  961. ) -> Result<Instruction, ProgramError> {
  962. check_program_account(token_program_id)?;
  963. let data = TokenInstruction::Approve { amount }.pack();
  964. let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
  965. accounts.push(AccountMeta::new(*source_pubkey, false));
  966. accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false));
  967. accounts.push(AccountMeta::new_readonly(
  968. *owner_pubkey,
  969. signer_pubkeys.is_empty(),
  970. ));
  971. for signer_pubkey in signer_pubkeys.iter() {
  972. accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
  973. }
  974. Ok(Instruction {
  975. program_id: *token_program_id,
  976. accounts,
  977. data,
  978. })
  979. }
  980. /// Creates a `Revoke` instruction.
  981. pub fn revoke(
  982. token_program_id: &Pubkey,
  983. source_pubkey: &Pubkey,
  984. owner_pubkey: &Pubkey,
  985. signer_pubkeys: &[&Pubkey],
  986. ) -> Result<Instruction, ProgramError> {
  987. check_program_account(token_program_id)?;
  988. let data = TokenInstruction::Revoke.pack();
  989. let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len());
  990. accounts.push(AccountMeta::new(*source_pubkey, false));
  991. accounts.push(AccountMeta::new_readonly(
  992. *owner_pubkey,
  993. signer_pubkeys.is_empty(),
  994. ));
  995. for signer_pubkey in signer_pubkeys.iter() {
  996. accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
  997. }
  998. Ok(Instruction {
  999. program_id: *token_program_id,
  1000. accounts,
  1001. data,
  1002. })
  1003. }
  1004. /// Creates a `SetAuthority` instruction.
  1005. pub fn set_authority(
  1006. token_program_id: &Pubkey,
  1007. owned_pubkey: &Pubkey,
  1008. new_authority_pubkey: Option<&Pubkey>,
  1009. authority_type: AuthorityType,
  1010. owner_pubkey: &Pubkey,
  1011. signer_pubkeys: &[&Pubkey],
  1012. ) -> Result<Instruction, ProgramError> {
  1013. check_program_account(token_program_id)?;
  1014. let new_authority = new_authority_pubkey.cloned().into();
  1015. let data = TokenInstruction::SetAuthority {
  1016. authority_type,
  1017. new_authority,
  1018. }
  1019. .pack();
  1020. let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
  1021. accounts.push(AccountMeta::new(*owned_pubkey, false));
  1022. accounts.push(AccountMeta::new_readonly(
  1023. *owner_pubkey,
  1024. signer_pubkeys.is_empty(),
  1025. ));
  1026. for signer_pubkey in signer_pubkeys.iter() {
  1027. accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
  1028. }
  1029. Ok(Instruction {
  1030. program_id: *token_program_id,
  1031. accounts,
  1032. data,
  1033. })
  1034. }
  1035. /// Creates a `MintTo` instruction.
  1036. pub fn mint_to(
  1037. token_program_id: &Pubkey,
  1038. mint_pubkey: &Pubkey,
  1039. account_pubkey: &Pubkey,
  1040. owner_pubkey: &Pubkey,
  1041. signer_pubkeys: &[&Pubkey],
  1042. amount: u64,
  1043. ) -> Result<Instruction, ProgramError> {
  1044. check_program_account(token_program_id)?;
  1045. let data = TokenInstruction::MintTo { amount }.pack();
  1046. let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
  1047. accounts.push(AccountMeta::new(*mint_pubkey, false));
  1048. accounts.push(AccountMeta::new(*account_pubkey, false));
  1049. accounts.push(AccountMeta::new_readonly(
  1050. *owner_pubkey,
  1051. signer_pubkeys.is_empty(),
  1052. ));
  1053. for signer_pubkey in signer_pubkeys.iter() {
  1054. accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
  1055. }
  1056. Ok(Instruction {
  1057. program_id: *token_program_id,
  1058. accounts,
  1059. data,
  1060. })
  1061. }
  1062. /// Creates a `Burn` instruction.
  1063. pub fn burn(
  1064. token_program_id: &Pubkey,
  1065. account_pubkey: &Pubkey,
  1066. mint_pubkey: &Pubkey,
  1067. authority_pubkey: &Pubkey,
  1068. signer_pubkeys: &[&Pubkey],
  1069. amount: u64,
  1070. ) -> Result<Instruction, ProgramError> {
  1071. check_program_account(token_program_id)?;
  1072. let data = TokenInstruction::Burn { amount }.pack();
  1073. let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
  1074. accounts.push(AccountMeta::new(*account_pubkey, false));
  1075. accounts.push(AccountMeta::new(*mint_pubkey, false));
  1076. accounts.push(AccountMeta::new_readonly(
  1077. *authority_pubkey,
  1078. signer_pubkeys.is_empty(),
  1079. ));
  1080. for signer_pubkey in signer_pubkeys.iter() {
  1081. accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
  1082. }
  1083. Ok(Instruction {
  1084. program_id: *token_program_id,
  1085. accounts,
  1086. data,
  1087. })
  1088. }
  1089. /// Creates a `CloseAccount` instruction.
  1090. pub fn close_account(
  1091. token_program_id: &Pubkey,
  1092. account_pubkey: &Pubkey,
  1093. destination_pubkey: &Pubkey,
  1094. owner_pubkey: &Pubkey,
  1095. signer_pubkeys: &[&Pubkey],
  1096. ) -> Result<Instruction, ProgramError> {
  1097. check_program_account(token_program_id)?;
  1098. let data = TokenInstruction::CloseAccount.pack();
  1099. let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
  1100. accounts.push(AccountMeta::new(*account_pubkey, false));
  1101. accounts.push(AccountMeta::new(*destination_pubkey, false));
  1102. accounts.push(AccountMeta::new_readonly(
  1103. *owner_pubkey,
  1104. signer_pubkeys.is_empty(),
  1105. ));
  1106. for signer_pubkey in signer_pubkeys.iter() {
  1107. accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
  1108. }
  1109. Ok(Instruction {
  1110. program_id: *token_program_id,
  1111. accounts,
  1112. data,
  1113. })
  1114. }
  1115. /// Creates a `FreezeAccount` instruction.
  1116. pub fn freeze_account(
  1117. token_program_id: &Pubkey,
  1118. account_pubkey: &Pubkey,
  1119. mint_pubkey: &Pubkey,
  1120. owner_pubkey: &Pubkey,
  1121. signer_pubkeys: &[&Pubkey],
  1122. ) -> Result<Instruction, ProgramError> {
  1123. check_program_account(token_program_id)?;
  1124. let data = TokenInstruction::FreezeAccount.pack();
  1125. let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
  1126. accounts.push(AccountMeta::new(*account_pubkey, false));
  1127. accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
  1128. accounts.push(AccountMeta::new_readonly(
  1129. *owner_pubkey,
  1130. signer_pubkeys.is_empty(),
  1131. ));
  1132. for signer_pubkey in signer_pubkeys.iter() {
  1133. accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
  1134. }
  1135. Ok(Instruction {
  1136. program_id: *token_program_id,
  1137. accounts,
  1138. data,
  1139. })
  1140. }
  1141. /// Creates a `ThawAccount` instruction.
  1142. pub fn thaw_account(
  1143. token_program_id: &Pubkey,
  1144. account_pubkey: &Pubkey,
  1145. mint_pubkey: &Pubkey,
  1146. owner_pubkey: &Pubkey,
  1147. signer_pubkeys: &[&Pubkey],
  1148. ) -> Result<Instruction, ProgramError> {
  1149. check_program_account(token_program_id)?;
  1150. let data = TokenInstruction::ThawAccount.pack();
  1151. let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
  1152. accounts.push(AccountMeta::new(*account_pubkey, false));
  1153. accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
  1154. accounts.push(AccountMeta::new_readonly(
  1155. *owner_pubkey,
  1156. signer_pubkeys.is_empty(),
  1157. ));
  1158. for signer_pubkey in signer_pubkeys.iter() {
  1159. accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
  1160. }
  1161. Ok(Instruction {
  1162. program_id: *token_program_id,
  1163. accounts,
  1164. data,
  1165. })
  1166. }
  1167. /// Creates a `TransferChecked` instruction.
  1168. #[allow(clippy::too_many_arguments)]
  1169. pub fn transfer_checked(
  1170. token_program_id: &Pubkey,
  1171. source_pubkey: &Pubkey,
  1172. mint_pubkey: &Pubkey,
  1173. destination_pubkey: &Pubkey,
  1174. authority_pubkey: &Pubkey,
  1175. signer_pubkeys: &[&Pubkey],
  1176. amount: u64,
  1177. decimals: u8,
  1178. ) -> Result<Instruction, ProgramError> {
  1179. check_program_account(token_program_id)?;
  1180. let data = TokenInstruction::TransferChecked { amount, decimals }.pack();
  1181. let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
  1182. accounts.push(AccountMeta::new(*source_pubkey, false));
  1183. accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
  1184. accounts.push(AccountMeta::new(*destination_pubkey, false));
  1185. accounts.push(AccountMeta::new_readonly(
  1186. *authority_pubkey,
  1187. signer_pubkeys.is_empty(),
  1188. ));
  1189. for signer_pubkey in signer_pubkeys.iter() {
  1190. accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
  1191. }
  1192. Ok(Instruction {
  1193. program_id: *token_program_id,
  1194. accounts,
  1195. data,
  1196. })
  1197. }
  1198. /// Creates an `ApproveChecked` instruction.
  1199. #[allow(clippy::too_many_arguments)]
  1200. pub fn approve_checked(
  1201. token_program_id: &Pubkey,
  1202. source_pubkey: &Pubkey,
  1203. mint_pubkey: &Pubkey,
  1204. delegate_pubkey: &Pubkey,
  1205. owner_pubkey: &Pubkey,
  1206. signer_pubkeys: &[&Pubkey],
  1207. amount: u64,
  1208. decimals: u8,
  1209. ) -> Result<Instruction, ProgramError> {
  1210. check_program_account(token_program_id)?;
  1211. let data = TokenInstruction::ApproveChecked { amount, decimals }.pack();
  1212. let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
  1213. accounts.push(AccountMeta::new(*source_pubkey, false));
  1214. accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
  1215. accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false));
  1216. accounts.push(AccountMeta::new_readonly(
  1217. *owner_pubkey,
  1218. signer_pubkeys.is_empty(),
  1219. ));
  1220. for signer_pubkey in signer_pubkeys.iter() {
  1221. accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
  1222. }
  1223. Ok(Instruction {
  1224. program_id: *token_program_id,
  1225. accounts,
  1226. data,
  1227. })
  1228. }
  1229. /// Creates a `MintToChecked` instruction.
  1230. pub fn mint_to_checked(
  1231. token_program_id: &Pubkey,
  1232. mint_pubkey: &Pubkey,
  1233. account_pubkey: &Pubkey,
  1234. owner_pubkey: &Pubkey,
  1235. signer_pubkeys: &[&Pubkey],
  1236. amount: u64,
  1237. decimals: u8,
  1238. ) -> Result<Instruction, ProgramError> {
  1239. check_program_account(token_program_id)?;
  1240. let data = TokenInstruction::MintToChecked { amount, decimals }.pack();
  1241. let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
  1242. accounts.push(AccountMeta::new(*mint_pubkey, false));
  1243. accounts.push(AccountMeta::new(*account_pubkey, false));
  1244. accounts.push(AccountMeta::new_readonly(
  1245. *owner_pubkey,
  1246. signer_pubkeys.is_empty(),
  1247. ));
  1248. for signer_pubkey in signer_pubkeys.iter() {
  1249. accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
  1250. }
  1251. Ok(Instruction {
  1252. program_id: *token_program_id,
  1253. accounts,
  1254. data,
  1255. })
  1256. }
  1257. /// Creates a `BurnChecked` instruction.
  1258. pub fn burn_checked(
  1259. token_program_id: &Pubkey,
  1260. account_pubkey: &Pubkey,
  1261. mint_pubkey: &Pubkey,
  1262. authority_pubkey: &Pubkey,
  1263. signer_pubkeys: &[&Pubkey],
  1264. amount: u64,
  1265. decimals: u8,
  1266. ) -> Result<Instruction, ProgramError> {
  1267. check_program_account(token_program_id)?;
  1268. let data = TokenInstruction::BurnChecked { amount, decimals }.pack();
  1269. let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
  1270. accounts.push(AccountMeta::new(*account_pubkey, false));
  1271. accounts.push(AccountMeta::new(*mint_pubkey, false));
  1272. accounts.push(AccountMeta::new_readonly(
  1273. *authority_pubkey,
  1274. signer_pubkeys.is_empty(),
  1275. ));
  1276. for signer_pubkey in signer_pubkeys.iter() {
  1277. accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
  1278. }
  1279. Ok(Instruction {
  1280. program_id: *token_program_id,
  1281. accounts,
  1282. data,
  1283. })
  1284. }
  1285. /// Creates a `SyncNative` instruction
  1286. pub fn sync_native(
  1287. token_program_id: &Pubkey,
  1288. account_pubkey: &Pubkey,
  1289. ) -> Result<Instruction, ProgramError> {
  1290. check_program_account(token_program_id)?;
  1291. Ok(Instruction {
  1292. program_id: *token_program_id,
  1293. accounts: vec![AccountMeta::new(*account_pubkey, false)],
  1294. data: TokenInstruction::SyncNative.pack(),
  1295. })
  1296. }
  1297. /// Creates a `GetAccountDataSize` instruction
  1298. pub fn get_account_data_size(
  1299. token_program_id: &Pubkey,
  1300. mint_pubkey: &Pubkey,
  1301. ) -> Result<Instruction, ProgramError> {
  1302. check_program_account(token_program_id)?;
  1303. Ok(Instruction {
  1304. program_id: *token_program_id,
  1305. accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)],
  1306. data: TokenInstruction::GetAccountDataSize.pack(),
  1307. })
  1308. }
  1309. /// Creates a `InitializeImmutableOwner` instruction
  1310. pub fn initialize_immutable_owner(
  1311. token_program_id: &Pubkey,
  1312. account_pubkey: &Pubkey,
  1313. ) -> Result<Instruction, ProgramError> {
  1314. check_program_account(token_program_id)?;
  1315. Ok(Instruction {
  1316. program_id: *token_program_id,
  1317. accounts: vec![AccountMeta::new(*account_pubkey, false)],
  1318. data: TokenInstruction::InitializeImmutableOwner.pack(),
  1319. })
  1320. }
  1321. /// Creates an `AmountToUiAmount` instruction
  1322. pub fn amount_to_ui_amount(
  1323. token_program_id: &Pubkey,
  1324. mint_pubkey: &Pubkey,
  1325. amount: u64,
  1326. ) -> Result<Instruction, ProgramError> {
  1327. check_program_account(token_program_id)?;
  1328. Ok(Instruction {
  1329. program_id: *token_program_id,
  1330. accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)],
  1331. data: TokenInstruction::AmountToUiAmount { amount }.pack(),
  1332. })
  1333. }
  1334. /// Creates a `UiAmountToAmount` instruction
  1335. pub fn ui_amount_to_amount(
  1336. token_program_id: &Pubkey,
  1337. mint_pubkey: &Pubkey,
  1338. ui_amount: &str,
  1339. ) -> Result<Instruction, ProgramError> {
  1340. check_program_account(token_program_id)?;
  1341. Ok(Instruction {
  1342. program_id: *token_program_id,
  1343. accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)],
  1344. data: TokenInstruction::UiAmountToAmount { ui_amount }.pack(),
  1345. })
  1346. }
  1347. /// Utility function that checks index is between `MIN_SIGNERS` and
  1348. /// `MAX_SIGNERS`
  1349. pub fn is_valid_signer_index(index: usize) -> bool {
  1350. (MIN_SIGNERS..=MAX_SIGNERS).contains(&index)
  1351. }
  1352. #[cfg(test)]
  1353. mod test {
  1354. use {super::*, proptest::prelude::*};
  1355. #[test]
  1356. fn test_instruction_packing() {
  1357. let check = TokenInstruction::InitializeMint {
  1358. decimals: 2,
  1359. mint_authority: Pubkey::new_from_array([1u8; 32]),
  1360. freeze_authority: COption::None,
  1361. };
  1362. let packed = check.pack();
  1363. let mut expect = Vec::from([0u8, 2]);
  1364. expect.extend_from_slice(&[1u8; 32]);
  1365. expect.extend_from_slice(&[0]);
  1366. assert_eq!(packed, expect);
  1367. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1368. assert_eq!(unpacked, check);
  1369. let check = TokenInstruction::InitializeMint {
  1370. decimals: 2,
  1371. mint_authority: Pubkey::new_from_array([2u8; 32]),
  1372. freeze_authority: COption::Some(Pubkey::new_from_array([3u8; 32])),
  1373. };
  1374. let packed = check.pack();
  1375. let mut expect = vec![0u8, 2];
  1376. expect.extend_from_slice(&[2u8; 32]);
  1377. expect.extend_from_slice(&[1]);
  1378. expect.extend_from_slice(&[3u8; 32]);
  1379. assert_eq!(packed, expect);
  1380. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1381. assert_eq!(unpacked, check);
  1382. let check = TokenInstruction::InitializeAccount;
  1383. let packed = check.pack();
  1384. let expect = Vec::from([1u8]);
  1385. assert_eq!(packed, expect);
  1386. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1387. assert_eq!(unpacked, check);
  1388. let check = TokenInstruction::InitializeMultisig { m: 1 };
  1389. let packed = check.pack();
  1390. let expect = Vec::from([2u8, 1]);
  1391. assert_eq!(packed, expect);
  1392. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1393. assert_eq!(unpacked, check);
  1394. let check = TokenInstruction::Transfer { amount: 1 };
  1395. let packed = check.pack();
  1396. let expect = Vec::from([3u8, 1, 0, 0, 0, 0, 0, 0, 0]);
  1397. assert_eq!(packed, expect);
  1398. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1399. assert_eq!(unpacked, check);
  1400. let check = TokenInstruction::Approve { amount: 1 };
  1401. let packed = check.pack();
  1402. let expect = Vec::from([4u8, 1, 0, 0, 0, 0, 0, 0, 0]);
  1403. assert_eq!(packed, expect);
  1404. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1405. assert_eq!(unpacked, check);
  1406. let check = TokenInstruction::Revoke;
  1407. let packed = check.pack();
  1408. let expect = Vec::from([5u8]);
  1409. assert_eq!(packed, expect);
  1410. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1411. assert_eq!(unpacked, check);
  1412. let check = TokenInstruction::SetAuthority {
  1413. authority_type: AuthorityType::FreezeAccount,
  1414. new_authority: COption::Some(Pubkey::new_from_array([4u8; 32])),
  1415. };
  1416. let packed = check.pack();
  1417. let mut expect = Vec::from([6u8, 1]);
  1418. expect.extend_from_slice(&[1]);
  1419. expect.extend_from_slice(&[4u8; 32]);
  1420. assert_eq!(packed, expect);
  1421. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1422. assert_eq!(unpacked, check);
  1423. let check = TokenInstruction::MintTo { amount: 1 };
  1424. let packed = check.pack();
  1425. let expect = Vec::from([7u8, 1, 0, 0, 0, 0, 0, 0, 0]);
  1426. assert_eq!(packed, expect);
  1427. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1428. assert_eq!(unpacked, check);
  1429. let check = TokenInstruction::Burn { amount: 1 };
  1430. let packed = check.pack();
  1431. let expect = Vec::from([8u8, 1, 0, 0, 0, 0, 0, 0, 0]);
  1432. assert_eq!(packed, expect);
  1433. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1434. assert_eq!(unpacked, check);
  1435. let check = TokenInstruction::CloseAccount;
  1436. let packed = check.pack();
  1437. let expect = Vec::from([9u8]);
  1438. assert_eq!(packed, expect);
  1439. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1440. assert_eq!(unpacked, check);
  1441. let check = TokenInstruction::FreezeAccount;
  1442. let packed = check.pack();
  1443. let expect = Vec::from([10u8]);
  1444. assert_eq!(packed, expect);
  1445. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1446. assert_eq!(unpacked, check);
  1447. let check = TokenInstruction::ThawAccount;
  1448. let packed = check.pack();
  1449. let expect = Vec::from([11u8]);
  1450. assert_eq!(packed, expect);
  1451. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1452. assert_eq!(unpacked, check);
  1453. let check = TokenInstruction::TransferChecked {
  1454. amount: 1,
  1455. decimals: 2,
  1456. };
  1457. let packed = check.pack();
  1458. let expect = Vec::from([12u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
  1459. assert_eq!(packed, expect);
  1460. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1461. assert_eq!(unpacked, check);
  1462. let check = TokenInstruction::ApproveChecked {
  1463. amount: 1,
  1464. decimals: 2,
  1465. };
  1466. let packed = check.pack();
  1467. let expect = Vec::from([13u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
  1468. assert_eq!(packed, expect);
  1469. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1470. assert_eq!(unpacked, check);
  1471. let check = TokenInstruction::MintToChecked {
  1472. amount: 1,
  1473. decimals: 2,
  1474. };
  1475. let packed = check.pack();
  1476. let expect = Vec::from([14u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
  1477. assert_eq!(packed, expect);
  1478. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1479. assert_eq!(unpacked, check);
  1480. let check = TokenInstruction::BurnChecked {
  1481. amount: 1,
  1482. decimals: 2,
  1483. };
  1484. let packed = check.pack();
  1485. let expect = Vec::from([15u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
  1486. assert_eq!(packed, expect);
  1487. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1488. assert_eq!(unpacked, check);
  1489. let check = TokenInstruction::InitializeAccount2 {
  1490. owner: Pubkey::new_from_array([2u8; 32]),
  1491. };
  1492. let packed = check.pack();
  1493. let mut expect = vec![16u8];
  1494. expect.extend_from_slice(&[2u8; 32]);
  1495. assert_eq!(packed, expect);
  1496. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1497. assert_eq!(unpacked, check);
  1498. let check = TokenInstruction::SyncNative;
  1499. let packed = check.pack();
  1500. let expect = vec![17u8];
  1501. assert_eq!(packed, expect);
  1502. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1503. assert_eq!(unpacked, check);
  1504. let check = TokenInstruction::InitializeAccount3 {
  1505. owner: Pubkey::new_from_array([2u8; 32]),
  1506. };
  1507. let packed = check.pack();
  1508. let mut expect = vec![18u8];
  1509. expect.extend_from_slice(&[2u8; 32]);
  1510. assert_eq!(packed, expect);
  1511. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1512. assert_eq!(unpacked, check);
  1513. let check = TokenInstruction::InitializeMultisig2 { m: 1 };
  1514. let packed = check.pack();
  1515. let expect = Vec::from([19u8, 1]);
  1516. assert_eq!(packed, expect);
  1517. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1518. assert_eq!(unpacked, check);
  1519. let check = TokenInstruction::InitializeMint2 {
  1520. decimals: 2,
  1521. mint_authority: Pubkey::new_from_array([1u8; 32]),
  1522. freeze_authority: COption::None,
  1523. };
  1524. let packed = check.pack();
  1525. let mut expect = Vec::from([20u8, 2]);
  1526. expect.extend_from_slice(&[1u8; 32]);
  1527. expect.extend_from_slice(&[0]);
  1528. assert_eq!(packed, expect);
  1529. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1530. assert_eq!(unpacked, check);
  1531. let check = TokenInstruction::InitializeMint2 {
  1532. decimals: 2,
  1533. mint_authority: Pubkey::new_from_array([2u8; 32]),
  1534. freeze_authority: COption::Some(Pubkey::new_from_array([3u8; 32])),
  1535. };
  1536. let packed = check.pack();
  1537. let mut expect = vec![20u8, 2];
  1538. expect.extend_from_slice(&[2u8; 32]);
  1539. expect.extend_from_slice(&[1]);
  1540. expect.extend_from_slice(&[3u8; 32]);
  1541. assert_eq!(packed, expect);
  1542. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1543. assert_eq!(unpacked, check);
  1544. let check = TokenInstruction::GetAccountDataSize;
  1545. let packed = check.pack();
  1546. let expect = vec![21u8];
  1547. assert_eq!(packed, expect);
  1548. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1549. assert_eq!(unpacked, check);
  1550. let check = TokenInstruction::InitializeImmutableOwner;
  1551. let packed = check.pack();
  1552. let expect = vec![22u8];
  1553. assert_eq!(packed, expect);
  1554. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1555. assert_eq!(unpacked, check);
  1556. let check = TokenInstruction::AmountToUiAmount { amount: 42 };
  1557. let packed = check.pack();
  1558. let expect = vec![23u8, 42, 0, 0, 0, 0, 0, 0, 0];
  1559. assert_eq!(packed, expect);
  1560. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1561. assert_eq!(unpacked, check);
  1562. let check = TokenInstruction::UiAmountToAmount { ui_amount: "0.42" };
  1563. let packed = check.pack();
  1564. let expect = vec![24u8, 48, 46, 52, 50];
  1565. assert_eq!(packed, expect);
  1566. let unpacked = TokenInstruction::unpack(&expect).unwrap();
  1567. assert_eq!(unpacked, check);
  1568. }
  1569. #[test]
  1570. fn test_instruction_unpack_panic() {
  1571. for i in 0..255u8 {
  1572. for j in 1..10 {
  1573. let mut data = vec![0; j];
  1574. data[0] = i;
  1575. let _no_panic = TokenInstruction::unpack(&data);
  1576. }
  1577. }
  1578. }
  1579. proptest! {
  1580. #![proptest_config(ProptestConfig::with_cases(1024))]
  1581. #[test]
  1582. fn test_instruction_unpack_proptest(
  1583. data in prop::collection::vec(any::<u8>(), 0..255)
  1584. ) {
  1585. let _no_panic = TokenInstruction::unpack(&data);
  1586. }
  1587. }
  1588. }