token.rs 10 KB

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