use crate::{
constants::BASIS_POINT_MAX,
errors::DloomError,
events::AmmFeesUpdated,
state::{ProtocolConfig},
amm::{state::{AmmPool}}
};
use anchor_lang::prelude::*;
pub fn handle_update_amm_fees(
ctx: Context<UpdateAmmFees>,
new_fee_rate: Option<u16>,
) -> Result<()> {
let amm_pool = &mut ctx.accounts.amm_pool;
let now = Clock::get()?.unix_timestamp;
if let Some(manual_fee_rate) = new_fee_rate {
require!(
manual_fee_rate as u128 <= BASIS_POINT_MAX,
DloomError::InvalidFeeRates
);
amm_pool.fee_rate = manual_fee_rate;
} else {
let time_elapsed = now
.checked_sub(amm_pool.last_fee_update_timestamp)
.ok_or(DloomError::MathOverflow)?;
require!(time_elapsed > 3600, DloomError::UpdateNotNeeded);
crate::amm::instructions::swap::update_oracle(amm_pool)?;
let price_change = if amm_pool.price_a_cumulative_last_fee_update > 0 {
(amm_pool.price_a_cumulative as i128)
.checked_sub(amm_pool.price_a_cumulative_last_fee_update as i128)
.ok_or(DloomError::MathOverflow)?
.abs() as u128
} else {
0
};
let volatility = price_change.checked_div(time_elapsed as u128).unwrap_or(0);
let base_fee = 25; let dynamic_fee = (volatility / 1_000_000) as u16; let new_dynamic_rate = (base_fee + dynamic_fee).min(100);
amm_pool.fee_rate = new_dynamic_rate;
}
amm_pool.last_fee_update_timestamp = now;
amm_pool.price_a_cumulative_last_fee_update = amm_pool.price_a_cumulative;
emit!(AmmFeesUpdated {
pool_address: amm_pool.key(),
new_fee_rate: amm_pool.fee_rate,
});
Ok(())
}
#[derive(Accounts)]
pub struct UpdateAmmFees<'info> {
pub authority: Signer<'info>,
#[account(seeds = [b"protocol_config"], bump, has_one = authority)]
pub protocol_config: Account<'info, ProtocolConfig>,
#[account(mut, constraint = amm_pool.authority == authority.key() @ DloomError::Unauthorized)]
pub amm_pool: Box<Account<'info, AmmPool>>,
}