From a6ee1c96060f4fba900ad4c94b944f386c4fc2cb Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Tue, 3 Jun 2025 21:00:09 -0400 Subject: [PATCH 1/2] Add changes from Max and Dr. Nick --- pallets/swap/src/pallet/impls.rs | 184 +++++++++++++++++++------------ pallets/swap/src/tick.rs | 4 + 2 files changed, 115 insertions(+), 73 deletions(-) diff --git a/pallets/swap/src/pallet/impls.rs b/pallets/swap/src/pallet/impls.rs index 878b758f57..80f31b3f1a 100644 --- a/pallets/swap/src/pallet/impls.rs +++ b/pallets/swap/src/pallet/impls.rs @@ -25,7 +25,6 @@ struct SwapStep { // Input parameters netuid: NetUid, order_type: OrderType, - first_step: bool, // Computed values current_liquidity: U64F64, @@ -57,7 +56,6 @@ impl SwapStep { order_type: OrderType, amount_remaining: u64, limit_sqrt_price: SqrtPrice, - first_step: bool, ) -> Self { // Calculate prices and ticks let current_tick = CurrentTick::::get(netuid); @@ -82,7 +80,6 @@ impl SwapStep { Self { netuid, order_type, - first_step, target_sqrt_price, limit_sqrt_price, current_sqrt_price, @@ -102,7 +99,7 @@ impl SwapStep { /// Execute the swap step and return the result fn execute(&mut self) -> Result> { - self.determine_action()?; + self.determine_action(); self.process_swap() } @@ -119,25 +116,9 @@ impl SwapStep { } /// Determine the appropriate action for this swap step - fn determine_action(&mut self) -> Result<(), Error> { + fn determine_action(&mut self) { let mut recalculate_fee = false; - // For sell orders: If the current price matches the edge price, then cross the tick first, - // and then move the edge price to one active tick lower. - // Also, if this is the first swap step, cross the tick. - if (self.edge_sqrt_price == self.current_sqrt_price) && (self.order_type == OrderType::Sell) - { - if self.first_step { - self.cross_tick()?; - } - self.edge_tick = ActiveTickIndexManager::::find_closest_lower( - self.netuid, - self.edge_tick.prev().unwrap_or(TickIndex::MIN), - ) - .unwrap_or(TickIndex::MIN); - self.edge_sqrt_price = self.edge_tick.as_sqrt_price_bounded(); - } - // Calculate the stopping price: The price at which we either reach the limit price, // exchange the full amount, or reach the edge price. if self.tick_is_closer(&self.target_tick, &self.limit_tick) @@ -176,6 +157,28 @@ impl SwapStep { recalculate_fee = true; } + // println!("\tAction : {:?}", self.action); + // println!( + // "\tCurrent Price : {}", + // self.current_sqrt_price * self.current_sqrt_price + // ); + // println!( + // "\tTarget Price : {}", + // self.target_sqrt_price * self.target_sqrt_price + // ); + // println!( + // "\tLimit Price : {}", + // self.limit_sqrt_price * self.limit_sqrt_price + // ); + // println!( + // "\tEdge Price : {}", + // self.edge_sqrt_price * self.edge_sqrt_price + // ); + // println!( + // "\t{}", + // format!("Delta In : {}", self.delta_in).yellow() + // ); + // Because on step creation we calculate fee off the total amount, we might need to recalculate it // in case if we hit the limit price or the edge price. if recalculate_fee { @@ -201,31 +204,6 @@ impl SwapStep { OrderType::Sell => SwapStepAction::Stop, }; } - - Ok(()) - } - - fn cross_tick(&self) -> Result<(), Error> { - // Get current tick - let current_tick_index = TickIndex::current_bounded::(self.netuid); - - let mut tick = match self.order_type { - OrderType::Sell => { - Pallet::::find_closest_lower_active_tick(self.netuid, current_tick_index) - } - OrderType::Buy => { - Pallet::::find_closest_higher_active_tick(self.netuid, current_tick_index) - } - } - .ok_or(Error::::InsufficientLiquidity)?; - - tick.fees_out_tao = FeeGlobalTao::::get(self.netuid).saturating_sub(tick.fees_out_tao); - tick.fees_out_alpha = - FeeGlobalAlpha::::get(self.netuid).saturating_sub(tick.fees_out_alpha); - Pallet::::update_liquidity_at_crossing(self.netuid, self.order_type)?; - Ticks::::insert(self.netuid, current_tick_index, tick); - - Ok(()) } /// Process a single step of a swap @@ -233,9 +211,28 @@ impl SwapStep { // Hold the fees Pallet::::add_fees(self.netuid, self.order_type, self.fee); let delta_out = Pallet::::convert_deltas(self.netuid, self.order_type, self.delta_in); + // println!("\t{}", format!("Delta Out : {}", delta_out).green()); + + // Get current tick + let current_tick_index = TickIndex::current_bounded::(self.netuid); if self.action == SwapStepAction::Crossing { - self.cross_tick()?; + let mut tick = match self.order_type { + OrderType::Sell => { + Pallet::::find_closest_lower_active_tick(self.netuid, current_tick_index) + } + OrderType::Buy => { + Pallet::::find_closest_higher_active_tick(self.netuid, current_tick_index) + } + } + .ok_or(Error::::InsufficientLiquidity)?; + + tick.fees_out_tao = + FeeGlobalTao::::get(self.netuid).saturating_sub(tick.fees_out_tao); + tick.fees_out_alpha = + FeeGlobalAlpha::::get(self.netuid).saturating_sub(tick.fees_out_alpha); + Pallet::::update_liquidity_at_crossing(self.netuid, self.order_type)?; + Ticks::::insert(self.netuid, current_tick_index, tick); } // Update current price @@ -352,7 +349,7 @@ impl Pallet { /// - `netuid`: The identifier of the subnet on which the swap is performed. /// - `order_type`: The type of the swap (e.g., Buy or Sell). /// - `amount`: The amount of tokens to swap. - /// - `sqrt_price_limit`: A price limit (expressed as a square root) to bound the swap. + /// - `limit_sqrt_price`: A price limit (expressed as a square root) to bound the swap. /// - `simulate`: If `true`, the function runs in simulation mode and does not persist any changes. /// /// # Returns @@ -372,7 +369,7 @@ impl Pallet { netuid: NetUid, order_type: OrderType, amount: u64, - sqrt_price_limit: SqrtPrice, + limit_sqrt_price: SqrtPrice, simulate: bool, ) -> Result { transactional::with_transaction(|| { @@ -381,7 +378,7 @@ impl Pallet { let alpha_reserve = T::SubnetInfo::alpha_reserve(netuid.into()); let mut result = - Self::swap_inner(netuid, order_type, amount, sqrt_price_limit).map_err(Into::into); + Self::swap_inner(netuid, order_type, amount, limit_sqrt_price).map_err(Into::into); if simulate || result.is_err() { // Simulation only @@ -410,7 +407,7 @@ impl Pallet { netuid: NetUid, order_type: OrderType, amount: u64, - sqrt_price_limit: SqrtPrice, + limit_sqrt_price: SqrtPrice, ) -> Result> { ensure!( T::SubnetInfo::tao_reserve(netuid.into()) >= T::MinimumReserve::get().get() @@ -426,16 +423,20 @@ impl Pallet { let mut in_acc: u64 = 0; let mut fee_acc: u64 = 0; + // println!("======== Start Swap ========"); + // println!("Amount Remaining: {}", amount_remaining); + // Swap one tick at a time until we reach one of the stop conditions while amount_remaining > 0 { + // println!("\nIteration: {}", iteration_counter); + // println!( + // "\tCurrent Liquidity: {}", + // CurrentLiquidity::::get(netuid) + // ); + // Create and execute a swap step - let mut swap_step = SwapStep::::new( - netuid, - order_type, - amount_remaining, - sqrt_price_limit, - iteration_counter == 0, - ); + let mut swap_step = + SwapStep::::new(netuid, order_type, amount_remaining, limit_sqrt_price); let swap_result = swap_step.execute()?; @@ -461,6 +462,9 @@ impl Pallet { ); } + // println!("\nAmount Paid Out: {}", amount_paid_out); + // println!("======== End Swap ========"); + let tao_reserve = T::SubnetInfo::tao_reserve(netuid.into()); let alpha_reserve = T::SubnetInfo::alpha_reserve(netuid.into()); let (new_tao_reserve, new_alpha_reserve) = match order_type { @@ -491,19 +495,27 @@ impl Pallet { /// the edge that is impossible to execute fn tick_edge(netuid: NetUid, current_tick: TickIndex, order_type: OrderType) -> TickIndex { match order_type { - OrderType::Buy => { - let higher_tick = - ActiveTickIndexManager::::find_closest_higher(netuid, current_tick) - .unwrap_or(TickIndex::MAX); - if higher_tick < TickIndex::MAX { - higher_tick.saturating_add(1) - } else { - higher_tick - } - } + OrderType::Buy => ActiveTickIndexManager::::find_closest_higher( + netuid, + current_tick.next().unwrap_or(TickIndex::MAX), + ) + .unwrap_or(TickIndex::MAX), OrderType::Sell => { - ActiveTickIndexManager::::find_closest_lower(netuid, current_tick) + let current_price = Pallet::::current_price_sqrt(netuid); + let current_tick_price = current_tick.as_sqrt_price_bounded(); + let is_active = ActiveTickIndexManager::::tick_is_active(netuid, current_tick); + + let lower_tick = if is_active && current_price > current_tick_price { + ActiveTickIndexManager::::find_closest_lower(netuid, current_tick) + .unwrap_or(TickIndex::MIN) + } else { + ActiveTickIndexManager::::find_closest_lower( + netuid, + current_tick.prev().unwrap_or(TickIndex::MIN), + ) .unwrap_or(TickIndex::MIN) + }; + lower_tick } } } @@ -635,8 +647,34 @@ impl Pallet { // Find the appropriate tick based on order type let tick = match order_type { - OrderType::Sell => Self::find_closest_lower_active_tick(netuid, current_tick_index), - OrderType::Buy => Self::find_closest_higher_active_tick(netuid, current_tick_index), + OrderType::Sell => { + // Self::find_closest_lower_active_tick(netuid, current_tick_index) + let current_price = Pallet::::current_price_sqrt(netuid); + let current_tick_price = current_tick_index.as_sqrt_price_bounded(); + let is_active = + ActiveTickIndexManager::::tick_is_active(netuid, current_tick_index); + + let lower_tick = if is_active && current_price > current_tick_price { + ActiveTickIndexManager::::find_closest_lower(netuid, current_tick_index) + .unwrap_or(TickIndex::MIN) + } else { + ActiveTickIndexManager::::find_closest_lower( + netuid, + current_tick_index.prev().unwrap_or(TickIndex::MIN), + ) + .unwrap_or(TickIndex::MIN) + }; + Ticks::::get(netuid, lower_tick) + } + OrderType::Buy => { + // Self::find_closest_higher_active_tick(netuid, current_tick_index), + let upper_tick = ActiveTickIndexManager::::find_closest_higher( + netuid, + current_tick_index.next().unwrap_or(TickIndex::MAX), + ) + .unwrap_or(TickIndex::MAX); + Ticks::::get(netuid, upper_tick) + } } .ok_or(Error::::InsufficientLiquidity)?; @@ -1082,7 +1120,7 @@ impl SwapHandler for Pallet { price_limit: u64, should_rollback: bool, ) -> Result { - let sqrt_price_limit = SqrtPrice::saturating_from_num(price_limit) + let limit_sqrt_price = SqrtPrice::saturating_from_num(price_limit) .safe_div(SqrtPrice::saturating_from_num(1_000_000_000)) .checked_sqrt(SqrtPrice::saturating_from_num(0.0000000001)) .ok_or(Error::::PriceLimitExceeded)?; @@ -1091,7 +1129,7 @@ impl SwapHandler for Pallet { NetUid::from(netuid), order_t, amount, - sqrt_price_limit, + limit_sqrt_price, should_rollback, ) .map_err(Into::into) diff --git a/pallets/swap/src/tick.rs b/pallets/swap/src/tick.rs index 5dce895113..db33043ff1 100644 --- a/pallets/swap/src/tick.rs +++ b/pallets/swap/src/tick.rs @@ -693,6 +693,10 @@ impl ActiveTickIndexManager { // Convert the result offset_index back to a tick index TickIndex::from_offset_index(result).ok() } + + pub fn tick_is_active(netuid: NetUid, tick: TickIndex) -> bool { + Self::find_closest_lower(netuid, tick).unwrap_or(TickIndex::MAX) == tick + } } /// Represents the three layers in the Uniswap V3 bitmap structure From fab5aaf49d4b428effd34ce754f8ad282a5c471d Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Wed, 4 Jun 2025 16:13:16 -0400 Subject: [PATCH 2/2] Convert println comments into log::info. Fix clippy --- Cargo.lock | 1 + pallets/swap/Cargo.toml | 1 + pallets/swap/src/pallet/impls.rs | 66 ++++++++++++++++---------------- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 77848ae978..35f7321427 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6930,6 +6930,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "log", "pallet-subtensor-swap-runtime-api", "parity-scale-codec", "safe-math", diff --git a/pallets/swap/Cargo.toml b/pallets/swap/Cargo.toml index df7ee91686..122dbead02 100644 --- a/pallets/swap/Cargo.toml +++ b/pallets/swap/Cargo.toml @@ -10,6 +10,7 @@ codec = { workspace = true } frame-benchmarking = { workspace = true, optional = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } safe-math = { workspace = true } scale-info = { workspace = true } serde = { workspace = true, optional = true } diff --git a/pallets/swap/src/pallet/impls.rs b/pallets/swap/src/pallet/impls.rs index 80f31b3f1a..0c238050ec 100644 --- a/pallets/swap/src/pallet/impls.rs +++ b/pallets/swap/src/pallet/impls.rs @@ -157,27 +157,26 @@ impl SwapStep { recalculate_fee = true; } - // println!("\tAction : {:?}", self.action); - // println!( - // "\tCurrent Price : {}", - // self.current_sqrt_price * self.current_sqrt_price - // ); - // println!( - // "\tTarget Price : {}", - // self.target_sqrt_price * self.target_sqrt_price - // ); - // println!( - // "\tLimit Price : {}", - // self.limit_sqrt_price * self.limit_sqrt_price - // ); - // println!( - // "\tEdge Price : {}", - // self.edge_sqrt_price * self.edge_sqrt_price - // ); - // println!( - // "\t{}", - // format!("Delta In : {}", self.delta_in).yellow() - // ); + log::info!("\tAction : {:?}", self.action); + log::info!( + "\tCurrent Price : {}", + self.current_sqrt_price + .saturating_mul(self.current_sqrt_price) + ); + log::info!( + "\tTarget Price : {}", + self.target_sqrt_price + .saturating_mul(self.target_sqrt_price) + ); + log::info!( + "\tLimit Price : {}", + self.limit_sqrt_price.saturating_mul(self.limit_sqrt_price) + ); + log::info!( + "\tEdge Price : {}", + self.edge_sqrt_price.saturating_mul(self.edge_sqrt_price) + ); + log::info!("\tDelta In : {}", self.delta_in); // Because on step creation we calculate fee off the total amount, we might need to recalculate it // in case if we hit the limit price or the edge price. @@ -211,7 +210,7 @@ impl SwapStep { // Hold the fees Pallet::::add_fees(self.netuid, self.order_type, self.fee); let delta_out = Pallet::::convert_deltas(self.netuid, self.order_type, self.delta_in); - // println!("\t{}", format!("Delta Out : {}", delta_out).green()); + log::info!("\tDelta Out : {:?}", delta_out); // Get current tick let current_tick_index = TickIndex::current_bounded::(self.netuid); @@ -423,16 +422,16 @@ impl Pallet { let mut in_acc: u64 = 0; let mut fee_acc: u64 = 0; - // println!("======== Start Swap ========"); - // println!("Amount Remaining: {}", amount_remaining); + log::info!("======== Start Swap ========"); + log::info!("Amount Remaining: {}", amount_remaining); // Swap one tick at a time until we reach one of the stop conditions while amount_remaining > 0 { - // println!("\nIteration: {}", iteration_counter); - // println!( - // "\tCurrent Liquidity: {}", - // CurrentLiquidity::::get(netuid) - // ); + log::info!("\nIteration: {}", iteration_counter); + log::info!( + "\tCurrent Liquidity: {}", + CurrentLiquidity::::get(netuid) + ); // Create and execute a swap step let mut swap_step = @@ -462,8 +461,8 @@ impl Pallet { ); } - // println!("\nAmount Paid Out: {}", amount_paid_out); - // println!("======== End Swap ========"); + log::info!("\nAmount Paid Out: {}", amount_paid_out); + log::info!("======== End Swap ========"); let tao_reserve = T::SubnetInfo::tao_reserve(netuid.into()); let alpha_reserve = T::SubnetInfo::alpha_reserve(netuid.into()); @@ -505,7 +504,7 @@ impl Pallet { let current_tick_price = current_tick.as_sqrt_price_bounded(); let is_active = ActiveTickIndexManager::::tick_is_active(netuid, current_tick); - let lower_tick = if is_active && current_price > current_tick_price { + if is_active && current_price > current_tick_price { ActiveTickIndexManager::::find_closest_lower(netuid, current_tick) .unwrap_or(TickIndex::MIN) } else { @@ -514,8 +513,7 @@ impl Pallet { current_tick.prev().unwrap_or(TickIndex::MIN), ) .unwrap_or(TickIndex::MIN) - }; - lower_tick + } } } }