diff --git a/src/chain/evm.rs b/src/chain/evm.rs index 5b85457..5711232 100644 --- a/src/chain/evm.rs +++ b/src/chain/evm.rs @@ -1,5 +1,6 @@ use crate::alloy_primitives::{Address, B256, FixedBytes, U256, aliases::B32, fixed_bytes}; use crate::alloy_primitives::{Keccak256, uint}; +use crate::quoting::util::real_last_time; use derive_more::From; use num_traits::Zero as _; use thiserror::Error; @@ -327,6 +328,13 @@ impl Chain for Evm { }, ) } + + fn real_last_virtual_order_execution_time( + block_timestamp: u64, + last_execution_time: u64, + ) -> u64 { + real_last_time(block_timestamp, last_execution_time as u32) + } } impl EvmPoolKey { diff --git a/src/chain/mod.rs b/src/chain/mod.rs index 393f8cc..e6df2cf 100644 --- a/src/chain/mod.rs +++ b/src/chain/mod.rs @@ -48,6 +48,11 @@ pub trait Chain: sqrt_ratio: U256, active_liquidity: u128, ) -> Result; + + fn real_last_virtual_order_execution_time( + block_timestamp: u64, + last_execution_time: u64, + ) -> u64; } #[cfg(test)] diff --git a/src/chain/starknet.rs b/src/chain/starknet.rs index b8f5a3f..ce6dfee 100644 --- a/src/chain/starknet.rs +++ b/src/chain/starknet.rs @@ -236,6 +236,14 @@ impl Chain for Starknet { } type Address = Felt; + + fn real_last_virtual_order_execution_time( + _block_timestamp: u64, + last_execution_time: u64, + ) -> u64 { + // We store the untruncated u64 on Starknet + last_execution_time + } } impl private::Sealed for Starknet {} diff --git a/src/quoting/pools/twamm.rs b/src/quoting/pools/twamm.rs index a54a786..d411327 100644 --- a/src/quoting/pools/twamm.rs +++ b/src/quoting/pools/twamm.rs @@ -214,16 +214,14 @@ impl Pool for TwammPool { } = params; let current_time = meta; - let initial_state = override_state.unwrap_or_else(|| self.state()); - - let mut next_sqrt_ratio = initial_state.full_range_pool_state.sqrt_ratio(); - let mut token0_sale_rate = initial_state.token0_sale_rate; - let mut token1_sale_rate = initial_state.token1_sale_rate; - let last_execution_time = initial_state.last_execution_time; + let TwammPoolState { + full_range_pool_state, + mut token0_sale_rate, + mut token1_sale_rate, + last_execution_time, + } = override_state.unwrap_or_else(|| self.state()); - if current_time < last_execution_time { - return Err(TwammPoolQuoteError::ExecutionTimeExceedsBlockTime); - } + let mut next_sqrt_ratio = full_range_pool_state.sqrt_ratio(); let mut virtual_order_delta_times_crossed = 0; let mut full_range_pool_state_override = override_state.map(|s| s.full_range_pool_state); @@ -236,6 +234,13 @@ impl Pool for TwammPool { config: PoolConfig { fee, .. }, } = self.full_range_pool.key(); + let last_execution_time = + C::real_last_virtual_order_execution_time(current_time, last_execution_time); + + if current_time < last_execution_time { + return Err(TwammPoolQuoteError::ExecutionTimeExceedsBlockTime); + } + let mut time = last_execution_time; for sale_rate_delta in self @@ -362,13 +367,11 @@ impl Pool for TwammPool { full_range: full_range_pool_execution_resources + final_quote.execution_resources, twamm: TwammStandalonePoolResources { extra_distinct_bitmap_lookups: approximate_extra_distinct_time_bitmap_lookups( - initial_state.last_execution_time, + last_execution_time, current_time, ), virtual_order_delta_times_crossed, - virtual_orders_executed: u32::from( - current_time > initial_state.last_execution_time, - ), + virtual_orders_executed: u32::from(current_time > last_execution_time), }, }, state_after: TwammPoolState { @@ -1654,6 +1657,38 @@ mod tests { .unwrap(); }); + #[test] + fn evm_quote_uses_truncated_last_execution_time() { + let last_execution_time = 100; + let current_time = last_execution_time + (1u64 << 32); + + let pool = build_pool::( + to_sqrt_ratio::(1).unwrap(), + 0, + last_execution_time, + 0, + 0, + vec![], + ); + + let quote = pool + .quote(QuoteParams { + token_amount: TokenAmount { + amount: 0, + token: Evm::zero_address(), + }, + sqrt_ratio_limit: None, + meta: current_time, + override_state: None, + }) + .unwrap(); + + // The untruncated time is updated... + assert_eq!(quote.state_after.last_execution_time, current_time); + // ...but since the u32 suffix of the last_execution_time and the current_time match, orders aren't executed + assert_eq!(quote.execution_resources.twamm.virtual_orders_executed, 0); + } + #[test] fn example_from_production_sepolia() { let pool = TwammPool::::new(