clmm-common 0.1.39

Blockchain, Clmm for Solana
Documentation
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
}