token.rs 11 KB

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