use solana_client::rpc_client::RpcClient;
use solana_program::instruction::{AccountMeta, Instruction};
use solana_program::pubkey::Pubkey;
use spl_associated_token_account::get_associated_token_address;
use crate::program::{SWAP_PROGRAM_ID};
use crate::utils::sighash;
use crate::command::CliConfig;
use crate::contract::instructions::tick::get_tick_info;
use crate::contract::state::{Clmmpool, TickArray};
use crate::contract::state::position::Position;
use crate::contract::state::tick::Tick;
pub fn new_collect_fee(
clmmpool: &Pubkey,
position: &Pubkey,
position_ata: &Pubkey,
token_a_ata: &Pubkey,
token_b_ata: &Pubkey,
token_a_vault: &Pubkey,
token_b_vault: &Pubkey,
tick_array_lower: &Pubkey,
tick_array_upper: &Pubkey,
payer: Pubkey,
) -> Instruction {
let distor = sighash::sighash("global", "collect_fee").to_vec();
Instruction {
program_id: SWAP_PROGRAM_ID,
accounts: vec![
AccountMeta::new(payer, true),
AccountMeta::new_readonly(*clmmpool, false),
AccountMeta::new(*position, false),
AccountMeta::new_readonly(*position_ata, false),
AccountMeta::new(*token_a_ata, false),
AccountMeta::new(*token_b_ata, false),
AccountMeta::new(*token_a_vault, false),
AccountMeta::new(*token_b_vault, false),
AccountMeta::new_readonly(*tick_array_lower, false),
AccountMeta::new_readonly(*tick_array_upper, false),
AccountMeta::new_readonly(spl_token::id(), false),
],
data: distor,
}
}
pub fn new_collect_fee_tx(
rpc_client: &RpcClient,
config: &CliConfig,
mint: &Pubkey,
) -> Option<Instruction> {
let (position, _) = Pubkey::find_program_address(
&[b"position", mint.as_ref()],
&SWAP_PROGRAM_ID,
);
let mut position_info = Position::get_info(rpc_client, &position);
let clmmpool_info = Clmmpool::get_info(rpc_client, &position_info.clmmpool);
let position_ata =
get_associated_token_address(&config.pubkey().unwrap(), &position_info.position_nft_mint);
let token_a_ata =
get_associated_token_address(&config.pubkey().unwrap(), &clmmpool_info.token_a);
let token_b_ata =
get_associated_token_address(&config.pubkey().unwrap(), &clmmpool_info.token_b);
let array_lower_index =
TickArray::array_index(position_info.tick_lower_index, clmmpool_info.tick_spacing).unwrap();
let (tick_array_lower_pubkey, _) = TickArray::calculate_tick_array_key(
position_info.clmmpool.as_ref(),
array_lower_index.to_le_bytes().as_ref(),
);
let array_upper_index =
TickArray::array_index(position_info.tick_upper_index, clmmpool_info.tick_spacing).unwrap();
let (tick_array_upper_pubkey, _) = TickArray::calculate_tick_array_key(
position_info.clmmpool.as_ref(),
array_upper_index.to_le_bytes().as_ref(),
);
let tick_lower = get_tick_info(rpc_client, position_info.tick_lower_index, &position_info.clmmpool);
let tick_upper = get_tick_info(rpc_client, position_info.tick_upper_index, &position_info.clmmpool);
let (fee_growth_inside_a, fee_growth_inside_b) = Tick::get_fee_in_tick_range(&clmmpool_info, Some(&tick_lower), Some(&tick_upper), position_info.tick_lower_index, position_info.tick_upper_index);
position_info.update_fee(fee_growth_inside_a, fee_growth_inside_b);
if position_info.fee_owed_a == 0 && position_info.fee_owed_b == 0 {
return None;
}
Some(new_collect_fee(
&position_info.clmmpool,
&position,
&position_ata,
&token_a_ata,
&token_b_ata,
&clmmpool_info.token_a_vault,
&clmmpool_info.token_b_vault,
&tick_array_lower_pubkey,
&tick_array_upper_pubkey,
config.pubkey().unwrap(),
))
}