use crate::{write_bytes, UNINIT_BYTE};
use core::slice::from_raw_parts;
use hayabusa_cpi::{CpiCtx, CheckProgramId};
use hayabusa_errors::Result;
use pinocchio::{account_info::AccountInfo, cpi::{invoke, invoke_signed}, instruction::{AccountMeta, Instruction}, pubkey::Pubkey};
pub struct Transfer<'a> {
pub from: &'a AccountInfo,
pub to: &'a AccountInfo,
pub authority: &'a AccountInfo,
}
impl CheckProgramId for Transfer<'_> {
const ID: Pubkey = crate::ID;
}
const DISCRIMINATOR: [u8; 1] = [3];
#[inline(always)]
pub fn transfer<'a>(
cpi_ctx: CpiCtx<'a, '_, '_, '_, Transfer<'a>>,
amount: u64,
) -> Result<()> {
let infos = [
cpi_ctx.from,
cpi_ctx.to,
cpi_ctx.authority,
];
let metas = [
AccountMeta::writable(cpi_ctx.from.key()),
AccountMeta::writable(cpi_ctx.to.key()),
AccountMeta::readonly_signer(cpi_ctx.authority.key()),
];
let mut ix_data = [UNINIT_BYTE; 9];
write_bytes(&mut ix_data, &DISCRIMINATOR);
write_bytes(&mut ix_data[1..9], &amount.to_le_bytes());
let instruction = Instruction {
program_id: &crate::ID,
accounts: &metas,
data: unsafe { from_raw_parts(ix_data.as_ptr() as _, 9) },
};
if let Some(signers) = cpi_ctx.signers {
invoke_signed(&instruction, &infos, signers)
} else {
invoke(&instruction, &infos)
}
}