token.rs 14 KB

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