pinocchio_token/instructions/
transfer_checked.rs

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