#[inline(always)]
pub const fn compute_fee(amount: u128, fee_basis_points: u128) -> u128 {
let whole = match (amount / 10_000).checked_mul(fee_basis_points) {
Some(value) => value,
None => return u128::MAX,
};
let remainder_product = match (amount % 10_000).checked_mul(fee_basis_points) {
Some(value) => value,
None => return u128::MAX,
};
match whole.checked_add(ceil_div(remainder_product, 10_000)) {
Some(value) => value,
None => u128::MAX,
}
}
#[inline(always)]
pub const fn ceil_div(a: u128, b: u128) -> u128 {
let quotient = a / b;
if a % b == 0 {
quotient
} else {
quotient + 1
}
}
pub const MAX_SLIPPAGE_BASIS_POINTS: u64 = 9999;
#[inline(always)]
pub const fn clamp_slippage_basis_points(basis_points: u64) -> u64 {
if basis_points > MAX_SLIPPAGE_BASIS_POINTS {
MAX_SLIPPAGE_BASIS_POINTS
} else {
basis_points
}
}
#[inline(always)]
pub const fn clamp_slippage_basis_points_u128(basis_points: u128) -> u128 {
if basis_points > MAX_SLIPPAGE_BASIS_POINTS as u128 {
MAX_SLIPPAGE_BASIS_POINTS as u128
} else {
basis_points
}
}
#[inline(always)]
pub const fn calculate_with_slippage_buy(amount: u64, basis_points: u64) -> u64 {
let bps = clamp_slippage_basis_points(basis_points);
let result = amount as u128 + (amount as u128 * bps as u128 / 10_000);
if result > u64::MAX as u128 {
u64::MAX
} else {
result as u64
}
}
#[inline(always)]
pub const fn calculate_with_slippage_sell(amount: u64, basis_points: u64) -> u64 {
if amount == 0 {
return 0;
}
let bps = clamp_slippage_basis_points(basis_points);
amount - (amount as u128 * bps as u128 / 10_000) as u64
}
#[inline(always)]
pub const fn calculate_min_amount_out(amount: u64, basis_points: u64) -> u64 {
let bps = clamp_slippage_basis_points(basis_points);
(amount as u128 * (10_000 - bps) as u128 / 10_000) as u64
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ceil_div_handles_u128_max_without_addition_overflow() {
assert_eq!(ceil_div(u128::MAX, u128::MAX), 1);
assert_eq!(ceil_div(u128::MAX, 2), u128::MAX / 2 + 1);
}
#[test]
fn compute_fee_handles_large_amounts_without_multiplication_overflow() {
assert_eq!(compute_fee(u128::MAX, 1), ceil_div(u128::MAX, 10_000));
assert_eq!(compute_fee(u128::MAX, 10_000), u128::MAX);
}
#[test]
fn slippage_helpers_are_deterministic_at_numeric_boundaries() {
assert_eq!(calculate_with_slippage_buy(u64::MAX, 100), u64::MAX);
assert_eq!(calculate_with_slippage_sell(u64::MAX, 100), 18_262_276_632_972_456_099);
assert_eq!(calculate_with_slippage_sell(10_000, u64::MAX), 1);
assert_eq!(calculate_with_slippage_sell(1, u64::MAX), 1);
}
#[test]
fn min_amount_out_uses_protocol_floor_rounding() {
assert_eq!(calculate_min_amount_out(101, 100), 99);
assert_eq!(calculate_min_amount_out(10_000, u64::MAX), 1);
assert_eq!(calculate_min_amount_out(1, u64::MAX), 0);
assert_eq!(calculate_min_amount_out(u64::MAX, 0), u64::MAX);
}
#[test]
fn clamp_slippage_basis_points_caps_at_max() {
assert_eq!(clamp_slippage_basis_points(0), 0);
assert_eq!(clamp_slippage_basis_points(100), 100);
assert_eq!(
clamp_slippage_basis_points(MAX_SLIPPAGE_BASIS_POINTS),
MAX_SLIPPAGE_BASIS_POINTS
);
assert_eq!(clamp_slippage_basis_points(10_000), MAX_SLIPPAGE_BASIS_POINTS);
assert_eq!(clamp_slippage_basis_points(u64::MAX), MAX_SLIPPAGE_BASIS_POINTS);
assert_eq!(clamp_slippage_basis_points_u128(0), 0);
assert_eq!(clamp_slippage_basis_points_u128(100), 100);
assert_eq!(clamp_slippage_basis_points_u128(10_000), MAX_SLIPPAGE_BASIS_POINTS as u128);
assert_eq!(clamp_slippage_basis_points_u128(u128::MAX), MAX_SLIPPAGE_BASIS_POINTS as u128);
}
}