token.rs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  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::{Accounts, CpiContext};
  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. ctx.program.clone(),
  29. ],
  30. ctx.signer_seeds,
  31. )
  32. }
  33. pub fn mint_to<'a, 'b, 'c, 'info>(
  34. ctx: CpiContext<'a, 'b, 'c, 'info, MintTo<'info>>,
  35. amount: u64,
  36. ) -> ProgramResult {
  37. let ix = spl_token::instruction::mint_to(
  38. &spl_token::ID,
  39. ctx.accounts.mint.key,
  40. ctx.accounts.to.key,
  41. ctx.accounts.authority.key,
  42. &[],
  43. amount,
  44. )?;
  45. solana_program::program::invoke_signed(
  46. &ix,
  47. &[
  48. ctx.accounts.to.clone(),
  49. ctx.accounts.mint.clone(),
  50. ctx.accounts.authority.clone(),
  51. ctx.program.clone(),
  52. ],
  53. ctx.signer_seeds,
  54. )
  55. }
  56. pub fn burn<'a, 'b, 'c, 'info>(
  57. ctx: CpiContext<'a, 'b, 'c, 'info, Burn<'info>>,
  58. amount: u64,
  59. ) -> ProgramResult {
  60. let ix = spl_token::instruction::burn(
  61. &spl_token::ID,
  62. ctx.accounts.to.key,
  63. ctx.accounts.mint.key,
  64. ctx.accounts.authority.key,
  65. &[],
  66. amount,
  67. )?;
  68. solana_program::program::invoke_signed(
  69. &ix,
  70. &[
  71. ctx.accounts.to.clone(),
  72. ctx.accounts.mint.clone(),
  73. ctx.accounts.authority.clone(),
  74. ctx.program.clone(),
  75. ],
  76. ctx.signer_seeds,
  77. )
  78. }
  79. pub fn approve<'a, 'b, 'c, 'info>(
  80. ctx: CpiContext<'a, 'b, 'c, 'info, Approve<'info>>,
  81. amount: u64,
  82. ) -> ProgramResult {
  83. let ix = spl_token::instruction::approve(
  84. &spl_token::ID,
  85. ctx.accounts.to.key,
  86. ctx.accounts.delegate.key,
  87. ctx.accounts.authority.key,
  88. &[],
  89. amount,
  90. )?;
  91. solana_program::program::invoke_signed(
  92. &ix,
  93. &[
  94. ctx.accounts.to.clone(),
  95. ctx.accounts.delegate.clone(),
  96. ctx.accounts.authority.clone(),
  97. ctx.program.clone(),
  98. ],
  99. ctx.signer_seeds,
  100. )
  101. }
  102. pub fn initialize_account<'a, 'b, 'c, 'info>(
  103. ctx: CpiContext<'a, 'b, 'c, 'info, InitializeAccount<'info>>,
  104. ) -> ProgramResult {
  105. let ix = spl_token::instruction::initialize_account(
  106. &spl_token::ID,
  107. ctx.accounts.account.key,
  108. ctx.accounts.mint.key,
  109. ctx.accounts.authority.key,
  110. )?;
  111. solana_program::program::invoke_signed(
  112. &ix,
  113. &[
  114. ctx.accounts.account.clone(),
  115. ctx.accounts.mint.clone(),
  116. ctx.accounts.authority.clone(),
  117. ctx.accounts.rent.clone(),
  118. ctx.program.clone(),
  119. ],
  120. ctx.signer_seeds,
  121. )
  122. }
  123. pub fn initialize_mint<'a, 'b, 'c, 'info>(
  124. ctx: CpiContext<'a, 'b, 'c, 'info, InitializeMint<'info>>,
  125. decimals: u8,
  126. authority: &Pubkey,
  127. freeze_authority: Option<&Pubkey>,
  128. ) -> ProgramResult {
  129. let ix = spl_token::instruction::initialize_mint(
  130. &spl_token::ID,
  131. ctx.accounts.mint.key,
  132. authority,
  133. freeze_authority,
  134. decimals,
  135. )?;
  136. solana_program::program::invoke_signed(
  137. &ix,
  138. &[
  139. ctx.accounts.mint.clone(),
  140. ctx.accounts.rent.clone(),
  141. ctx.program.clone(),
  142. ],
  143. ctx.signer_seeds,
  144. )
  145. }
  146. pub fn set_authority<'a, 'b, 'c, 'info>(
  147. ctx: CpiContext<'a, 'b, 'c, 'info, SetAuthority<'info>>,
  148. authority_type: spl_token::instruction::AuthorityType,
  149. new_authority: Option<Pubkey>,
  150. ) -> ProgramResult {
  151. let mut spl_new_authority: Option<&Pubkey> = None;
  152. if new_authority.is_some() {
  153. spl_new_authority = new_authority.as_ref()
  154. }
  155. let ix = spl_token::instruction::set_authority(
  156. &spl_token::ID,
  157. ctx.accounts.account_or_mint.key,
  158. spl_new_authority,
  159. authority_type,
  160. ctx.accounts.current_authority.key,
  161. &[], // TODO: Support multisig signers.
  162. )?;
  163. solana_program::program::invoke_signed(
  164. &ix,
  165. &[
  166. ctx.accounts.account_or_mint.clone(),
  167. ctx.accounts.current_authority.clone(),
  168. ctx.program.clone(),
  169. ],
  170. ctx.signer_seeds,
  171. )
  172. }
  173. #[derive(Accounts)]
  174. pub struct Transfer<'info> {
  175. pub from: AccountInfo<'info>,
  176. pub to: AccountInfo<'info>,
  177. pub authority: AccountInfo<'info>,
  178. }
  179. #[derive(Accounts)]
  180. pub struct MintTo<'info> {
  181. pub mint: AccountInfo<'info>,
  182. pub to: AccountInfo<'info>,
  183. pub authority: AccountInfo<'info>,
  184. }
  185. #[derive(Accounts)]
  186. pub struct Burn<'info> {
  187. pub mint: AccountInfo<'info>,
  188. pub to: AccountInfo<'info>,
  189. pub authority: AccountInfo<'info>,
  190. }
  191. #[derive(Accounts)]
  192. pub struct Approve<'info> {
  193. pub to: AccountInfo<'info>,
  194. pub delegate: AccountInfo<'info>,
  195. pub authority: AccountInfo<'info>,
  196. }
  197. #[derive(Accounts)]
  198. pub struct InitializeAccount<'info> {
  199. pub account: AccountInfo<'info>,
  200. pub mint: AccountInfo<'info>,
  201. pub authority: AccountInfo<'info>,
  202. pub rent: AccountInfo<'info>,
  203. }
  204. #[derive(Accounts)]
  205. pub struct InitializeMint<'info> {
  206. pub mint: AccountInfo<'info>,
  207. pub rent: AccountInfo<'info>,
  208. }
  209. #[derive(Accounts)]
  210. pub struct SetAuthority<'info> {
  211. pub current_authority: AccountInfo<'info>,
  212. pub account_or_mint: AccountInfo<'info>,
  213. }
  214. #[derive(Clone)]
  215. pub struct TokenAccount(spl_token::state::Account);
  216. impl TokenAccount {
  217. pub const LEN: usize = spl_token::state::Account::LEN;
  218. }
  219. impl anchor_lang::AccountDeserialize for TokenAccount {
  220. fn try_deserialize(buf: &mut &[u8]) -> Result<Self, ProgramError> {
  221. TokenAccount::try_deserialize_unchecked(buf)
  222. }
  223. fn try_deserialize_unchecked(buf: &mut &[u8]) -> Result<Self, ProgramError> {
  224. spl_token::state::Account::unpack(buf).map(TokenAccount)
  225. }
  226. }
  227. impl Deref for TokenAccount {
  228. type Target = spl_token::state::Account;
  229. fn deref(&self) -> &Self::Target {
  230. &self.0
  231. }
  232. }
  233. #[derive(Clone)]
  234. pub struct Mint(spl_token::state::Mint);
  235. impl anchor_lang::AccountDeserialize for Mint {
  236. fn try_deserialize(buf: &mut &[u8]) -> Result<Self, ProgramError> {
  237. Mint::try_deserialize_unchecked(buf)
  238. }
  239. fn try_deserialize_unchecked(buf: &mut &[u8]) -> Result<Self, ProgramError> {
  240. spl_token::state::Mint::unpack(buf).map(Mint)
  241. }
  242. }
  243. impl Deref for Mint {
  244. type Target = spl_token::state::Mint;
  245. fn deref(&self) -> &Self::Target {
  246. &self.0
  247. }
  248. }
  249. // Field parsers to save compute. All account validation is assumed to be done
  250. // outside of these methods.
  251. pub mod accessor {
  252. use super::*;
  253. pub fn amount(account: &AccountInfo) -> Result<u64, ProgramError> {
  254. let bytes = account.try_borrow_data()?;
  255. let mut amount_bytes = [0u8; 8];
  256. amount_bytes.copy_from_slice(&bytes[64..72]);
  257. Ok(u64::from_le_bytes(amount_bytes))
  258. }
  259. pub fn mint(account: &AccountInfo) -> Result<Pubkey, ProgramError> {
  260. let bytes = account.try_borrow_data()?;
  261. let mut mint_bytes = [0u8; 32];
  262. mint_bytes.copy_from_slice(&bytes[..32]);
  263. Ok(Pubkey::new_from_array(mint_bytes))
  264. }
  265. pub fn authority(account: &AccountInfo) -> Result<Pubkey, ProgramError> {
  266. let bytes = account.try_borrow_data()?;
  267. let mut owner_bytes = [0u8; 32];
  268. owner_bytes.copy_from_slice(&bytes[32..64]);
  269. Ok(Pubkey::new_from_array(owner_bytes))
  270. }
  271. }