use super::{BondingCurve, OperationSide};
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct LogarithmicBondingCurve {
pub base: f64,
pub growth: f64,
}
impl LogarithmicBondingCurve {
pub fn new(base: f64, growth: f64) -> Self {
Self { base, growth }
}
}
impl BondingCurve<f64> for LogarithmicBondingCurve {
fn calculate_price(&self, supply: u64) -> f64 {
if supply == 0 {
return self.base; }
self.growth * (supply as f64).ln() + self.base
}
fn calculate_price_many(&self, starting_supply: u64, amount: u64, side: OperationSide) -> f64 {
let start = starting_supply as f64;
let end = match side {
OperationSide::Add => (starting_supply + amount) as f64,
OperationSide::Remove => (starting_supply - amount) as f64,
};
let integral = |x: f64| self.growth * x * x.ln() - self.growth * x + self.base * x;
let price = match side {
OperationSide::Add => integral(end) - integral(start),
OperationSide::Remove => integral(start) - integral(end),
};
if starting_supply == 0 && side == OperationSide::Add {
price + self.base } else {
price
}
}
}
#[cfg(test)]
mod test {
use crate::{
fixed_point_to_float, float_to_fixed_point, BondingCurve, LogarithmicBondingCurve,
OperationSide,
};
#[test]
pub fn test_logarithmic_price_calculus() {
let curve = LogarithmicBondingCurve::new(0.02, 0.01);
let price = curve.calculate_price(100);
assert_eq!(price, 0.06605170185988092);
}
#[test]
pub fn test_logarithmic_price_calculus_fixed_point() {
let base = fixed_point_to_float(2, 2);
let growth = fixed_point_to_float(1, 2);
let curve = LogarithmicBondingCurve::new(base, growth);
let price = curve.calculate_price(100);
assert_eq!(float_to_fixed_point(price, 9), 0_066_051_701);
}
#[test]
pub fn test_logarithmic_price_calculus_many() {
let curve = LogarithmicBondingCurve::new(0.02, 0.01);
let price_add = curve.calculate_price_many(100, 10, OperationSide::Add);
assert_eq!(price_add, 0.6653582163835674);
let price_remove = curve.calculate_price_many(100, 10, OperationSide::Remove);
assert_eq!(price_remove, 0.6553414826908526);
}
}