transfer_checked.rs 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. use core::slice::from_raw_parts;
  2. use pinocchio::{
  3. account_info::AccountInfo,
  4. instruction::{AccountMeta, Instruction, Signer},
  5. program::invoke_signed,
  6. pubkey::Pubkey,
  7. ProgramResult,
  8. };
  9. use crate::{write_bytes, UNINIT_BYTE};
  10. /// Transfer Tokens from one Token Account to another.
  11. ///
  12. /// ### Accounts:
  13. /// 0. `[WRITE]` The source account.
  14. /// 1. `[]` The token mint.
  15. /// 2. `[WRITE]` The destination account.
  16. /// 3. `[SIGNER]` The source account's owner/delegate.
  17. pub struct TransferChecked<'a, 'b> {
  18. /// Sender account.
  19. pub from: &'a AccountInfo,
  20. /// Mint Account
  21. pub mint: &'a AccountInfo,
  22. /// Recipient account.
  23. pub to: &'a AccountInfo,
  24. /// Authority account.
  25. pub authority: &'a AccountInfo,
  26. /// Amount of micro-tokens to transfer.
  27. pub amount: u64,
  28. /// Decimal for the Token
  29. pub decimals: u8,
  30. /// Token Program
  31. pub token_program: &'b Pubkey,
  32. }
  33. impl TransferChecked<'_, '_> {
  34. #[inline(always)]
  35. pub fn invoke(&self) -> ProgramResult {
  36. self.invoke_signed(&[])
  37. }
  38. #[inline(always)]
  39. pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
  40. // account metadata
  41. let account_metas: [AccountMeta; 4] = [
  42. AccountMeta::writable(self.from.key()),
  43. AccountMeta::readonly(self.mint.key()),
  44. AccountMeta::writable(self.to.key()),
  45. AccountMeta::readonly_signer(self.authority.key()),
  46. ];
  47. // Instruction data layout:
  48. // - [0]: instruction discriminator (1 byte, u8)
  49. // - [1..9]: amount (8 bytes, u64)
  50. // - [9]: decimals (1 byte, u8)
  51. let mut instruction_data = [UNINIT_BYTE; 10];
  52. // Set discriminator as u8 at offset [0]
  53. write_bytes(&mut instruction_data, &[12]);
  54. // Set amount as u64 at offset [1..9]
  55. write_bytes(&mut instruction_data[1..9], &self.amount.to_le_bytes());
  56. // Set decimals as u8 at offset [9]
  57. write_bytes(&mut instruction_data[9..], &[self.decimals]);
  58. let instruction = Instruction {
  59. program_id: self.token_program,
  60. accounts: &account_metas,
  61. data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, 10) },
  62. };
  63. invoke_signed(
  64. &instruction,
  65. &[self.from, self.mint, self.to, self.authority],
  66. signers,
  67. )
  68. }
  69. }