clmm-common 0.1.39

Blockchain, Clmm for Solana
Documentation
use std::vec;

use crate::{program::SWAP_PROGRAM_ID, utils::sqrt_price::SqrtPrice};
use borsh::BorshDeserialize;
use solana_client::rpc_client::RpcClient;
use solana_sdk::pubkey::Pubkey;
use tabled::Tabled;

use super::config::ClmmConfig;

#[derive(BorshDeserialize, Tabled, Copy, Clone, Debug)]
pub struct Clmmpool {
    /// clmm_config
    pub clmm_config: Pubkey,
    /// The pool token a mint address.
    pub token_a: Pubkey,
    /// The pool token b mint address.
    pub token_b: Pubkey,

    /// The vault for hold clmmpool's token a.
    pub token_a_vault: Pubkey,
    /// The vault for hold clmmpool's token b.
    pub token_b_vault: Pubkey,

    /// The tick spacing.
    pub tick_spacing: u16,

    pub tick_spacing_seed: u16,

    /// The numerator of fee rate, the denominator is 1_000_000.
    pub fee_rate: u16,
    /// The numerator of protocol fee rate, the denominator is 1_000_0.

    /// The liquidity of current tick index.
    pub liquidity: u128,

    /// The current sqrt price, Q64.64 and MAX/MIN is Q32.64.
    pub current_sqrt_price: u128,
    /// The current tick index.
    pub current_tick_index: i32,

    /// The fee growth a as Q64.64.
    pub fee_growth_global_a: u128,
    /// The fee growth b as Q64.64.
    pub fee_growth_global_b: u128,

    /// The amounts of token a owed to protocol.
    pub fee_protocol_token_a: u64,
    /// The amounts of token b owed to protocol.
    pub fee_protocol_token_b: u64,

    /// The bump
    pub bump: u8,

    pub reward_infos: Rewarders,
    pub reward_last_updated_time: u64, // 8

    pub is_pause: bool,
}

#[derive(Copy, Clone, BorshDeserialize, Default, Debug, Eq, PartialEq)]
pub struct Rewarder {
    pub mint_wrapper: Pubkey,
    pub minter: Pubkey,
    /// Reward token mint.
    pub mint: Pubkey,
    /// Authority account that has permission to initialize the reward and set emissions.
    pub authority: Pubkey,
    /// Q64.64 number that indicates how many tokens per second are earned per unit of liquidity.
    pub emissions_per_second: u128,
    /// Q64.64 number that tracks the total tokens earned per unit of liquidity since the reward
    /// emissions were turned on.
    pub growth_global: u128,
}

impl Rewarder {
    pub const LEN: usize = 32 + 32 + 32 + 32 + 16 + 16;

    pub fn is_initialized(&self) -> bool {
        self.mint.ne(&Pubkey::default())
    }
}

#[derive(Copy, Clone, BorshDeserialize, Default, Debug, PartialEq)]
pub struct Rewarders(pub [Rewarder; 3]);

impl std::fmt::Display for Rewarders {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let mut res: Vec<String> = vec![];
        for (i, e) in self.0.iter().enumerate() {
            res.push(format!("{}. minter_wrapper: {:?} |", i, e.mint_wrapper));
            res.push(format!("minter: {:?} |", e.minter));
            res.push(format!("mint: {:?} |\n", e.mint));
            res.push(format!("authority: {:?} |", e.authority));
            res.push(format!(
                "emissions_per_second: {:?} |",
                e.emissions_per_second
            ));
            res.push(format!("growth_global: {:?} |\n", e.growth_global));
            res.push("\n".to_string());
        }
        let res_str = res.join("");
        write!(f, "{}", res_str)
    }
}

impl Clmmpool {
    pub const REWARD_NUM: usize = 3;
    pub const LEN: usize = 5 * 32
        + 3 * 2
        + 2 * 16
        + 4
        + 2 * 16
        + 2 * 8
        + 1
        + Clmmpool::REWARD_NUM * Rewarder::LEN
        + 8
        + 1;

    pub fn find_address(token_a: &Pubkey, token_b: &Pubkey, tick_spacing: u16) -> Pubkey {
        let clmm_config = ClmmConfig::find_address();
        let (clmmpool_pubkey, _) = if token_a.lt(&token_b) {
            Pubkey::find_program_address(
                &[
                    b"clmmpool",
                    clmm_config.as_ref(),
                    token_a.as_ref(),
                    token_b.as_ref(),
                    tick_spacing.to_le_bytes().as_ref(),
                ],
                &SWAP_PROGRAM_ID,
            )
        } else {
            Pubkey::find_program_address(
                &[
                    b"clmmpool",
                    clmm_config.as_ref(),
                    token_b.as_ref(),
                    token_a.as_ref(),
                    tick_spacing.to_le_bytes().as_ref(),
                ],
                &SWAP_PROGRAM_ID,
            )
        };
        clmmpool_pubkey
    }

    pub fn get_info(rpc_client: &RpcClient, pubkey: &Pubkey) -> Self {
        let data_slice = &rpc_client.get_account_data(pubkey).unwrap()[8..];
        Clmmpool::try_from_slice(data_slice).unwrap()
    }

    pub fn get_tick_map_address(pool: &Pubkey, program_id: Pubkey) -> Pubkey {
        let (expect_address, _) =
            Pubkey::find_program_address(&[b"tick_array_map", pool.as_ref()], &program_id);
        expect_address
    }

    pub fn ui_list(self, clmmpool: Pubkey) -> ClmmpoolUiList {
        ClmmpoolUiList {
            name: String::from(""),
            clmmpool,
            token_a: self.token_a,
            token_b: self.token_b,
            tick_spacing: self.tick_spacing,
            current_sqrt_price: SqrtPrice::new(self.current_sqrt_price),
            current_tick_index: self.current_tick_index,
            liquidity: self.liquidity,
        }
    }

    pub fn ui(self) -> ClmmpoolUiDetail {
        ClmmpoolUiDetail {
            name: String::from(""),
            clmm_config: self.clmm_config,
            token_a: self.token_a,
            token_b: self.token_b,

            token_a_vault: self.token_a_vault,
            token_b_vault: self.token_b_vault,
            tick_spacing: self.tick_spacing,
            tick_spacing_seed: self.tick_spacing_seed,
            fee_rate: self.fee_rate,
            liquidity: self.liquidity,
            current_sqrt_price: self.current_sqrt_price,
            current_tick_index: self.current_tick_index,
            fee_growth_global_a: self.fee_growth_global_a,
            fee_growth_global_b: self.fee_growth_global_b,
            fee_protocol_token_a: self.fee_protocol_token_a,
            fee_protocol_token_b: self.fee_protocol_token_b,
            bump: self.bump,
            reward_last_updated_time: self.reward_last_updated_time,
            is_pause: self.is_pause,
            amount_a: 0f64,
            amount_b: 0f64,
        }
    }
}

#[derive(Tabled)]
pub struct ClmmpoolUiList {
    pub name: String,
    pub clmmpool: Pubkey,
    pub token_a: Pubkey,
    pub token_b: Pubkey,
    pub tick_spacing: u16,
    pub current_sqrt_price: SqrtPrice,
    pub current_tick_index: i32,
    pub liquidity: u128,
}

#[derive(Tabled)]
pub struct ClmmpoolUiDetail {
    pub name: String,
    pub clmm_config: Pubkey,
    pub token_a: Pubkey,
    pub token_b: Pubkey,
    pub token_a_vault: Pubkey,
    pub token_b_vault: Pubkey,
    pub tick_spacing: u16,
    pub tick_spacing_seed: u16,
    pub fee_rate: u16,
    pub liquidity: u128,
    pub current_sqrt_price: u128,
    pub current_tick_index: i32,
    pub fee_growth_global_a: u128,
    pub fee_growth_global_b: u128,
    pub fee_protocol_token_a: u64,
    pub fee_protocol_token_b: u64,
    pub bump: u8,
    pub reward_last_updated_time: u64, // 8
    pub is_pause: bool,
    pub amount_a: f64,
    pub amount_b: f64,
}