use crate::command::CliConfig;
use crate::contract::instructions::tick::get_tick_info;
use crate::contract::state::position::Position;
use crate::contract::state::tick::Tick;
use crate::contract::state::{Clmmpool, TickArray};
use crate::program::{MINT_WRAPPER_PROGRAM_ID, SWAP_PROGRAM_ID};
use crate::utils::sighash;
use borsh::{BorshDeserialize, BorshSerialize};
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 spl_associated_token_account::instruction::create_associated_token_account;
#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)]
pub struct CollectRewarderArgs {
pub rewarder_index: u8,
}
#[allow(clippy::too_many_arguments)]
pub fn new_collect_rewarder(
clmmpool: Pubkey,
position: Pubkey,
position_ata: Pubkey,
rewarder_ata: Pubkey,
mint_wrapper: Pubkey,
minter: Pubkey,
rewarder_token_mint: Pubkey,
tick_array_lower: Pubkey,
tick_array_upper: Pubkey,
rewarder_index: u8,
payer: Pubkey,
) -> Instruction {
let data = &CollectRewarderArgs { rewarder_index };
let mut dsa = data.try_to_vec().unwrap();
let mut distor = sighash::sighash("global", "collect_rewarder").to_vec();
distor.append(&mut dsa);
Instruction {
program_id: SWAP_PROGRAM_ID,
accounts: vec![
AccountMeta::new_readonly(payer, true),
AccountMeta::new(clmmpool, false),
AccountMeta::new(position, false),
AccountMeta::new_readonly(position_ata, false),
AccountMeta::new(rewarder_ata, false),
AccountMeta::new(mint_wrapper, false),
AccountMeta::new(minter, false),
AccountMeta::new_readonly(MINT_WRAPPER_PROGRAM_ID, false),
AccountMeta::new(rewarder_token_mint, 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_rewarder_tx(
rpc_client: &RpcClient,
config: &CliConfig,
mint: Pubkey,
rewarder_index: u8,
) -> Vec<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 mut 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 reward = clmmpool_info.reward_infos.0.as_slice()[rewarder_index as usize];
let rewarder_ata = get_associated_token_address(&config.pubkey().unwrap(), &reward.mint);
let mut ixs = vec![];
if rpc_client.get_account(&rewarder_ata).is_err() {
ixs.push(create_associated_token_account(
&config.pubkey().unwrap(),
&config.pubkey().unwrap(),
&reward.mint,
&spl_token::id(),
));
}
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 rewards = Tick::get_reward_in_tick_range(
&mut clmmpool_info,
Some(&tick_lower),
Some(&tick_upper),
position_info.tick_lower_index,
position_info.tick_upper_index,
);
position_info.update_rewarder(&rewards);
if position_info.reward_infos.0.as_slice()[rewarder_index as usize].amount_owed == 0 {
return vec![];
}
ixs.push(new_collect_rewarder(
position_info.clmmpool,
position,
position_ata,
rewarder_ata,
reward.mint_wrapper,
reward.minter,
reward.mint,
tick_array_lower_pubkey,
tick_array_upper_pubkey,
rewarder_index,
config.pubkey().unwrap(),
));
ixs
}