diff --git a/Cargo.lock b/Cargo.lock index d09f106..7fa7968 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,28 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "alloy-primitives" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "600d34d8de81e23b6d909c094e23b3d357e01ca36b78a8c5424c501eedbe86f0" -dependencies = [ - "alloy-rlp", - "bytes", - "cfg-if", - "const-hex", - "derive_more 0.99.20", - "hex-literal", - "itoa", - "k256", - "keccak-asm", - "proptest", - "rand 0.8.5", - "ruint", - "serde", - "tiny-keccak", -] - [[package]] name = "alloy-primitives" version = "1.4.1" @@ -34,7 +12,7 @@ dependencies = [ "bytes", "cfg-if", "const-hex", - "derive_more 2.0.1", + "derive_more", "foldhash", "hashbrown", "indexmap", @@ -408,12 +386,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - [[package]] name = "cpufeatures" version = "0.2.17" @@ -472,19 +444,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "derive_more" -version = "0.99.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version 0.4.1", - "syn 2.0.99", -] - [[package]] name = "derive_more" version = "2.0.1" @@ -563,9 +522,8 @@ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" name = "ekubo_sdk" version = "3.0.1" dependencies = [ - "alloy-primitives 0.6.4", - "alloy-primitives 1.4.1", - "derive_more 2.0.1", + "alloy-primitives", + "derive_more", "libm", "num-traits", "ruint", @@ -766,12 +724,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hex-literal" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" - [[package]] name = "hmac" version = "0.12.1" @@ -858,7 +810,6 @@ dependencies = [ "elliptic-curve", "once_cell", "sha2", - "signature", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 0df8423..14ea186 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,8 +14,7 @@ readme = "README.md" keywords = ["crypto", "ekubo", "protocol", "defi", "no_std"] [dependencies] -alloy-primitives-0_6 = { package = "alloy-primitives", version = "0.6", optional = true, default-features = false } -alloy-primitives-1 = { package = "alloy-primitives", version = "1", optional = true, default-features = false } +alloy-primitives = { version = "1", optional = true, default-features = false } derive_more = { version = "2", features = [ "add", "add_assign", @@ -35,8 +34,7 @@ thiserror = { version = "2", default-features = false } [features] default = ["std"] std = [ - "alloy-primitives-0_6?/std", - "alloy-primitives-1?/std", + "alloy-primitives?/std", "derive_more/std", "num-traits/std", "ruint/std", @@ -47,12 +45,9 @@ std = [ no_std = ["dep:libm"] serde = [ "dep:serde", - "alloy-primitives-0_6?/serde", - "alloy-primitives-1?/serde", + "alloy-primitives?/serde", "starknet-types-core?/serde", "ruint/serde", ] starknet = ["starknet-types-core"] -evm = ["evm-alloy-1"] -evm-alloy-0_6 = ["dep:alloy-primitives-0_6"] -evm-alloy-1 = ["dep:alloy-primitives-1"] +evm = ["dep:alloy-primitives"] diff --git a/src/chain/evm.rs b/src/chain/evm.rs index 3e0c49a..4b68fdf 100644 --- a/src/chain/evm.rs +++ b/src/chain/evm.rs @@ -6,9 +6,6 @@ use thiserror::Error; use crate::chain::Chain; -#[cfg(all(feature = "evm-alloy-0_6", not(feature = "evm-alloy-1")))] -type U96 = ruint::Uint<96, 2>; -#[cfg(feature = "evm-alloy-1")] use crate::alloy_primitives::aliases::U96; use crate::private; use crate::quoting::pools::boosted_fees::concentrated::{ @@ -197,15 +194,9 @@ pub enum EvmPoolTypeConfig { Concentrated(ConcentratedPoolTypeConfig), } -#[cfg(feature = "evm-alloy-1")] const EVM_POOL_TYPE_CONFIG_CONCENTRATED_MASK: B32 = fixed_bytes!("0x80000000"); -#[cfg(all(feature = "evm-alloy-0_6", not(feature = "evm-alloy-1")))] -const EVM_POOL_TYPE_CONFIG_CONCENTRATED_MASK: B32 = fixed_bytes!("80000000"); -#[cfg(feature = "evm-alloy-1")] const EVM_POOL_TYPE_CONFIG_TICK_SPACING_MASK: B32 = fixed_bytes!("0x7fffffff"); -#[cfg(all(feature = "evm-alloy-0_6", not(feature = "evm-alloy-1")))] -const EVM_POOL_TYPE_CONFIG_TICK_SPACING_MASK: B32 = fixed_bytes!("7fffffff"); /// Order identifier emitted by the TWAMM extension. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -312,19 +303,12 @@ impl Chain for Evm { active_liquidity: u128, ) -> Result { FullRangePool::new( - PoolKey { + PoolKey::new( token0, token1, - config: PoolConfig { - fee, - pool_type_config: FullRangePoolTypeConfig, - extension, - }, - }, - FullRangePoolState { - sqrt_ratio, - liquidity: active_liquidity, - }, + PoolConfig::new(extension, fee, FullRangePoolTypeConfig), + ), + FullRangePoolState::new(sqrt_ratio, active_liquidity), ) } } @@ -469,13 +453,16 @@ impl TryFrom for EvmPoolConfig { impl private::Sealed for Evm {} -/// Converts a compressed sqrt ratio into a fixed-point sqrt ratio. +/// 96-bit contract `sqrtPrice` to canonical SDK `U256 sqrt_ratio`. +/// +/// The on-chain value is a compact float-like encoding (`uint96` payload) used for calldata/storage +/// efficiency. All quote logic in the SDK uses the expanded fixed `U256` representation. pub fn float_sqrt_ratio_to_fixed(sqrt_ratio_float: U96) -> U256 { U256::from(sqrt_ratio_float & NOT_BIT_MASK) << u8::try_from(uint!(2_U96) + ((sqrt_ratio_float & BIT_MASK) >> 89_u8)).unwrap() } -/// Converts a fixed-point sqrt ratio into the compressed contract representation. +/// Canonical SDK `U256 sqrt_ratio` to compact contract `sqrtPrice` payload. pub fn fixed_sqrt_ratio_to_contract_sqrt_ratio(sqrt_ratio: U256) -> U256 { if sqrt_ratio >= TWO_POW_192 { panic!("failed to convert sqrt ratio limit"); @@ -498,41 +485,20 @@ mod tests { use super::*; - #[cfg(feature = "evm-alloy-1")] const ONE_ADDRESS: Address = address!("0x0000000000000000000000000000000000000001"); - #[cfg(all(feature = "evm-alloy-0_6", not(feature = "evm-alloy-1")))] - const ONE_ADDRESS: Address = address!("0000000000000000000000000000000000000001"); - #[cfg(feature = "evm-alloy-1")] const ORDER_CONFIG_RAW: B256 = fixed_bytes!("0x01020304050607080100000000000000112233445566778899aabbccddeeff00"); - #[cfg(all(feature = "evm-alloy-0_6", not(feature = "evm-alloy-1")))] - const ORDER_CONFIG_RAW: B256 = - fixed_bytes!("01020304050607080100000000000000112233445566778899aabbccddeeff00"); - #[cfg(feature = "evm-alloy-1")] const POOL_TOKEN0: Address = address!("0x37c8671A16E257eC501711Cc1d7eb8AF8544A69f"); - #[cfg(all(feature = "evm-alloy-0_6", not(feature = "evm-alloy-1")))] - const POOL_TOKEN0: Address = address!("37c8671A16E257eC501711Cc1d7eb8AF8544A69f"); - #[cfg(feature = "evm-alloy-1")] const POOL_TOKEN1: Address = address!("0xeE8F2aA3e6864493BEae55E27bb5d8a7B57021F8"); - #[cfg(all(feature = "evm-alloy-0_6", not(feature = "evm-alloy-1")))] - const POOL_TOKEN1: Address = address!("eE8F2aA3e6864493BEae55E27bb5d8a7B57021F8"); - #[cfg(feature = "evm-alloy-1")] const POOL_CONFIG_RAW: B256 = fixed_bytes!("0x000000000000000000000000000000000000000040000000000000000d000000"); - #[cfg(all(feature = "evm-alloy-0_6", not(feature = "evm-alloy-1")))] - const POOL_CONFIG_RAW: B256 = - fixed_bytes!("000000000000000000000000000000000000000040000000000000000d000000"); - #[cfg(feature = "evm-alloy-1")] const POOL_ID: B256 = fixed_bytes!("0xa7dfc779e04825212b0daf2a2272e9574a1cc54cd3ff26f590a1b2789677b3c9"); - #[cfg(all(feature = "evm-alloy-0_6", not(feature = "evm-alloy-1")))] - const POOL_ID: B256 = - fixed_bytes!("a7dfc779e04825212b0daf2a2272e9574a1cc54cd3ff26f590a1b2789677b3c9"); impl ChainTest for Evm { fn zero_address() -> Self::Address { diff --git a/src/chain/mod.rs b/src/chain/mod.rs index 393f8cc..c0173e7 100644 --- a/src/chain/mod.rs +++ b/src/chain/mod.rs @@ -10,7 +10,7 @@ use core::{ use num_traits::Zero; use ruint::aliases::U256; -#[cfg(any(feature = "evm", feature = "evm-alloy-0_6", feature = "evm-alloy-1"))] +#[cfg(feature = "evm")] pub mod evm; #[cfg(feature = "starknet")] pub mod starknet; diff --git a/src/lib.rs b/src/lib.rs index 85effb5..2c4c3e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,22 +6,14 @@ compile_error!(r#"Features "std" and "no_std" are mutually exclusive."#); #[cfg(not(any(feature = "std", feature = "no_std")))] compile_error!(r#"Either feature "std" or "no_std" must be enabled."#); -#[cfg(all( - feature = "evm", - not(any(feature = "evm-alloy-0_6", feature = "evm-alloy-1")) -))] -compile_error!(r#"Feature "evm" requires either "evm-alloy-0_6" or "evm-alloy-1"."#); - extern crate alloc; #[cfg(any(test, feature = "std"))] extern crate std; pub use ruint::aliases::U256; -#[cfg(all(feature = "evm-alloy-0_6", not(feature = "evm-alloy-1")))] -pub use alloy_primitives_0_6 as alloy_primitives; -#[cfg(feature = "evm-alloy-1")] -pub use alloy_primitives_1 as alloy_primitives; +#[cfg(feature = "evm")] +pub use alloy_primitives; pub mod chain; pub mod math; diff --git a/src/quoting/pools/boosted_fees/concentrated.rs b/src/quoting/pools/boosted_fees/concentrated.rs index 96ba726..56a7ffe 100644 --- a/src/quoting/pools/boosted_fees/concentrated.rs +++ b/src/quoting/pools/boosted_fees/concentrated.rs @@ -2,7 +2,8 @@ use core::iter::once; use crate::chain::Chain; use crate::quoting::types::{ - BlockTimestamp, LastTimeInfo, Pool, PoolConfig, PoolKey, Quote, QuoteParams, TimeRateDelta, + BlockTimestamp, LastTimeInfo, Pool, PoolConfig, PoolKey, Quote, QuoteParams, Tick, + TimeRateDelta, }; use crate::quoting::util::{approximate_extra_distinct_time_bitmap_lookups, real_last_time}; use crate::{private, quoting::types::PoolState}; @@ -48,6 +49,22 @@ pub struct BoostedFeesConcentratedPoolState { pub donate_rate1: u128, } +impl BoostedFeesConcentratedPoolState { + pub const fn new( + concentrated_pool_state: EvmConcentratedPoolState, + last_donate_time: u32, + donate_rate0: u128, + donate_rate1: u128, + ) -> Self { + Self { + concentrated_pool_state, + last_donate_time, + donate_rate0, + donate_rate1, + } + } +} + #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Add, AddAssign, Sub, SubAssign)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct BoostedFeesConcentratedStandalonePoolResources { @@ -79,6 +96,18 @@ pub enum BoostedFeesConcentratedPoolConstructionError { IncorrectPoolType, } +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Error)] +pub enum BoostedFeesConcentratedPoolFromPartialDataError { + #[error("concentrated pool construction error")] + ConcentratedPoolConstructionError( + #[from] crate::quoting::pools::concentrated::ConcentratedPoolConstructionError, + ), + #[error("boosted-fees concentrated pool construction error")] + BoostedFeesConcentratedPoolConstructionError( + #[from] BoostedFeesConcentratedPoolConstructionError, + ), +} + impl BoostedFeesConcentratedPool { pub fn new( underlying_pool: ConcentratedPool, @@ -122,6 +151,40 @@ impl BoostedFeesConcentratedPool { pub fn donate_rate_deltas(&self) -> &Vec { &self.donate_rate_deltas } + + #[allow(clippy::too_many_arguments)] + pub fn from_partial_data( + key: EvmConcentratedPoolKey, + sqrt_ratio: U256, + partial_ticks: Vec, + min_tick_searched: i32, + max_tick_searched: i32, + liquidity: u128, + current_tick: i32, + last_donate_time_info: LastTimeInfo, + donate_rate0: u128, + donate_rate1: u128, + donate_rate_deltas: Vec, + ) -> Result { + let underlying_pool = ConcentratedPool::from_partial_data( + key, + sqrt_ratio, + partial_ticks, + min_tick_searched, + max_tick_searched, + liquidity, + current_tick, + )?; + + Self::new( + underlying_pool, + last_donate_time_info, + donate_rate0, + donate_rate1, + donate_rate_deltas, + ) + .map_err(Into::into) + } } #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Error)] @@ -144,12 +207,12 @@ impl Pool for BoostedFeesConcentratedPool { } fn state(&self) -> Self::State { - BoostedFeesConcentratedPoolState { - concentrated_pool_state: self.underlying_pool.state(), - last_donate_time: self.last_donate_time, - donate_rate0: self.donate_rate0, - donate_rate1: self.donate_rate1, - } + BoostedFeesConcentratedPoolState::new( + self.underlying_pool.state(), + self.last_donate_time, + self.donate_rate0, + self.donate_rate1, + ) } fn quote( @@ -238,12 +301,12 @@ impl Pool for BoostedFeesConcentratedPool { fees_accumulated: u32::from(fees_accumulated), }, }, - state_after: BoostedFeesConcentratedPoolState { - concentrated_pool_state: underlying_state_after, - last_donate_time: current_time as u32, + state_after: BoostedFeesConcentratedPoolState::new( + underlying_state_after, + current_time as u32, donate_rate0, donate_rate1, - }, + ), }) } diff --git a/src/quoting/pools/concentrated.rs b/src/quoting/pools/concentrated.rs index d595db0..fb8bfbb 100644 --- a/src/quoting/pools/concentrated.rs +++ b/src/quoting/pools/concentrated.rs @@ -63,6 +63,22 @@ pub struct ConcentratedPoolState { pub active_tick_index: Option, } +impl TickSpacing { + pub const fn new(tick_spacing: u32) -> Self { + Self(tick_spacing) + } +} + +impl ConcentratedPoolState { + pub const fn new(sqrt_ratio: U256, liquidity: u128, active_tick_index: Option) -> Self { + Self { + sqrt_ratio, + liquidity, + active_tick_index, + } + } +} + /// Resources consumed during swap execution #[derive(Clone, Copy, Default, Debug, PartialEq, Hash, Eq, Add, AddAssign, Sub, SubAssign)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -190,11 +206,7 @@ impl ConcentratedPool { } // Create the ConcentratedPoolState with the provided sqrt_ratio, liquidity, and computed active_tick_index - let state = ConcentratedPoolState { - sqrt_ratio, - liquidity, - active_tick_index, - }; + let state = ConcentratedPoolState::new(sqrt_ratio, liquidity, active_tick_index); // Call the existing constructor with the prepared parameters Self::new(key, state, sorted_ticks) diff --git a/src/quoting/pools/full_range.rs b/src/quoting/pools/full_range.rs index ea249b0..9561e70 100644 --- a/src/quoting/pools/full_range.rs +++ b/src/quoting/pools/full_range.rs @@ -47,6 +47,15 @@ pub struct FullRangePoolState { pub liquidity: u128, } +impl FullRangePoolState { + pub const fn new(sqrt_ratio: U256, liquidity: u128) -> Self { + Self { + sqrt_ratio, + liquidity, + } + } +} + /// Resources consumed during full range swap execution. #[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash, Add, AddAssign, Sub, SubAssign)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -88,10 +97,7 @@ impl FullRangePool { Ok(Self { key, - state: FullRangePoolState { - sqrt_ratio: state.sqrt_ratio, - liquidity: state.liquidity, - }, + state: FullRangePoolState::new(state.sqrt_ratio, state.liquidity), }) } } @@ -198,10 +204,7 @@ impl Pool for FullRangePool { ), }; - let state_after = FullRangePoolState { - sqrt_ratio, - liquidity, - }; + let state_after = FullRangePoolState::new(sqrt_ratio, liquidity); Ok(Quote { is_price_increasing: is_increasing, diff --git a/src/quoting/pools/limit_order.rs b/src/quoting/pools/limit_order.rs index 2dd44a8..4e1454e 100644 --- a/src/quoting/pools/limit_order.rs +++ b/src/quoting/pools/limit_order.rs @@ -56,6 +56,18 @@ pub struct LimitOrderPoolState { pub tick_indices_reached: Option<(Option, Option)>, } +impl LimitOrderPoolState { + pub const fn new( + concentrated_pool_state: ConcentratedPoolState, + tick_indices_reached: Option<(Option, Option)>, + ) -> Self { + Self { + concentrated_pool_state, + tick_indices_reached, + } + } +} + /// Resources consumed during limit order quote execution. #[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash, Add, AddAssign, Sub, SubAssign)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -86,19 +98,12 @@ pub enum LimitOrderPoolConstructionError { } impl LimitOrderPool { - pub fn new( - token0: Felt, - token1: Felt, - extension: Felt, - sqrt_ratio: U256, - tick: i32, - liquidity: u128, - sorted_ticks: Vec, - ) -> Result { + fn validate_ticks_have_neighbors( + sorted_ticks: &[Tick], + ) -> Result<(), LimitOrderPoolConstructionError> { // check that each tick has at least 1 neighbor within 128 ticks - let active_tick_index = find_nearest_initialized_tick_index(&sorted_ticks, tick); let mut maybe_last: Option<(&Tick, usize)> = None; - for t in &sorted_ticks { + for t in sorted_ticks { if let Some((last, count)) = maybe_last { if t.index == last.index + LIMIT_ORDER_TICK_SPACING { maybe_last = Some((t, count + 1)); @@ -115,28 +120,65 @@ impl LimitOrderPool { if maybe_last.is_some_and(|(_, count)| count.is_zero()) { return Err(LimitOrderPoolConstructionError::LastTickHasNoNeighbor); } + Ok(()) + } + + pub fn new( + token0: Felt, + token1: Felt, + extension: Felt, + sqrt_ratio: U256, + tick: i32, + liquidity: u128, + sorted_ticks: Vec, + ) -> Result { + let key = PoolKey::new( + token0, + token1, + PoolConfig::new( + extension, + 0, + TickSpacing(LIMIT_ORDER_TICK_SPACING.unsigned_abs()), + ), + ); + + let active_tick_index = find_nearest_initialized_tick_index(&sorted_ticks, tick); + Self::validate_ticks_have_neighbors(&sorted_ticks)?; Ok(LimitOrderPool { concentrated_pool: ConcentratedPool::new( - PoolKey { - token0, - token1, - config: PoolConfig { - fee: 0, - pool_type_config: TickSpacing(LIMIT_ORDER_TICK_SPACING.unsigned_abs()), - extension, - }, - }, - ConcentratedPoolState { - sqrt_ratio, - liquidity, - active_tick_index, - }, + key, + ConcentratedPoolState::new(sqrt_ratio, liquidity, active_tick_index), sorted_ticks, ) .map_err(LimitOrderPoolConstructionError::ConcentratedPoolConstructionError)?, }) } + + #[allow(clippy::too_many_arguments)] + pub fn from_partial_data( + key: LimitOrderPoolKey, + sqrt_ratio: U256, + partial_ticks: Vec, + min_tick_searched: i32, + max_tick_searched: i32, + liquidity: u128, + current_tick: i32, + ) -> Result { + let concentrated_pool = ConcentratedPool::from_partial_data( + key, + sqrt_ratio, + partial_ticks, + min_tick_searched, + max_tick_searched, + liquidity, + current_tick, + )?; + + Self::validate_ticks_have_neighbors(concentrated_pool.ticks())?; + + Ok(Self { concentrated_pool }) + } } impl Pool for LimitOrderPool { @@ -153,10 +195,7 @@ impl Pool for LimitOrderPool { } fn state(&self) -> Self::State { - LimitOrderPoolState { - concentrated_pool_state: self.concentrated_pool.state(), - tick_indices_reached: None, - } + LimitOrderPoolState::new(self.concentrated_pool.state(), None) } fn quote( diff --git a/src/quoting/pools/mev_capture.rs b/src/quoting/pools/mev_capture.rs index ee5e128..28f2f6a 100644 --- a/src/quoting/pools/mev_capture.rs +++ b/src/quoting/pools/mev_capture.rs @@ -1,3 +1,4 @@ +use alloc::vec::Vec; use derive_more::{Add, AddAssign, Sub, SubAssign}; use num_traits::Zero; use ruint::aliases::U256; @@ -17,7 +18,7 @@ use crate::{ }; use crate::{ chain::Chain, - quoting::types::{BlockTimestamp, Pool, PoolConfig, PoolKey, Quote, QuoteParams}, + quoting::types::{BlockTimestamp, Pool, PoolConfig, PoolKey, Quote, QuoteParams, Tick}, }; use crate::{math::tick::approximate_sqrt_ratio_to_tick, quoting::types::PoolState}; @@ -53,6 +54,18 @@ pub struct MevCapturePoolState { pub concentrated_pool_state: ConcentratedPoolState, } +impl MevCapturePoolState { + pub const fn new( + last_update_time: u32, + concentrated_pool_state: ConcentratedPoolState, + ) -> Self { + Self { + last_update_time, + concentrated_pool_state, + } + } +} + /// Resources consumed during MEV-capture quote execution. #[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash, Add, AddAssign, Sub, SubAssign)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -84,6 +97,16 @@ pub enum MevCapturePoolConstructionError { InvalidCurrentTick, } +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Error)] +pub enum MevCapturePoolFromPartialDataError { + #[error("concentrated pool construction error")] + ConcentratedPoolConstructionError( + #[from] crate::quoting::pools::concentrated::ConcentratedPoolConstructionError, + ), + #[error("mev-capture pool construction error")] + MevCapturePoolConstructionError(#[from] MevCapturePoolConstructionError), +} + impl MevCapturePool { // An MEV resist pool just wraps a concentrated pool with some additional logic pub fn new( @@ -132,6 +155,30 @@ impl MevCapturePool { tick, }) } + + #[allow(clippy::too_many_arguments)] + pub fn from_partial_data( + key: MevCapturePoolKey, + sqrt_ratio: U256, + partial_ticks: Vec, + min_tick_searched: i32, + max_tick_searched: i32, + liquidity: u128, + current_tick: i32, + last_update_time: u32, + ) -> Result { + let concentrated_pool = ConcentratedPool::from_partial_data( + key, + sqrt_ratio, + partial_ticks, + min_tick_searched, + max_tick_searched, + liquidity, + current_tick, + )?; + + Self::new(concentrated_pool, last_update_time, current_tick).map_err(Into::into) + } } impl Pool for MevCapturePool { @@ -148,10 +195,7 @@ impl Pool for MevCapturePool { } fn state(&self) -> Self::State { - MevCapturePoolState { - concentrated_pool_state: self.concentrated_pool.state(), - last_update_time: self.last_update_time, - } + MevCapturePoolState::new(self.last_update_time, self.concentrated_pool.state()) } fn quote( @@ -218,10 +262,7 @@ impl Pool for MevCapturePool { }, fees_paid: quote.fees_paid, is_price_increasing: quote.is_price_increasing, - state_after: MevCapturePoolState { - last_update_time: current_time, - concentrated_pool_state: quote.state_after, - }, + state_after: MevCapturePoolState::new(current_time, quote.state_after), }) } Err(err) => Err(err), diff --git a/src/quoting/pools/mod.rs b/src/quoting/pools/mod.rs index 2d40db0..857c133 100644 --- a/src/quoting/pools/mod.rs +++ b/src/quoting/pools/mod.rs @@ -1,16 +1,16 @@ -#[cfg(any(feature = "evm", feature = "evm-alloy-0_6", feature = "evm-alloy-1"))] +#[cfg(feature = "evm")] pub mod boosted_fees; pub mod concentrated; -#[cfg(any(feature = "evm", feature = "evm-alloy-0_6", feature = "evm-alloy-1"))] +#[cfg(feature = "evm")] pub mod full_range; #[cfg(feature = "starknet")] pub mod limit_order; -#[cfg(any(feature = "evm", feature = "evm-alloy-0_6", feature = "evm-alloy-1"))] +#[cfg(feature = "evm")] pub mod mev_capture; pub mod oracle; #[cfg(feature = "starknet")] pub mod spline; -#[cfg(any(feature = "evm", feature = "evm-alloy-0_6", feature = "evm-alloy-1"))] +#[cfg(feature = "evm")] pub mod stableswap; pub mod twamm; diff --git a/src/quoting/pools/oracle.rs b/src/quoting/pools/oracle.rs index 0a9546f..21a0eaa 100644 --- a/src/quoting/pools/oracle.rs +++ b/src/quoting/pools/oracle.rs @@ -17,6 +17,15 @@ pub struct OraclePoolState { pub last_snapshot_time: u64, } +impl OraclePoolState { + pub const fn new(full_range_pool_state: S, last_snapshot_time: u64) -> Self { + Self { + full_range_pool_state, + last_snapshot_time, + } + } +} + /// Resources consumed during oracle quote execution. #[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash, Add, AddAssign, Sub, SubAssign)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -98,10 +107,7 @@ impl Pool for OraclePool { } fn state(&self) -> Self::State { - OraclePoolState { - full_range_pool_state: self.full_range_pool.state(), - last_snapshot_time: self.last_snapshot_time, - } + OraclePoolState::new(self.full_range_pool.state(), self.last_snapshot_time) } fn quote( @@ -131,10 +137,7 @@ impl Pool for OraclePool { }, fees_paid: result.fees_paid, is_price_increasing: result.is_price_increasing, - state_after: OraclePoolState { - full_range_pool_state: result.state_after, - last_snapshot_time: block_time, - }, + state_after: OraclePoolState::new(result.state_after, block_time), }) } diff --git a/src/quoting/pools/stableswap.rs b/src/quoting/pools/stableswap.rs index bfb18bc..2fccfa0 100644 --- a/src/quoting/pools/stableswap.rs +++ b/src/quoting/pools/stableswap.rs @@ -26,6 +26,15 @@ pub struct StableswapPoolTypeConfig { pub amplification_factor: u8, } +impl StableswapPoolTypeConfig { + pub const fn new(center_tick: i32, amplification_factor: u8) -> Self { + Self { + center_tick, + amplification_factor, + } + } +} + /// Stableswap pool specialized for tightly-pegged assets. #[derive(Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -109,10 +118,7 @@ impl StableswapPool { Ok(Self { key, - state: FullRangePoolState { - sqrt_ratio: state.sqrt_ratio, - liquidity: state.liquidity, - }, + state: FullRangePoolState::new(state.sqrt_ratio, state.liquidity), lower_price: { let lower_tick = center_tick - liquidity_width; @@ -257,10 +263,7 @@ impl Pool for StableswapPool { consumed_amount: amount - amount_remaining, calculated_amount, execution_resources: resources, - state_after: FullRangePoolState { - sqrt_ratio, - liquidity, - }, + state_after: FullRangePoolState::new(sqrt_ratio, liquidity), fees_paid, }) } diff --git a/src/quoting/pools/twamm.rs b/src/quoting/pools/twamm.rs index f567a1d..2830132 100644 --- a/src/quoting/pools/twamm.rs +++ b/src/quoting/pools/twamm.rs @@ -38,6 +38,22 @@ pub struct TwammPoolState { pub last_execution_time: u64, } +impl TwammPoolState { + pub const fn new( + full_range_pool_state: S, + token0_sale_rate: u128, + token1_sale_rate: u128, + last_execution_time: u64, + ) -> Self { + Self { + full_range_pool_state, + token0_sale_rate, + token1_sale_rate, + last_execution_time, + } + } +} + #[derive(Clone, Debug, Copy, Default, PartialEq, Eq, Hash, Add, AddAssign, Sub, SubAssign)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TwammStandalonePoolResources { @@ -170,12 +186,12 @@ impl Pool for TwammPool { } fn state(&self) -> Self::State { - TwammPoolState { - full_range_pool_state: self.full_range_pool.state(), - last_execution_time: self.last_execution_time, - token0_sale_rate: self.token0_sale_rate, - token1_sale_rate: self.token1_sale_rate, - } + TwammPoolState::new( + self.full_range_pool.state(), + self.token0_sale_rate, + self.token1_sale_rate, + self.last_execution_time, + ) } fn quote( diff --git a/src/quoting/types.rs b/src/quoting/types.rs index cdc8fb2..b5e0cb4 100644 --- a/src/quoting/types.rs +++ b/src/quoting/types.rs @@ -167,7 +167,25 @@ impl LastTimeInfo { } } +impl PoolConfig { + pub fn new(extension: A, fee: F, pool_type_config: C) -> Self { + Self { + extension, + fee, + pool_type_config, + } + } +} + impl PoolKey { + pub fn new(token0: A, token1: A, config: PoolConfig) -> Self { + Self { + token0, + token1, + config, + } + } + /// Convenience function to map pool type configs using their [`From`] implementations. pub fn map_into_config>(self) -> PoolKey { let Self { @@ -192,3 +210,34 @@ impl PoolKey { } } } + +impl Tick { + pub fn new(index: i32, liquidity_delta: i128) -> Self { + Self { + index, + liquidity_delta, + } + } +} + +impl TokenAmount { + pub fn new(token: A, amount: i128) -> Self { + Self { token, amount } + } +} + +impl QuoteParams { + pub fn new( + token_amount: TokenAmount, + sqrt_ratio_limit: Option, + override_state: Option, + meta: M, + ) -> Self { + Self { + token_amount, + sqrt_ratio_limit, + override_state, + meta, + } + } +}