diff --git a/programs/cp-amm/src/liquidity_handler/compounding_liquidity.rs b/programs/cp-amm/src/liquidity_handler/compounding_liquidity.rs index 05276c3a..23f1b885 100644 --- a/programs/cp-amm/src/liquidity_handler/compounding_liquidity.rs +++ b/programs/cp-amm/src/liquidity_handler/compounding_liquidity.rs @@ -148,6 +148,7 @@ impl LiquidityHandler for CompoundingLiquidity { Ok((self.token_a_amount, self.token_b_amount)) } + // xyk, the price is determined by the ratio of reserves and it always rounded down. fn get_next_sqrt_price(&self, _next_sqrt_price: u128) -> Result { get_sqrt_price_from_amounts(self.token_a_amount, self.token_b_amount) } diff --git a/programs/cp-amm/src/liquidity_handler/concentrated_liquidity.rs b/programs/cp-amm/src/liquidity_handler/concentrated_liquidity.rs index 3897c7f9..7ff3567a 100644 --- a/programs/cp-amm/src/liquidity_handler/concentrated_liquidity.rs +++ b/programs/cp-amm/src/liquidity_handler/concentrated_liquidity.rs @@ -1,17 +1,10 @@ #[cfg(test)] use crate::params::swap::TradeDirection; use crate::{ - // curve::{ - // get_delta_amount_a_unsigned, get_delta_amount_a_unsigned_unchecked, - // get_delta_amount_b_unsigned, get_delta_amount_b_unsigned_unchecked, - // get_next_sqrt_price_from_input, get_next_sqrt_price_from_output, - // }, safe_math::SafeMath, state::{SwapAmountFromInput, SwapAmountFromOutput}, u128x128_math::{mul_div_u256, Rounding}, - InitialPoolInformation, - LiquidityHandler, - PoolError, + InitialPoolInformation, LiquidityHandler, PoolError, }; use anchor_lang::prelude::*; use ruint::aliases::U256; @@ -257,6 +250,7 @@ impl LiquidityHandler for ConcentratedLiquidity { Ok((reserve_a_amount, reserve_b_amount)) } + // It does nothing because next_sqrt_price is computed by swap-path + rounding direction. fn get_next_sqrt_price(&self, next_sqrt_price: u128) -> Result { Ok(next_sqrt_price) } @@ -268,13 +262,13 @@ impl LiquidityHandler for ConcentratedLiquidity { self.sqrt_min_price, self.sqrt_price, self.liquidity, - Rounding::Down, + Rounding::Up, )?, TradeDirection::BtoA => get_delta_amount_b_unsigned_unchecked( self.sqrt_price, self.sqrt_max_price, self.liquidity, - Rounding::Down, + Rounding::Up, )?, }; if amount > U256::from(u64::MAX) { @@ -368,7 +362,7 @@ pub fn get_delta_amount_b_unsigned_unchecked( } /// Gets the next sqrt price given an input amount of token_a or token_b -/// Throws if price or liquidity are 0, or if the next price is out of bounds +/// Throws if price or liquidity are 0, or if the next price overflow q64.64 pub fn get_next_sqrt_price_from_input( sqrt_price: u128, liquidity: u128, @@ -378,6 +372,10 @@ pub fn get_next_sqrt_price_from_input( assert!(sqrt_price > 0); assert!(liquidity > 0); + if amount_in == 0 { + return Ok(sqrt_price); + } + // round to make sure that we don't pass the target price if a_for_b { get_next_sqrt_price_from_amount_in_a_rounding_up(sqrt_price, liquidity, amount_in) @@ -387,7 +385,7 @@ pub fn get_next_sqrt_price_from_input( } /// Gets the next sqrt price given an output amount of token_a or token_b -/// Throws if price or liquidity are 0, or if the next price is out of bounds +/// Throws if price or liquidity are 0, or if the next price overflow q64.64 pub fn get_next_sqrt_price_from_output( sqrt_price: u128, liquidity: u128, @@ -397,6 +395,10 @@ pub fn get_next_sqrt_price_from_output( assert!(sqrt_price > 0); assert!(liquidity > 0); + if amount_out == 0 { + return Ok(sqrt_price); + } + // round to make sure that we don't pass the target price if a_for_b { get_next_sqrt_price_from_amount_out_b_rounding_down(sqrt_price, liquidity, amount_out) @@ -438,9 +440,6 @@ pub fn get_next_sqrt_price_from_amount_in_a_rounding_up( liquidity: u128, amount: u64, ) -> Result { - if amount == 0 { - return Ok(sqrt_price); - } let sqrt_price = U256::from(sqrt_price); let liquidity = U256::from(liquidity); @@ -457,9 +456,6 @@ pub fn get_next_sqrt_price_from_amount_out_a_rounding_up( liquidity: u128, amount: u64, ) -> Result { - if amount == 0 { - return Ok(sqrt_price); - } let sqrt_price = U256::from(sqrt_price); let liquidity = U256::from(liquidity); diff --git a/programs/cp-amm/src/liquidity_handler/mod.rs b/programs/cp-amm/src/liquidity_handler/mod.rs index 6699bd9f..9953d3a8 100644 --- a/programs/cp-amm/src/liquidity_handler/mod.rs +++ b/programs/cp-amm/src/liquidity_handler/mod.rs @@ -40,6 +40,12 @@ pub trait LiquidityHandler { fn get_reserves_amount(&self) -> Result<(u64, u64)>; + // Note: Due to different way of concentrated liquidity and compounding liquidity calculating price, compounding and concentrated pools can update dynamic-fee volatility differently for equivalent swap price moves. + // Additionally the market cap based base fee will also behave differently: + // Concentrated Amount_In B to A -> Rounding Down + // Concentrated Amount_Out B to A -> Rounding Up + // Compounding Amount_In B to A -> Rounding Down + // Compounding Amount_Out B to A -> Rounding Down fn get_next_sqrt_price(&self, next_sqrt_price: u128) -> Result; #[cfg(test)] diff --git a/tsconfig.json b/tsconfig.json index b05883ec..281ebf8a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,6 +8,7 @@ "esModuleInterop": true, "resolveJsonModule": true, "noEmit": true, - "skipLibCheck": true + "skipLibCheck": true, + "strict": false } }