use borsh::BorshDeserialize;
use tabled::Tabled;
use crate::contract::state::clmmpools::Clmmpool;
use crate::math::{MAX_TICK, MIN_TICK};
#[derive(BorshDeserialize, Tabled, Copy, Clone, Default)]
pub struct Tick {
pub is_initialized: bool,
pub index: i32,
pub sqrt_price: u128,
pub liquidity_net: i128,
pub liquidity_gross: u128,
pub fee_growth_outside_a: u128,
pub fee_growth_outside_b: u128,
pub reward_growth_outside: TickRewarder,
}
#[derive(Copy, Clone, BorshDeserialize, Default, Debug, Eq, PartialEq)]
pub struct TickRewarder([u128; 3]);
impl std::fmt::Display for TickRewarder {
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!("{}. growth_outside:{}", i, e));
}
let res_str = res.join("\n");
write!(f, "{}", res_str)
}
}
impl Tick {
pub const LEN: usize = 1 + 4 + 16 + 16 + 16 + 16 + 16 + Clmmpool::REWARD_NUM * 16;
#[inline]
pub fn min(tick_spacing: u16) -> i32 {
MIN_TICK + MIN_TICK.abs() % tick_spacing as i32
}
#[inline]
pub fn max(tick_spacing: u16) -> i32 {
MAX_TICK - MAX_TICK % tick_spacing as i32
}
pub fn update(&mut self, tick: &Tick) {
self.is_initialized = tick.is_initialized;
self.index = tick.index;
self.sqrt_price = tick.sqrt_price;
self.liquidity_net = tick.liquidity_net;
self.liquidity_gross = tick.liquidity_gross;
self.fee_growth_outside_a = tick.fee_growth_outside_a;
self.fee_growth_outside_b = tick.fee_growth_outside_b;
}
pub fn get_fee_in_tick_range(
clmmpool: &Clmmpool,
tick_lower: Option<&Tick>,
tick_upper: Option<&Tick>,
tick_lower_index: i32,
tick_upper_index: i32,
) -> (u128, u128) {
let (fee_growth_below_a, fee_growth_below_b) = match tick_lower {
None => (clmmpool.fee_growth_global_a, clmmpool.fee_growth_global_b),
Some(tick_lower) => match clmmpool.current_tick_index < tick_lower_index {
true => (
clmmpool
.fee_growth_global_a
.wrapping_sub(tick_lower.fee_growth_outside_a),
clmmpool
.fee_growth_global_b
.wrapping_sub(tick_lower.fee_growth_outside_b),
),
false => (
tick_lower.fee_growth_outside_a,
tick_lower.fee_growth_outside_b,
),
},
};
let (fee_growth_above_a, fee_growth_above_b) = match tick_upper {
None => (0, 0),
Some(tick_upper) => match clmmpool.current_tick_index < tick_upper_index {
true => (
tick_upper.fee_growth_outside_a,
tick_upper.fee_growth_outside_b,
),
false => (
clmmpool
.fee_growth_global_a
.wrapping_sub(tick_upper.fee_growth_outside_a),
clmmpool
.fee_growth_global_b
.wrapping_sub(tick_upper.fee_growth_outside_b),
),
},
};
(
clmmpool
.fee_growth_global_a
.wrapping_sub(fee_growth_below_a)
.wrapping_sub(fee_growth_above_a),
clmmpool
.fee_growth_global_b
.wrapping_sub(fee_growth_below_b)
.wrapping_sub(fee_growth_above_b),
)
}
pub fn get_reward_in_tick_range(
clmmpool: &mut Clmmpool,
tick_lower: Option<&Tick>,
tick_upper: Option<&Tick>,
tick_lower_index: i32,
tick_upper_index: i32,
) -> ([u128; Clmmpool::REWARD_NUM]) {
let rewarder_infos = clmmpool.reward_infos.0.as_mut_slice();
let mut rewarder_growths_inside = [0; Clmmpool::REWARD_NUM];
for i in 0..Clmmpool::REWARD_NUM {
if !rewarder_infos[i].is_initialized() {
continue;
}
let rewarder_growths_below = match tick_lower {
None => rewarder_infos[i].growth_global,
Some(tick_lower) => match clmmpool.current_tick_index < tick_lower_index {
true => rewarder_infos[i]
.growth_global
.wrapping_sub(tick_lower.reward_growth_outside.0.as_slice()[i]),
false => tick_lower.reward_growth_outside.0.as_slice()[i],
},
};
let rewarder_growths_above = match tick_upper {
None => 0,
Some(tick_upper) => match clmmpool.current_tick_index < tick_upper_index {
true => tick_upper.reward_growth_outside.0.as_slice()[i],
false => rewarder_infos[i]
.growth_global
.wrapping_sub(tick_upper.reward_growth_outside.0.as_slice()[i]),
},
};
rewarder_growths_inside[i] = rewarder_infos[i]
.growth_global
.wrapping_sub(rewarder_growths_below)
.wrapping_sub(rewarder_growths_above);
}
rewarder_growths_inside
}
}