use crate::instruction::utils::raydium_cpmm::accounts::{
CREATOR_FEE_RATE, FEE_RATE_DENOMINATOR_VALUE, FUND_FEE_RATE, PROTOCOL_FEE_RATE, TRADE_FEE_RATE,
};
#[inline(always)]
fn compute_trading_fee(amount: u64, fee_rate: u64) -> u64 {
let numerator = (amount as u128) * (fee_rate as u128);
((numerator + FEE_RATE_DENOMINATOR_VALUE - 1) / FEE_RATE_DENOMINATOR_VALUE) as u64
}
#[inline(always)]
fn compute_protocol_fund_fee(amount: u64, fee_rate: u64) -> u64 {
let numerator = (amount as u128) * (fee_rate as u128);
(numerator / FEE_RATE_DENOMINATOR_VALUE) as u64
}
#[inline(always)]
fn compute_creator_fee_new(amount: u64, fee_rate: u64) -> u64 {
let numerator = (amount as u128) * (fee_rate as u128);
((numerator + FEE_RATE_DENOMINATOR_VALUE - 1) / FEE_RATE_DENOMINATOR_VALUE) as u64
}
#[derive(Debug, Clone)]
pub struct ComputeSwapParams {
pub all_trade: bool,
pub amount_in: u64,
pub amount_out: u64,
pub min_amount_out: u64,
pub fee: u64,
}
#[derive(Debug, Clone)]
pub struct SwapResult {
pub new_input_vault_amount: u64,
pub new_output_vault_amount: u64,
pub input_amount: u64,
pub output_amount: u64,
pub trade_fee: u64,
pub protocol_fee: u64,
pub fund_fee: u64,
pub creator_fee: u64,
}
#[inline]
fn swap_base_input(
input_amount: u64,
input_vault_amount: u64,
output_vault_amount: u64,
trade_fee_rate: u64,
creator_fee_rate: u64,
protocol_fee_rate: u64,
fund_fee_rate: u64,
is_creator_fee_on_input: bool,
) -> SwapResult {
let mut creator_fee = 0u64;
let trade_fee = compute_trading_fee(input_amount, trade_fee_rate);
let input_amount_less_fees = if is_creator_fee_on_input {
creator_fee = compute_creator_fee_new(input_amount, creator_fee_rate);
input_amount.saturating_sub(trade_fee).saturating_sub(creator_fee)
} else {
input_amount.saturating_sub(trade_fee)
};
let protocol_fee = compute_protocol_fund_fee(trade_fee, protocol_fee_rate);
let fund_fee = compute_protocol_fund_fee(trade_fee, fund_fee_rate);
let output_amount_swapped = ((output_vault_amount as u128)
.saturating_mul(input_amount_less_fees as u128)
/ (input_vault_amount as u128).saturating_add(input_amount_less_fees as u128))
as u64;
let output_amount = if is_creator_fee_on_input {
output_amount_swapped
} else {
creator_fee = compute_creator_fee_new(output_amount_swapped, creator_fee_rate);
output_amount_swapped.saturating_sub(creator_fee)
};
SwapResult {
new_input_vault_amount: input_vault_amount.saturating_add(input_amount_less_fees),
new_output_vault_amount: output_vault_amount.saturating_sub(output_amount_swapped),
input_amount,
output_amount,
trade_fee,
protocol_fee,
fund_fee,
creator_fee,
}
}
#[inline]
pub fn compute_swap_amount(
base_reserve: u64,
quote_reserve: u64,
is_base_in: bool,
amount_in: u64,
slippage_basis_points: u64,
) -> ComputeSwapParams {
let (input_reserve, output_reserve) =
if is_base_in { (base_reserve, quote_reserve) } else { (quote_reserve, base_reserve) };
let swap_result = swap_base_input(
amount_in,
input_reserve,
output_reserve,
TRADE_FEE_RATE,
CREATOR_FEE_RATE,
PROTOCOL_FEE_RATE,
FUND_FEE_RATE,
true,
);
let min_amount_out = ((swap_result.output_amount as f64)
* (1.0 - (slippage_basis_points as f64) / 10000.0)) as u64;
let all_trade = swap_result.input_amount == amount_in;
ComputeSwapParams {
all_trade,
amount_in,
amount_out: swap_result.output_amount,
min_amount_out,
fee: swap_result.trade_fee,
}
}