use super::{position::PoolPosition, profiler::PoolProfiler};
use crate::defi::pool_analysis::snapshot::PoolSnapshot;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PoolProfilerComparison {
Match,
SqrtPriceMismatch,
Mismatch,
}
impl PoolProfilerComparison {
#[must_use]
pub const fn is_exact_match(self) -> bool {
matches!(self, Self::Match)
}
#[must_use]
pub const fn is_valid_for_snapshot(self) -> bool {
matches!(self, Self::Match | Self::SqrtPriceMismatch)
}
}
#[must_use]
pub fn compare_pool_profiler(profiler: &PoolProfiler, snapshot: &PoolSnapshot) -> bool {
compare_pool_profiler_detailed(profiler, snapshot).is_exact_match()
}
#[must_use]
pub fn compare_pool_profiler_detailed(
profiler: &PoolProfiler,
snapshot: &PoolSnapshot,
) -> PoolProfilerComparison {
assert!(profiler.is_initialized, "Profiler is not initialized");
let mut structural_match = true;
let mut sqrt_price_matches = true;
let total_ticks = snapshot.ticks.len();
let total_positions = snapshot.positions.len();
if snapshot.state.current_tick == profiler.state.current_tick {
log::info!("✓ current_tick matches: {}", snapshot.state.current_tick);
} else {
log::error!(
"Tick mismatch: profiler={}, compared={}",
profiler.state.current_tick,
snapshot.state.current_tick
);
structural_match = false;
}
if snapshot.state.price_sqrt_ratio_x96 == profiler.state.price_sqrt_ratio_x96 {
log::info!(
"✓ sqrt_price_x96 matches: {}",
profiler.state.price_sqrt_ratio_x96,
);
} else {
log::warn!(
"Sqrt ratio mismatch: profiler={}, compared={}",
profiler.state.price_sqrt_ratio_x96,
snapshot.state.price_sqrt_ratio_x96
);
sqrt_price_matches = false;
}
if snapshot.state.fee_protocol == profiler.state.fee_protocol {
log::info!("✓ fee_protocol matches: {}", snapshot.state.fee_protocol);
} else {
log::error!(
"Fee protocol mismatch: profiler={}, compared={}",
profiler.state.fee_protocol,
snapshot.state.fee_protocol
);
structural_match = false;
}
if snapshot.state.liquidity == profiler.tick_map.liquidity {
log::info!("✓ liquidity matches: {}", snapshot.state.liquidity);
} else {
log::error!(
"Liquidity mismatch: profiler={}, compared={}",
profiler.tick_map.liquidity,
snapshot.state.liquidity
);
structural_match = false;
}
let mut tick_mismatches = 0;
for tick in &snapshot.ticks {
if let Some(profiler_tick) = profiler.get_tick(tick.value) {
let mut all_tick_fields_matching = true;
if profiler_tick.liquidity_net != tick.liquidity_net {
log::error!(
"Tick {} mismatch on net liquidity: profiler={}, compared={}",
tick.value,
profiler_tick.liquidity_net,
tick.liquidity_net
);
all_tick_fields_matching = false;
}
if profiler_tick.liquidity_gross != tick.liquidity_gross {
log::error!(
"Tick {} mismatch on gross liquidity: profiler={}, compared={}",
tick.value,
profiler_tick.liquidity_gross,
tick.liquidity_gross
);
all_tick_fields_matching = false;
}
if !all_tick_fields_matching {
tick_mismatches += 1;
structural_match = false;
}
} else {
log::error!(
"Tick {} not found in the profiler but provided in the compare mapping",
tick.value
);
structural_match = false;
}
}
if tick_mismatches == 0 {
log::info!("✓ Provided {total_ticks} ticks with liquidity net and gross are matching");
}
let mut position_mismatches = 0;
for position in &snapshot.positions {
if let Some(profiler_position) =
profiler.get_position(&position.owner, position.tick_lower, position.tick_upper)
{
let position_key = PoolPosition::get_position_key(
&position.owner,
position.tick_lower,
position.tick_upper,
);
if position.liquidity != profiler_position.liquidity {
log::error!(
"Position '{}' mismatch on liquidity: profiler={}, compared={}",
position_key,
profiler_position.liquidity,
position.liquidity
);
position_mismatches += 1;
}
} else {
log::error!(
"Position {} not found in the profiler but provided in the compare mapping",
position.owner
);
structural_match = false;
}
}
if position_mismatches == 0 {
log::info!("✓ Provided {total_positions} active positions with liquidity are matching");
} else {
structural_match = false;
}
if structural_match && sqrt_price_matches {
PoolProfilerComparison::Match
} else if structural_match {
log::warn!("Pool profiler sqrt ratio differs, but all structural state matches");
PoolProfilerComparison::SqrtPriceMismatch
} else {
PoolProfilerComparison::Mismatch
}
}