token.rs 13 KB

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