From 95f9b7879ba3208d1d9dbb3798de3cdc4194d520 Mon Sep 17 00:00:00 2001 From: Shuhui Luo <107524008+shuhuiluo@users.noreply.github.com> Date: Mon, 1 Jan 2024 00:58:14 -0800 Subject: [PATCH 1/2] Add `TickList` trait and tests A `TickList` trait has been implemented to handle tick-related tasks such as binary search, position checking, and list validation on array slices. A `Tick` structure and a `TickTrait` were created to manage ticks more efficiently. Relevant test cases were also added. This update is marked by a version change to 0.4.0. --- Cargo.lock | 60 ++++---- Cargo.toml | 2 +- src/entities/mod.rs | 6 +- src/entities/tick.rs | 58 +++++++ src/lib.rs | 1 + src/utils/mod.rs | 2 + src/utils/tick_list.rs | 339 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 436 insertions(+), 32 deletions(-) create mode 100644 src/entities/tick.rs create mode 100644 src/utils/tick_list.rs diff --git a/Cargo.lock b/Cargo.lock index 371b8a9..8984f08 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,7 +120,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.44", "syn-solidity", "tiny-keccak", ] @@ -160,9 +160,9 @@ checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" [[package]] name = "anyhow" -version = "1.0.77" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9d19de80eff169429ac1e9f48fffb163916b448a44e8e046186232046d9e1f9" +checksum = "ca87830a3e3fb156dc96cfbd31cb620265dd053be734723f22b760d6cc3c3051" [[package]] name = "ark-ff" @@ -296,13 +296,13 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "async-trait" -version = "0.1.75" +version = "0.1.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdf6721fb0140e4f897002dd086c06f6c27775df19cfe1fccb21181a48fd2c98" +checksum = "531b97fb4cd3dfdce92c35dedbfdc1f0b9d8091c8ca943d6dae340ef5012d514" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.44", ] [[package]] @@ -1100,7 +1100,7 @@ dependencies = [ "regex", "serde", "serde_json", - "syn 2.0.43", + "syn 2.0.44", "toml", "walkdir", ] @@ -1118,7 +1118,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.43", + "syn 2.0.44", ] [[package]] @@ -1144,7 +1144,7 @@ dependencies = [ "serde", "serde_json", "strum", - "syn 2.0.43", + "syn 2.0.44", "tempfile", "thiserror", "tiny-keccak", @@ -1374,7 +1374,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.44", ] [[package]] @@ -1910,7 +1910,7 @@ dependencies = [ "proc-macro-crate 2.0.1", "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.44", ] [[package]] @@ -2072,7 +2072,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.44", ] [[package]] @@ -2144,7 +2144,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" dependencies = [ "proc-macro2", - "syn 2.0.43", + "syn 2.0.44", ] [[package]] @@ -2207,9 +2207,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.71" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8" +checksum = "2dd5e8a1f1029c43224ad5898e50140c2aebb1705f19e67c918ebf5b9e797fe1" dependencies = [ "unicode-ident", ] @@ -2242,9 +2242,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.33" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "22a37c9326af5ed140c86a46655b5278de879853be5573c01df185b6f49a580a" dependencies = [ "proc-macro2", ] @@ -2740,14 +2740,14 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.44", ] [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "cb0652c533506ad7a2e353cce269330d6afd8bdfb6d75e0ace5b35aacbd7b9e9" dependencies = [ "itoa", "ryu", @@ -2888,7 +2888,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.43", + "syn 2.0.44", ] [[package]] @@ -2910,9 +2910,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.43" +version = "2.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53" +checksum = "92d27c2c202598d05175a6dd3af46824b7f747f8d8e9b14c623f19fa5069735d" dependencies = [ "proc-macro2", "quote", @@ -2928,7 +2928,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.44", ] [[package]] @@ -2988,7 +2988,7 @@ checksum = "3dcf4a824cce0aeacd6f38ae6f24234c8e80d68632338ebaa1443b5df9e29e19" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.44", ] [[package]] @@ -3164,7 +3164,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.44", ] [[package]] @@ -3270,7 +3270,7 @@ dependencies = [ [[package]] name = "uniswap-v3-sdk-rs" -version = "0.3.0" +version = "0.4.0" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -3399,7 +3399,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.44", "wasm-bindgen-shared", ] @@ -3433,7 +3433,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.44", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3681,5 +3681,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.44", ] diff --git a/Cargo.toml b/Cargo.toml index b1fdf1f..352115f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uniswap-v3-sdk-rs" -version = "0.3.0" +version = "0.4.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/entities/mod.rs b/src/entities/mod.rs index c9e2bb1..0643c4f 100644 --- a/src/entities/mod.rs +++ b/src/entities/mod.rs @@ -1 +1,5 @@ -pub mod pool; +mod pool; +mod tick; + +pub use pool::Pool; +pub use tick::{Tick, TickTrait}; diff --git a/src/entities/tick.rs b/src/entities/tick.rs new file mode 100644 index 0000000..8fdea30 --- /dev/null +++ b/src/entities/tick.rs @@ -0,0 +1,58 @@ +use crate::utils::{MAX_TICK, MIN_TICK}; + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Tick { + pub index: i32, + pub liquidity_gross: u128, + pub liquidity_net: i128, +} + +pub trait TickTrait: PartialOrd { + fn index(&self) -> i32; + + fn liquidity_gross(&self) -> u128; + + fn liquidity_net(&self) -> i128; +} + +impl TickTrait for Tick { + fn index(&self) -> i32 { + self.index + } + + fn liquidity_gross(&self) -> u128 { + self.liquidity_gross + } + + fn liquidity_net(&self) -> i128 { + self.liquidity_net + } +} + +impl Tick { + pub const fn new(index: i32, liquidity_gross: u128, liquidity_net: i128) -> Self { + assert!(index >= MIN_TICK && index <= MAX_TICK, "TICK"); + Self { + index, + liquidity_gross, + liquidity_net, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[should_panic(expected = "TICK")] + fn test_tick_below_min_tick() { + Tick::new(MIN_TICK - 1, 0, 0); + } + + #[test] + #[should_panic(expected = "TICK")] + fn test_tick_above_max_tick() { + Tick::new(MAX_TICK + 1, 0, 0); + } +} diff --git a/src/lib.rs b/src/lib.rs index 8b60b4e..04b793b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ #![feature(int_roundings)] +#![feature(is_sorted)] //! # v3-sdk-rs //! //! Migration of Uniswap V3 SDK to Rust diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 6e619e1..11fd876 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -9,6 +9,7 @@ mod position; mod price_tick_conversions; mod sqrt_price_math; mod swap_math; +mod tick_list; mod tick_math; pub use bit_math::*; @@ -22,6 +23,7 @@ pub use position::get_tokens_owed; pub use price_tick_conversions::*; pub use sqrt_price_math::*; pub use swap_math::compute_swap_step; +pub use tick_list::TickList; pub use tick_math::*; use alloy_primitives::U256; diff --git a/src/utils/tick_list.rs b/src/utils/tick_list.rs new file mode 100644 index 0000000..d5e1670 --- /dev/null +++ b/src/utils/tick_list.rs @@ -0,0 +1,339 @@ +use super::add_delta; +use crate::entities::TickTrait; + +/// Utility methods for interacting with sorted lists of self +pub trait TickList { + fn validate_list(&self, tick_spacing: i32); + + fn is_below_smallest(&self, tick: i32) -> bool; + + fn is_at_or_above_largest(&self, tick: i32) -> bool; + + fn get_tick(&self, index: i32) -> &T; + + /// Finds the largest tick in the list of ticks that is less than or equal to tick + /// + /// # Arguments + /// + /// * `tick`: tick to find the largest tick that is less than or equal to tick + /// + /// returns: usize + /// + fn binary_search_by_tick(&self, tick: i32) -> usize; + + fn next_initialized_tick(&self, tick: i32, lte: bool) -> &T; + + fn next_initialized_tick_within_one_word( + &self, + tick: i32, + lte: bool, + tick_spacing: i32, + ) -> (i32, bool); +} + +impl TickList for [T] { + fn validate_list(&self, tick_spacing: i32) { + assert!(tick_spacing > 0, "TICK_SPACING_NONZERO"); + assert!( + self.iter().all(|x| x.index() % tick_spacing == 0), + "TICK_SPACING" + ); + assert!(self.is_sorted(), "SORTED"); + assert_eq!( + self.iter() + .fold(0, |acc, x| add_delta(acc, x.liquidity_net()).unwrap()), + 0, + "ZERO_NET" + ); + } + + fn is_below_smallest(&self, tick: i32) -> bool { + assert!(!self.is_empty(), "LENGTH"); + tick < self[0].index() + } + + fn is_at_or_above_largest(&self, tick: i32) -> bool { + assert!(!self.is_empty(), "LENGTH"); + tick >= self.last().unwrap().index() + } + + fn get_tick(&self, index: i32) -> &T { + let i = Self::binary_search_by_tick(self, index); + let tick = &self[i]; + assert_eq!(tick.index(), index, "NOT_CONTAINED"); + tick + } + + fn binary_search_by_tick(&self, tick: i32) -> usize { + assert!(!Self::is_below_smallest(self, tick), "BELOW_SMALLEST"); + let mut l = 0; + let mut r = self.len() - 1; + + loop { + let i = (l + r) / 2; + if self[i].index() <= tick && (i == self.len() - 1 || self[i + 1].index() > tick) { + return i; + } + if self[i].index() < tick { + l = i + 1; + } else { + r = i - 1; + } + } + } + + fn next_initialized_tick(&self, tick: i32, lte: bool) -> &T { + if lte { + assert!(!Self::is_below_smallest(self, tick), "BELOW_SMALLEST"); + if Self::is_at_or_above_largest(self, tick) { + return self.last().unwrap(); + } + let index = Self::binary_search_by_tick(self, tick); + &self[index] + } else { + assert!( + !Self::is_at_or_above_largest(self, tick), + "AT_OR_ABOVE_LARGEST" + ); + if Self::is_below_smallest(self, tick) { + return &self[0]; + } + let index = Self::binary_search_by_tick(self, tick); + &self[index + 1] + } + } + + fn next_initialized_tick_within_one_word( + &self, + tick: i32, + lte: bool, + tick_spacing: i32, + ) -> (i32, bool) { + let compressed = tick.div_floor(tick_spacing); + if lte { + let word_pos = compressed >> 8; + let minimum = (word_pos << 8) * tick_spacing; + + if Self::is_below_smallest(self, tick) { + return (minimum, false); + } + let index = Self::next_initialized_tick(self, tick, lte).index(); + let next_initialized_tick = minimum.max(index); + (next_initialized_tick, next_initialized_tick == index) + } else { + let word_pos = (compressed + 1) >> 8; + let maximum = (((word_pos + 1) << 8) - 1) * tick_spacing; + if Self::is_at_or_above_largest(self, tick) { + return (maximum, false); + } + let index = Self::next_initialized_tick(self, tick, lte).index(); + let next_initialized_tick = maximum.min(index); + (next_initialized_tick, next_initialized_tick == index) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + entities::Tick, + utils::{MAX_TICK, MIN_TICK}, + }; + + const LOW_TICK: Tick = Tick::new(MIN_TICK + 1, 10, 10); + const MID_TICK: Tick = Tick::new(0, 5, -5); + const HIGH_TICK: Tick = Tick::new(MAX_TICK - 1, 5, -5); + const TICKS: [Tick; 3] = [LOW_TICK, MID_TICK, HIGH_TICK]; + + #[test] + fn test_impl_for_vec() { + let ticks = vec![LOW_TICK, MID_TICK, HIGH_TICK]; + assert_eq!(ticks.binary_search_by_tick(-1), 0); + assert_eq!(ticks.binary_search_by_tick(0), 1); + assert_eq!(ticks.binary_search_by_tick(1), 1); + assert_eq!(ticks.binary_search_by_tick(MAX_TICK), 2); + } + + #[test] + #[should_panic(expected = "ZERO_NET")] + fn test_validate_list_zero_net() { + [LOW_TICK].validate_list(1); + } + + #[test] + #[should_panic(expected = "SORTED")] + fn test_validate_list_unsorted() { + [HIGH_TICK, LOW_TICK, MID_TICK].validate_list(1); + } + + #[test] + #[should_panic(expected = "TICK_SPACING")] + fn test_validate_list_tick_spacing() { + [HIGH_TICK, LOW_TICK, MID_TICK].validate_list(1337); + } + + #[test] + fn test_is_below_smallest() { + assert!(TICKS.is_below_smallest(MIN_TICK)); + assert!(!TICKS.is_below_smallest(MIN_TICK + 1)); + } + + #[test] + fn test_is_at_or_above_largest() { + assert!(!TICKS.is_at_or_above_largest(MAX_TICK - 2)); + assert!(TICKS.is_at_or_above_largest(MAX_TICK - 1)); + } + + #[test] + #[should_panic(expected = "BELOW_SMALLEST")] + fn test_next_initialized_tick_low_lte_true() { + TICKS.next_initialized_tick(MIN_TICK, true); + } + + #[test] + fn test_next_initialized_tick_low_lte_true_2() { + assert_eq!(TICKS.next_initialized_tick(MIN_TICK + 1, true), &LOW_TICK); + assert_eq!(TICKS.next_initialized_tick(MIN_TICK + 2, true), &LOW_TICK); + } + + #[test] + fn test_next_initialized_tick_low_lte_false() { + assert_eq!(TICKS.next_initialized_tick(MIN_TICK, false), &LOW_TICK); + assert_eq!(TICKS.next_initialized_tick(MIN_TICK + 1, false), &MID_TICK); + } + + #[test] + fn test_next_initialized_tick_mid_lte_true() { + assert_eq!(TICKS.next_initialized_tick(0, true), &MID_TICK); + assert_eq!(TICKS.next_initialized_tick(1, true), &MID_TICK); + } + + #[test] + fn test_next_initialized_tick_mid_lte_false() { + assert_eq!(TICKS.next_initialized_tick(-1, false), &MID_TICK); + assert_eq!(TICKS.next_initialized_tick(0 + 1, false), &HIGH_TICK); + } + + #[test] + fn test_next_initialized_tick_high_lte_true() { + assert_eq!(TICKS.next_initialized_tick(MAX_TICK - 1, true), &HIGH_TICK); + assert_eq!(TICKS.next_initialized_tick(MAX_TICK, true), &HIGH_TICK); + } + + #[test] + #[should_panic(expected = "AT_OR_ABOVE_LARGEST")] + fn test_next_initialized_tick_high_lte_false() { + TICKS.next_initialized_tick(MAX_TICK - 1, false); + } + + #[test] + fn test_next_initialized_tick_high_lte_false_2() { + assert_eq!(TICKS.next_initialized_tick(MAX_TICK - 2, false), &HIGH_TICK); + assert_eq!(TICKS.next_initialized_tick(MAX_TICK - 3, false), &HIGH_TICK); + } + + #[test] + fn test_next_initialized_tick_within_one_word_lte_true() { + assert_eq!( + TICKS.next_initialized_tick_within_one_word(-257, true, 1), + (-512, false) + ); + assert_eq!( + TICKS.next_initialized_tick_within_one_word(-256, true, 1), + (-256, false) + ); + assert_eq!( + TICKS.next_initialized_tick_within_one_word(-1, true, 1), + (-256, false) + ); + assert_eq!( + TICKS.next_initialized_tick_within_one_word(0, true, 1), + (0, true) + ); + assert_eq!( + TICKS.next_initialized_tick_within_one_word(1, true, 1), + (0, true) + ); + assert_eq!( + TICKS.next_initialized_tick_within_one_word(255, true, 1), + (0, true) + ); + assert_eq!( + TICKS.next_initialized_tick_within_one_word(256, true, 1), + (256, false) + ); + assert_eq!( + TICKS.next_initialized_tick_within_one_word(257, true, 1), + (256, false) + ); + } + + #[test] + fn test_next_initialized_tick_within_one_word_lte_false() { + assert_eq!( + TICKS.next_initialized_tick_within_one_word(-258, false, 1), + (-257, false) + ); + assert_eq!( + TICKS.next_initialized_tick_within_one_word(-257, false, 1), + (-1, false) + ); + assert_eq!( + TICKS.next_initialized_tick_within_one_word(-256, false, 1), + (-1, false) + ); + assert_eq!( + TICKS.next_initialized_tick_within_one_word(-2, false, 1), + (-1, false) + ); + assert_eq!( + TICKS.next_initialized_tick_within_one_word(-1, false, 1), + (0, true) + ); + assert_eq!( + TICKS.next_initialized_tick_within_one_word(0, false, 1), + (255, false) + ); + assert_eq!( + TICKS.next_initialized_tick_within_one_word(1, false, 1), + (255, false) + ); + assert_eq!( + TICKS.next_initialized_tick_within_one_word(254, false, 1), + (255, false) + ); + assert_eq!( + TICKS.next_initialized_tick_within_one_word(255, false, 1), + (511, false) + ); + assert_eq!( + TICKS.next_initialized_tick_within_one_word(256, false, 1), + (511, false) + ); + } + + #[test] + fn test_next_initialized_tick_within_one_word_tick_spacing_gt_1() { + let ticks = [ + Tick { + index: 0, + liquidity_net: 0, + liquidity_gross: 0, + }, + Tick { + index: 511, + liquidity_net: 0, + liquidity_gross: 0, + }, + ]; + assert_eq!( + ticks.next_initialized_tick_within_one_word(0, false, 1), + (255, false) + ); + assert_eq!( + ticks.next_initialized_tick_within_one_word(0, false, 2), + (510, false) + ); + } +} From 1b107700cf0c1ac39a3fce8409c5caae9bf78bb7 Mon Sep 17 00:00:00 2001 From: Shuhui Luo <107524008+shuhuiluo@users.noreply.github.com> Date: Mon, 1 Jan 2024 00:59:42 -0800 Subject: [PATCH 2/2] Convert functions to `const` in math and tick utils Functions in the `sqrt_price_math.rs` and `nearest_usable_tick.rs` files, as well as the `constants.rs` file, were changed from regular to `const` functions. This provides the capacity to have these functions evaluated at compile time wherever their usage throughout the codebase makes it possible for constant evaluation. Also, updated the tick comparison in `nearest_usable_tick.rs` which ensures more readability. --- src/constants.rs | 2 +- src/utils/nearest_usable_tick.rs | 4 ++-- src/utils/sqrt_price_math.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/constants.rs b/src/constants.rs index acd0e35..aac627c 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -18,7 +18,7 @@ pub enum FeeAmount { impl FeeAmount { /// The default factory tick spacings by fee amount. - pub fn tick_spacing(&self) -> i32 { + pub const fn tick_spacing(&self) -> i32 { match self { Self::LOWEST => 1, Self::LOW => 10, diff --git a/src/utils/nearest_usable_tick.rs b/src/utils/nearest_usable_tick.rs index 11d3d0b..55a54f8 100644 --- a/src/utils/nearest_usable_tick.rs +++ b/src/utils/nearest_usable_tick.rs @@ -9,9 +9,9 @@ use super::tick_math::{MAX_TICK, MIN_TICK}; /// /// returns: i32 /// -pub fn nearest_usable_tick(tick: i32, tick_spacing: i32) -> i32 { +pub const fn nearest_usable_tick(tick: i32, tick_spacing: i32) -> i32 { assert!(tick_spacing > 0, "TICK_SPACING"); - assert!((MIN_TICK..=MAX_TICK).contains(&tick), "TICK_BOUND"); + assert!(tick >= MIN_TICK && tick <= MAX_TICK, "TICK_BOUND"); let rounded = tick.div_floor(tick_spacing) * tick_spacing; let rounded = rounded + (tick - rounded + tick_spacing / 2) / tick_spacing * tick_spacing; if rounded < MIN_TICK { diff --git a/src/utils/sqrt_price_math.rs b/src/utils/sqrt_price_math.rs index 9da123e..d4cbd25 100644 --- a/src/utils/sqrt_price_math.rs +++ b/src/utils/sqrt_price_math.rs @@ -17,7 +17,7 @@ fn to_uint160(x: U256) -> Result { } } -fn to_uint256(x: u128) -> U256 { +const fn to_uint256(x: u128) -> U256 { U256::from_limbs([x as u64, (x >> 64) as u64, 0, 0]) }