token.rs 10 KB

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