token_2022.rs 15 KB

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