pinocchio_token/instructions/
transfer_checked.rs

1use core::slice::from_raw_parts;
2
3use pinocchio::{
4    account_info::AccountInfo,
5    instruction::{AccountMeta, Instruction, Signer},
6    program::invoke_signed,
7    ProgramResult,
8};
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 AccountInfo,
22    /// Mint Account
23    pub mint: &'a AccountInfo,
24    /// Recipient account.
25    pub to: &'a AccountInfo,
26    /// Authority account.
27    pub authority: &'a AccountInfo,
28    /// Amount of microtokens 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    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
41        // account metadata
42        let account_metas: [AccountMeta; 4] = [
43            AccountMeta::writable(self.from.key()),
44            AccountMeta::readonly(self.mint.key()),
45            AccountMeta::writable(self.to.key()),
46            AccountMeta::readonly_signer(self.authority.key()),
47        ];
48
49        // Instruction data layout:
50        // -  [0]: instruction discriminator (1 byte, u8)
51        // -  [1..9]: amount (8 bytes, u64)
52        // -  [9]: decimals (1 byte, u8)
53        let mut instruction_data = [UNINIT_BYTE; 10];
54
55        // Set discriminator as u8 at offset [0]
56        write_bytes(&mut instruction_data, &[12]);
57        // Set amount as u64 at offset [1..9]
58        write_bytes(&mut instruction_data[1..9], &self.amount.to_le_bytes());
59        // Set decimals as u8 at offset [9]
60        write_bytes(&mut instruction_data[9..], &[self.decimals]);
61
62        let instruction = Instruction {
63            program_id: &crate::ID,
64            accounts: &account_metas,
65            data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, 10) },
66        };
67
68        invoke_signed(
69            &instruction,
70            &[self.from, self.mint, self.to, self.authority],
71            signers,
72        )
73    }
74}