use crate::constants::MAX_BIN_PER_POSITION;
use crate::errors::LBError;
use crate::math::weight_to_amounts::{to_amount_ask_side, to_amount_bid_side, to_amount_both_side};
use crate::ModifyLiquidity;
use anchor_lang::prelude::*;
#[derive(AnchorSerialize, AnchorDeserialize, Eq, PartialEq, Clone, Debug, Default)]
pub struct BinLiquidityDistributionByWeight {
pub bin_id: i32,
pub weight: u16,
}
#[derive(AnchorSerialize, AnchorDeserialize, Eq, PartialEq, Clone, Debug)]
pub struct LiquidityParameterByWeight {
pub amount_x: u64,
pub amount_y: u64,
pub active_id: i32,
pub max_active_bin_slippage: i32,
pub bin_liquidity_dist: Vec<BinLiquidityDistributionByWeight>,
}
impl LiquidityParameterByWeight {
fn bin_count(&self) -> u32 {
self.bin_liquidity_dist.len() as u32
}
pub fn validate<'a, 'info>(&'a self, active_id: i32) -> Result<()> {
let bin_count = self.bin_count();
require!(bin_count > 0, LBError::InvalidInput);
require!(
bin_count <= MAX_BIN_PER_POSITION as u32,
LBError::InvalidInput
);
let bin_shift = if active_id > self.active_id {
active_id - self.active_id
} else {
self.active_id - active_id
};
require!(
bin_shift <= self.max_active_bin_slippage.into(),
LBError::ExceededBinSlippageTolerance
);
for (i, val) in self.bin_liquidity_dist.iter().enumerate() {
require!(val.weight != 0, LBError::InvalidInput);
if i != 0 {
require!(
val.bin_id > self.bin_liquidity_dist[i - 1].bin_id,
LBError::InvalidInput
);
}
}
let first_bin_id = self.bin_liquidity_dist[0].bin_id;
let last_bin_id = self.bin_liquidity_dist[self.bin_liquidity_dist.len() - 1].bin_id;
if first_bin_id > active_id {
require!(self.amount_x != 0, LBError::InvalidInput);
}
if last_bin_id < active_id {
require!(self.amount_y != 0, LBError::InvalidInput);
}
Ok(())
}
pub fn to_amounts_into_bin<'a, 'info>(
&'a self,
active_id: i32,
bin_step: u16,
amount_x_in_active_bin: u64, amount_y_in_active_bin: u64, ) -> Result<Vec<(i32, u64, u64)>> {
if active_id > self.bin_liquidity_dist[self.bin_liquidity_dist.len() - 1].bin_id {
let amounts = to_amount_bid_side(
active_id,
self.amount_y,
&self
.bin_liquidity_dist
.iter()
.map(|x| (x.bin_id, x.weight))
.collect::<Vec<(i32, u16)>>(),
)?;
let amounts = amounts
.iter()
.map(|x| (x.0, 0, x.1))
.collect::<Vec<(i32, u64, u64)>>();
return Ok(amounts);
}
if active_id < self.bin_liquidity_dist[0].bin_id {
let amounts = to_amount_ask_side(
active_id,
self.amount_x,
bin_step,
&self
.bin_liquidity_dist
.iter()
.map(|x| (x.bin_id, x.weight))
.collect::<Vec<(i32, u16)>>(),
)?;
let amounts = amounts
.iter()
.map(|x| (x.0, x.1, 0))
.collect::<Vec<(i32, u64, u64)>>();
return Ok(amounts);
}
to_amount_both_side(
active_id,
bin_step,
amount_x_in_active_bin,
amount_y_in_active_bin,
self.amount_x,
self.amount_y,
&self
.bin_liquidity_dist
.iter()
.map(|x| (x.bin_id, x.weight))
.collect::<Vec<(i32, u16)>>(),
)
}
}
pub fn handle<'a, 'b, 'c, 'info>(
ctx: &Context<'a, 'b, 'c, 'info, ModifyLiquidity<'info>>,
liquidity_parameter: &LiquidityParameterByWeight,
) -> Result<()> {
Ok(())
}