solana_central/meteora/calculate_base_fee_numerator.rs
1use crate::CentralContext;
2use crate::types::meteora_dammv2_pool::MeteoraDammV2Pool;
3use std::cmp;
4use std::sync::Arc;
5use std::time::{SystemTime, UNIX_EPOCH};
6
7impl MeteoraDammV2Pool {
8 /// Calculate the base fee numerator for DAMMv2 pools with fee scheduling
9 ///
10 /// Supports multiple fee modes:
11 /// - Linear decay: Fee decreases linearly over periods
12 /// - Exponential decay: Fee decreases exponentially over periods
13 /// - Rate limiter: Not yet implemented, returns cliff fee
14 ///
15 /// The calculation is based on the activation point and elapsed time/slots since activation.
16 pub fn calculate_base_fee_numerator(&self, central_context: &Arc<CentralContext>) -> u64 {
17 // Decode overloaded fields based on base_fee_mode
18 match self.base_fee_mode {
19 0 | 1 => {
20 // Fee Scheduler modes (Linear or Exponential)
21 let number_of_period = self.first_factor;
22 let period_frequency = u64::from_le_bytes(self.second_factor);
23 let reduction_factor = self.third_factor;
24
25 // If period frequency is 0, return cliff fee
26 if period_frequency == 0 {
27 return self.cliff_fee_numerator;
28 }
29
30 // Determine current point based on activation type
31 let current_point = match self.activation_type {
32 // Slot-based timing
33 0 => *central_context.current_slot.read().unwrap(),
34 // Timestamp-based timing (in seconds)
35 1 => SystemTime::now()
36 .duration_since(UNIX_EPOCH)
37 .unwrap()
38 .as_secs(),
39 // Default to slot-based
40 _ => *central_context.current_slot.read().unwrap(),
41 };
42
43 // Check if we've reached the activation point
44 if current_point < self.activation_point {
45 return self.cliff_fee_numerator;
46 }
47
48 let periods_passed = cmp::min(
49 number_of_period as u64,
50 (current_point - self.activation_point) / period_frequency,
51 );
52
53 match self.base_fee_mode {
54 0 => {
55 // Linear: cliff_fee_numerator - (period * reduction_factor)
56 let reduction = periods_passed * reduction_factor;
57 if reduction >= self.cliff_fee_numerator {
58 0
59 } else {
60 self.cliff_fee_numerator - reduction
61 }
62 }
63 1 => {
64 // Exponential: cliff_fee_numerator * (1 - reduction_factor/BASIS_POINT_MAX)^period
65 let reduction_rate = reduction_factor as f64 / 10000f64;
66 let decay_factor = (1.0 - reduction_rate).powi(periods_passed as i32);
67 (self.cliff_fee_numerator as f64 * decay_factor) as u64
68 }
69 _ => unreachable!(),
70 }
71 }
72 2 => {
73 // Rate Limiter mode - not implemented yet
74 // Would need to decode: fee_increment_bps, max_limiter_duration, max_fee_bps, reference_amount
75 // For now, return cliff fee
76 self.cliff_fee_numerator
77 }
78 // Default to cliff fee for unknown modes
79 _ => self.cliff_fee_numerator,
80 }
81 }
82}