token_2022.rs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. use anchor_lang::solana_program::account_info::AccountInfo;
  2. use anchor_lang::solana_program::pubkey::Pubkey;
  3. use anchor_lang::{context::CpiContext, Accounts};
  4. use anchor_lang::{solana_program, Result};
  5. pub use spl_token_2022;
  6. pub use spl_token_2022::ID;
  7. #[deprecated(
  8. since = "0.28.0",
  9. note = "please use `transfer_checked` or `transfer_checked_with_fee` instead"
  10. )]
  11. pub fn transfer<'info>(
  12. ctx: CpiContext<'_, '_, '_, 'info, Transfer<'info>>,
  13. amount: u64,
  14. ) -> Result<()> {
  15. #[allow(deprecated)]
  16. let ix = spl_token_2022::instruction::transfer(
  17. ctx.program.key,
  18. ctx.accounts.from.key,
  19. ctx.accounts.to.key,
  20. ctx.accounts.authority.key,
  21. &[],
  22. amount,
  23. )?;
  24. solana_program::program::invoke_signed(
  25. &ix,
  26. &[ctx.accounts.from, ctx.accounts.to, ctx.accounts.authority],
  27. ctx.signer_seeds,
  28. )
  29. .map_err(Into::into)
  30. }
  31. pub fn transfer_checked<'info>(
  32. ctx: CpiContext<'_, '_, '_, 'info, TransferChecked<'info>>,
  33. amount: u64,
  34. decimals: u8,
  35. ) -> Result<()> {
  36. let ix = spl_token_2022::instruction::transfer_checked(
  37. ctx.program.key,
  38. ctx.accounts.from.key,
  39. ctx.accounts.mint.key,
  40. ctx.accounts.to.key,
  41. ctx.accounts.authority.key,
  42. &[],
  43. amount,
  44. decimals,
  45. )?;
  46. solana_program::program::invoke_signed(
  47. &ix,
  48. &[
  49. ctx.accounts.from,
  50. ctx.accounts.mint,
  51. ctx.accounts.to,
  52. ctx.accounts.authority,
  53. ],
  54. ctx.signer_seeds,
  55. )
  56. .map_err(Into::into)
  57. }
  58. pub fn mint_to<'info>(
  59. ctx: CpiContext<'_, '_, '_, 'info, MintTo<'info>>,
  60. amount: u64,
  61. ) -> Result<()> {
  62. let ix = spl_token_2022::instruction::mint_to(
  63. ctx.program.key,
  64. ctx.accounts.mint.key,
  65. ctx.accounts.to.key,
  66. ctx.accounts.authority.key,
  67. &[],
  68. amount,
  69. )?;
  70. solana_program::program::invoke_signed(
  71. &ix,
  72. &[ctx.accounts.to, ctx.accounts.mint, ctx.accounts.authority],
  73. ctx.signer_seeds,
  74. )
  75. .map_err(Into::into)
  76. }
  77. pub fn burn<'info>(ctx: CpiContext<'_, '_, '_, 'info, Burn<'info>>, amount: u64) -> Result<()> {
  78. let ix = spl_token_2022::instruction::burn(
  79. ctx.program.key,
  80. ctx.accounts.from.key,
  81. ctx.accounts.mint.key,
  82. ctx.accounts.authority.key,
  83. &[],
  84. amount,
  85. )?;
  86. solana_program::program::invoke_signed(
  87. &ix,
  88. &[ctx.accounts.from, ctx.accounts.mint, ctx.accounts.authority],
  89. ctx.signer_seeds,
  90. )
  91. .map_err(Into::into)
  92. }
  93. pub fn approve<'info>(
  94. ctx: CpiContext<'_, '_, '_, 'info, Approve<'info>>,
  95. amount: u64,
  96. ) -> Result<()> {
  97. let ix = spl_token_2022::instruction::approve(
  98. ctx.program.key,
  99. ctx.accounts.to.key,
  100. ctx.accounts.delegate.key,
  101. ctx.accounts.authority.key,
  102. &[],
  103. amount,
  104. )?;
  105. solana_program::program::invoke_signed(
  106. &ix,
  107. &[
  108. ctx.accounts.to,
  109. ctx.accounts.delegate,
  110. ctx.accounts.authority,
  111. ],
  112. ctx.signer_seeds,
  113. )
  114. .map_err(Into::into)
  115. }
  116. pub fn revoke<'info>(ctx: CpiContext<'_, '_, '_, 'info, Revoke<'info>>) -> Result<()> {
  117. let ix = spl_token_2022::instruction::revoke(
  118. ctx.program.key,
  119. ctx.accounts.source.key,
  120. ctx.accounts.authority.key,
  121. &[],
  122. )?;
  123. solana_program::program::invoke_signed(
  124. &ix,
  125. &[ctx.accounts.source, ctx.accounts.authority],
  126. ctx.signer_seeds,
  127. )
  128. .map_err(Into::into)
  129. }
  130. pub fn initialize_account<'info>(
  131. ctx: CpiContext<'_, '_, '_, 'info, InitializeAccount<'info>>,
  132. ) -> Result<()> {
  133. let ix = spl_token_2022::instruction::initialize_account(
  134. ctx.program.key,
  135. ctx.accounts.account.key,
  136. ctx.accounts.mint.key,
  137. ctx.accounts.authority.key,
  138. )?;
  139. solana_program::program::invoke(
  140. &ix,
  141. &[
  142. ctx.accounts.account,
  143. ctx.accounts.mint,
  144. ctx.accounts.authority,
  145. ctx.accounts.rent,
  146. ],
  147. )
  148. .map_err(Into::into)
  149. }
  150. pub fn initialize_account3<'info>(
  151. ctx: CpiContext<'_, '_, '_, 'info, InitializeAccount3<'info>>,
  152. ) -> Result<()> {
  153. let ix = spl_token_2022::instruction::initialize_account3(
  154. ctx.program.key,
  155. ctx.accounts.account.key,
  156. ctx.accounts.mint.key,
  157. ctx.accounts.authority.key,
  158. )?;
  159. solana_program::program::invoke(&ix, &[ctx.accounts.account, ctx.accounts.mint])
  160. .map_err(Into::into)
  161. }
  162. pub fn close_account<'info>(ctx: CpiContext<'_, '_, '_, 'info, CloseAccount<'info>>) -> Result<()> {
  163. let ix = spl_token_2022::instruction::close_account(
  164. ctx.program.key,
  165. ctx.accounts.account.key,
  166. ctx.accounts.destination.key,
  167. ctx.accounts.authority.key,
  168. &[], // TODO: support multisig
  169. )?;
  170. solana_program::program::invoke_signed(
  171. &ix,
  172. &[
  173. ctx.accounts.account,
  174. ctx.accounts.destination,
  175. ctx.accounts.authority,
  176. ],
  177. ctx.signer_seeds,
  178. )
  179. .map_err(Into::into)
  180. }
  181. pub fn freeze_account<'info>(
  182. ctx: CpiContext<'_, '_, '_, 'info, FreezeAccount<'info>>,
  183. ) -> Result<()> {
  184. let ix = spl_token_2022::instruction::freeze_account(
  185. ctx.program.key,
  186. ctx.accounts.account.key,
  187. ctx.accounts.mint.key,
  188. ctx.accounts.authority.key,
  189. &[], // TODO: Support multisig signers.
  190. )?;
  191. solana_program::program::invoke_signed(
  192. &ix,
  193. &[
  194. ctx.accounts.account,
  195. ctx.accounts.mint,
  196. ctx.accounts.authority,
  197. ],
  198. ctx.signer_seeds,
  199. )
  200. .map_err(Into::into)
  201. }
  202. pub fn thaw_account<'info>(ctx: CpiContext<'_, '_, '_, 'info, ThawAccount<'info>>) -> Result<()> {
  203. let ix = spl_token_2022::instruction::thaw_account(
  204. ctx.program.key,
  205. ctx.accounts.account.key,
  206. ctx.accounts.mint.key,
  207. ctx.accounts.authority.key,
  208. &[], // TODO: Support multisig signers.
  209. )?;
  210. solana_program::program::invoke_signed(
  211. &ix,
  212. &[
  213. ctx.accounts.account,
  214. ctx.accounts.mint,
  215. ctx.accounts.authority,
  216. ],
  217. ctx.signer_seeds,
  218. )
  219. .map_err(Into::into)
  220. }
  221. pub fn initialize_mint<'info>(
  222. ctx: CpiContext<'_, '_, '_, 'info, InitializeMint<'info>>,
  223. decimals: u8,
  224. authority: &Pubkey,
  225. freeze_authority: Option<&Pubkey>,
  226. ) -> Result<()> {
  227. let ix = spl_token_2022::instruction::initialize_mint(
  228. ctx.program.key,
  229. ctx.accounts.mint.key,
  230. authority,
  231. freeze_authority,
  232. decimals,
  233. )?;
  234. solana_program::program::invoke(&ix, &[ctx.accounts.mint, ctx.accounts.rent])
  235. .map_err(Into::into)
  236. }
  237. pub fn initialize_mint2<'info>(
  238. ctx: CpiContext<'_, '_, '_, 'info, InitializeMint2<'info>>,
  239. decimals: u8,
  240. authority: &Pubkey,
  241. freeze_authority: Option<&Pubkey>,
  242. ) -> Result<()> {
  243. let ix = spl_token_2022::instruction::initialize_mint2(
  244. ctx.program.key,
  245. ctx.accounts.mint.key,
  246. authority,
  247. freeze_authority,
  248. decimals,
  249. )?;
  250. solana_program::program::invoke(&ix, &[ctx.accounts.mint]).map_err(Into::into)
  251. }
  252. pub fn set_authority<'info>(
  253. ctx: CpiContext<'_, '_, '_, 'info, SetAuthority<'info>>,
  254. authority_type: spl_token_2022::instruction::AuthorityType,
  255. new_authority: Option<Pubkey>,
  256. ) -> Result<()> {
  257. let mut spl_new_authority: Option<&Pubkey> = None;
  258. if new_authority.is_some() {
  259. spl_new_authority = new_authority.as_ref()
  260. }
  261. let ix = spl_token_2022::instruction::set_authority(
  262. ctx.program.key,
  263. ctx.accounts.account_or_mint.key,
  264. spl_new_authority,
  265. authority_type,
  266. ctx.accounts.current_authority.key,
  267. &[], // TODO: Support multisig signers.
  268. )?;
  269. solana_program::program::invoke_signed(
  270. &ix,
  271. &[ctx.accounts.account_or_mint, ctx.accounts.current_authority],
  272. ctx.signer_seeds,
  273. )
  274. .map_err(Into::into)
  275. }
  276. pub fn sync_native<'info>(ctx: CpiContext<'_, '_, '_, 'info, SyncNative<'info>>) -> Result<()> {
  277. let ix = spl_token_2022::instruction::sync_native(ctx.program.key, ctx.accounts.account.key)?;
  278. solana_program::program::invoke(&ix, &[ctx.accounts.account]).map_err(Into::into)
  279. }
  280. pub fn get_account_data_size<'info>(
  281. ctx: CpiContext<'_, '_, '_, 'info, GetAccountDataSize<'info>>,
  282. extension_types: &[spl_token_2022::extension::ExtensionType],
  283. ) -> Result<u64> {
  284. let ix = spl_token_2022::instruction::get_account_data_size(
  285. ctx.program.key,
  286. ctx.accounts.mint.key,
  287. extension_types,
  288. )?;
  289. solana_program::program::invoke(&ix, &[ctx.accounts.mint])?;
  290. solana_program::program::get_return_data()
  291. .ok_or(solana_program::program_error::ProgramError::InvalidInstructionData)
  292. .and_then(|(key, data)| {
  293. if key != *ctx.program.key {
  294. Err(solana_program::program_error::ProgramError::IncorrectProgramId)
  295. } else {
  296. data.try_into().map(u64::from_le_bytes).map_err(|_| {
  297. solana_program::program_error::ProgramError::InvalidInstructionData
  298. })
  299. }
  300. })
  301. .map_err(Into::into)
  302. }
  303. pub fn initialize_mint_close_authority<'info>(
  304. ctx: CpiContext<'_, '_, '_, 'info, InitializeMintCloseAuthority<'info>>,
  305. close_authority: Option<&Pubkey>,
  306. ) -> Result<()> {
  307. let ix = spl_token_2022::instruction::initialize_mint_close_authority(
  308. ctx.program.key,
  309. ctx.accounts.mint.key,
  310. close_authority,
  311. )?;
  312. solana_program::program::invoke(&ix, &[ctx.accounts.mint]).map_err(Into::into)
  313. }
  314. pub fn initialize_immutable_owner<'info>(
  315. ctx: CpiContext<'_, '_, '_, 'info, InitializeImmutableOwner<'info>>,
  316. ) -> Result<()> {
  317. let ix = spl_token_2022::instruction::initialize_immutable_owner(
  318. ctx.program.key,
  319. ctx.accounts.account.key,
  320. )?;
  321. solana_program::program::invoke(&ix, &[ctx.accounts.account]).map_err(Into::into)
  322. }
  323. pub fn amount_to_ui_amount<'info>(
  324. ctx: CpiContext<'_, '_, '_, 'info, AmountToUiAmount<'info>>,
  325. amount: u64,
  326. ) -> Result<String> {
  327. let ix = spl_token_2022::instruction::amount_to_ui_amount(
  328. ctx.program.key,
  329. ctx.accounts.account.key,
  330. amount,
  331. )?;
  332. solana_program::program::invoke(&ix, &[ctx.accounts.account])?;
  333. solana_program::program::get_return_data()
  334. .ok_or(solana_program::program_error::ProgramError::InvalidInstructionData)
  335. .and_then(|(key, data)| {
  336. if key != *ctx.program.key {
  337. Err(solana_program::program_error::ProgramError::IncorrectProgramId)
  338. } else {
  339. String::from_utf8(data).map_err(|_| {
  340. solana_program::program_error::ProgramError::InvalidInstructionData
  341. })
  342. }
  343. })
  344. .map_err(Into::into)
  345. }
  346. pub fn ui_amount_to_amount<'info>(
  347. ctx: CpiContext<'_, '_, '_, 'info, UiAmountToAmount<'info>>,
  348. ui_amount: &str,
  349. ) -> Result<u64> {
  350. let ix = spl_token_2022::instruction::ui_amount_to_amount(
  351. ctx.program.key,
  352. ctx.accounts.account.key,
  353. ui_amount,
  354. )?;
  355. solana_program::program::invoke(&ix, &[ctx.accounts.account])?;
  356. solana_program::program::get_return_data()
  357. .ok_or(solana_program::program_error::ProgramError::InvalidInstructionData)
  358. .and_then(|(key, data)| {
  359. if key != *ctx.program.key {
  360. Err(solana_program::program_error::ProgramError::IncorrectProgramId)
  361. } else {
  362. data.try_into().map(u64::from_le_bytes).map_err(|_| {
  363. solana_program::program_error::ProgramError::InvalidInstructionData
  364. })
  365. }
  366. })
  367. .map_err(Into::into)
  368. }
  369. #[derive(Accounts)]
  370. pub struct Transfer<'info> {
  371. pub from: AccountInfo<'info>,
  372. pub to: AccountInfo<'info>,
  373. pub authority: AccountInfo<'info>,
  374. }
  375. #[derive(Accounts)]
  376. pub struct TransferChecked<'info> {
  377. pub from: AccountInfo<'info>,
  378. pub mint: AccountInfo<'info>,
  379. pub to: AccountInfo<'info>,
  380. pub authority: AccountInfo<'info>,
  381. }
  382. #[derive(Accounts)]
  383. pub struct MintTo<'info> {
  384. pub mint: AccountInfo<'info>,
  385. pub to: AccountInfo<'info>,
  386. pub authority: AccountInfo<'info>,
  387. }
  388. #[derive(Accounts)]
  389. pub struct Burn<'info> {
  390. pub mint: AccountInfo<'info>,
  391. pub from: AccountInfo<'info>,
  392. pub authority: AccountInfo<'info>,
  393. }
  394. #[derive(Accounts)]
  395. pub struct Approve<'info> {
  396. pub to: AccountInfo<'info>,
  397. pub delegate: AccountInfo<'info>,
  398. pub authority: AccountInfo<'info>,
  399. }
  400. #[derive(Accounts)]
  401. pub struct Revoke<'info> {
  402. pub source: AccountInfo<'info>,
  403. pub authority: AccountInfo<'info>,
  404. }
  405. #[derive(Accounts)]
  406. pub struct InitializeAccount<'info> {
  407. pub account: AccountInfo<'info>,
  408. pub mint: AccountInfo<'info>,
  409. pub authority: AccountInfo<'info>,
  410. pub rent: AccountInfo<'info>,
  411. }
  412. #[derive(Accounts)]
  413. pub struct InitializeAccount3<'info> {
  414. pub account: AccountInfo<'info>,
  415. pub mint: AccountInfo<'info>,
  416. pub authority: AccountInfo<'info>,
  417. }
  418. #[derive(Accounts)]
  419. pub struct CloseAccount<'info> {
  420. pub account: AccountInfo<'info>,
  421. pub destination: AccountInfo<'info>,
  422. pub authority: AccountInfo<'info>,
  423. }
  424. #[derive(Accounts)]
  425. pub struct FreezeAccount<'info> {
  426. pub account: AccountInfo<'info>,
  427. pub mint: AccountInfo<'info>,
  428. pub authority: AccountInfo<'info>,
  429. }
  430. #[derive(Accounts)]
  431. pub struct ThawAccount<'info> {
  432. pub account: AccountInfo<'info>,
  433. pub mint: AccountInfo<'info>,
  434. pub authority: AccountInfo<'info>,
  435. }
  436. #[derive(Accounts)]
  437. pub struct InitializeMint<'info> {
  438. pub mint: AccountInfo<'info>,
  439. pub rent: AccountInfo<'info>,
  440. }
  441. #[derive(Accounts)]
  442. pub struct InitializeMint2<'info> {
  443. pub mint: AccountInfo<'info>,
  444. }
  445. #[derive(Accounts)]
  446. pub struct SetAuthority<'info> {
  447. pub current_authority: AccountInfo<'info>,
  448. pub account_or_mint: AccountInfo<'info>,
  449. }
  450. #[derive(Accounts)]
  451. pub struct SyncNative<'info> {
  452. pub account: AccountInfo<'info>,
  453. }
  454. #[derive(Accounts)]
  455. pub struct GetAccountDataSize<'info> {
  456. pub mint: AccountInfo<'info>,
  457. }
  458. #[derive(Accounts)]
  459. pub struct InitializeMintCloseAuthority<'info> {
  460. pub mint: AccountInfo<'info>,
  461. }
  462. #[derive(Accounts)]
  463. pub struct InitializeImmutableOwner<'info> {
  464. pub account: AccountInfo<'info>,
  465. }
  466. #[derive(Accounts)]
  467. pub struct AmountToUiAmount<'info> {
  468. pub account: AccountInfo<'info>,
  469. }
  470. #[derive(Accounts)]
  471. pub struct UiAmountToAmount<'info> {
  472. pub account: AccountInfo<'info>,
  473. }
  474. #[derive(Clone)]
  475. pub struct Token2022;
  476. impl anchor_lang::Id for Token2022 {
  477. fn id() -> Pubkey {
  478. ID
  479. }
  480. }
  481. // Field parsers to save compute. All account validation is assumed to be done
  482. // outside of these methods.
  483. pub use crate::token::accessor;