use borsh::BorshSerialize;
use light_token_interface::LIGHT_TOKEN_PROGRAM_ID;
use light_token_types::{
instruction::delegation::CompressedTokenInstructionDataApprove, ValidityProof,
};
use solana_instruction::Instruction;
use solana_pubkey::Pubkey;
use super::account_metas::{get_approve_instruction_account_metas, ApproveMetaConfig};
use crate::{
compressed_token::v1::CTokenAccount,
error::{Result, TokenSdkError},
};
#[derive(Debug, Clone)]
pub struct ApproveInputs {
pub fee_payer: Pubkey,
pub authority: Pubkey,
pub sender_account: CTokenAccount,
pub validity_proof: ValidityProof,
pub delegate: Pubkey,
pub delegated_amount: u64,
pub delegate_lamports: Option<u64>,
pub delegated_compressed_account_merkle_tree: Pubkey,
pub change_compressed_account_merkle_tree: Pubkey,
}
pub fn create_approve_instruction(inputs: ApproveInputs) -> Result<Instruction> {
let mint = *inputs.sender_account.mint();
let (input_token_data, _) = inputs.sender_account.into_inputs_and_outputs();
if input_token_data.is_empty() {
return Err(TokenSdkError::InsufficientBalance);
}
let total_input_amount: u64 = input_token_data.iter().map(|data| data.amount).sum();
if total_input_amount < inputs.delegated_amount {
return Err(TokenSdkError::InsufficientBalance);
}
let input_token_data_with_context = input_token_data;
let instruction_data = CompressedTokenInstructionDataApprove {
proof: inputs.validity_proof.0.unwrap(),
mint: mint.to_bytes(),
input_token_data_with_context,
cpi_context: None,
delegate: inputs.delegate.to_bytes(),
delegated_amount: inputs.delegated_amount,
delegate_merkle_tree_index: 0, change_account_merkle_tree_index: 1, delegate_lamports: inputs.delegate_lamports,
};
let serialized_data = instruction_data
.try_to_vec()
.map_err(|_| TokenSdkError::SerializationError)?;
let meta_config = ApproveMetaConfig::new(
inputs.fee_payer,
inputs.authority,
inputs.delegated_compressed_account_merkle_tree,
inputs.change_compressed_account_merkle_tree,
);
let account_metas = get_approve_instruction_account_metas(meta_config);
Ok(Instruction {
program_id: Pubkey::new_from_array(LIGHT_TOKEN_PROGRAM_ID),
accounts: account_metas,
data: serialized_data,
})
}
pub fn approve(inputs: ApproveInputs) -> Result<Instruction> {
create_approve_instruction(inputs)
}