use light_sdk_types::LIGHT_TOKEN_PROGRAM_ID;
use solana_account_info::AccountInfo;
use solana_cpi::{invoke, invoke_signed};
use solana_instruction::{AccountMeta, Instruction};
use solana_program_error::ProgramError;
use solana_pubkey::Pubkey;
pub struct Transfer {
pub source: Pubkey,
pub destination: Pubkey,
pub amount: u64,
pub authority: Pubkey,
pub fee_payer: Pubkey,
}
pub struct TransferCpi<'info> {
pub source: AccountInfo<'info>,
pub destination: AccountInfo<'info>,
pub amount: u64,
pub authority: AccountInfo<'info>,
pub system_program: AccountInfo<'info>,
pub fee_payer: AccountInfo<'info>,
}
impl<'info> TransferCpi<'info> {
pub fn instruction(&self) -> Result<Instruction, ProgramError> {
Transfer::from(self).instruction()
}
pub fn invoke(self) -> Result<(), ProgramError> {
let instruction = Transfer::from(&self).instruction()?;
let account_infos = [
self.source,
self.destination,
self.authority,
self.system_program,
self.fee_payer,
];
invoke(&instruction, &account_infos)
}
pub fn invoke_signed(self, signer_seeds: &[&[&[u8]]]) -> Result<(), ProgramError> {
let instruction = Transfer::from(&self).instruction()?;
let account_infos = [
self.source,
self.destination,
self.authority,
self.system_program,
self.fee_payer,
];
invoke_signed(&instruction, &account_infos, signer_seeds)
}
}
impl<'info> From<&TransferCpi<'info>> for Transfer {
fn from(account_infos: &TransferCpi<'info>) -> Self {
Self {
source: *account_infos.source.key,
destination: *account_infos.destination.key,
amount: account_infos.amount,
authority: *account_infos.authority.key,
fee_payer: *account_infos.fee_payer.key,
}
}
}
impl_with_top_up!(Transfer, TransferWithTopUp);
impl Transfer {
fn build_instruction(self, max_top_up: Option<u16>) -> Result<Instruction, ProgramError> {
let accounts = vec![
AccountMeta::new(self.source, false),
AccountMeta::new(self.destination, false),
AccountMeta::new_readonly(self.authority, true),
AccountMeta::new_readonly(Pubkey::default(), false),
AccountMeta::new(self.fee_payer, true),
];
let mut data = vec![3u8];
data.extend_from_slice(&self.amount.to_le_bytes());
if let Some(max_top_up) = max_top_up {
data.extend_from_slice(&max_top_up.to_le_bytes());
}
Ok(Instruction {
program_id: Pubkey::from(LIGHT_TOKEN_PROGRAM_ID),
accounts,
data,
})
}
}