Skip to content

Commit

Permalink
feat: adds more docs
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinrodriguez-io committed Sep 5, 2024
1 parent 0c61a85 commit b62021e
Show file tree
Hide file tree
Showing 10 changed files with 476 additions and 41 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@ Note: Version 0 of Semantic Versioning is handled differently from version 1 and

### Breaking

## [1.0.0] - 2024-09-05

### Features

- Added `calculate_price_many` and `calculate_price_many_checked` to all bonding curves.

### Fixes

### Breaking

- Removed "lossy" suffix on `f64` curves: Exponential, Logarithmic, and Sigmoid.

## [0.1.0] - 2024-08-21

### Features
Expand Down
18 changes: 0 additions & 18 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion crates/magic-curves/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,3 @@ keywords = ["blockchain", "financial", "solana", "defi", "finance"]
categories = ["finance", "cryptography"]

[dependencies]
num-traits = "^0.2.19"
60 changes: 60 additions & 0 deletions crates/magic-curves/src/core/exponential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,82 @@ use std::f64::consts::E;

use super::{BondingCurve, OperationSide};

/// Represents an exponential bonding curve.
///
/// This struct defines an exponential bonding curve with a base price and a growth rate.
///
/// # Fields
///
/// * `base`: The base price, which is the initial price for the first token.
/// * `growth`: The growth rate that determines how quickly the price increases.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct ExponentialBondingCurve {
pub base: f64,
pub growth: f64,
}

impl ExponentialBondingCurve {
/// Creates a new `ExponentialBondingCurve` with the specified base price and growth rate.
///
/// # Arguments
///
/// * `base` - The base price, which is the initial price for the first token.
/// * `growth` - The growth rate that determines how quickly the price increases.
///
/// # Returns
///
/// A new instance of `ExponentialBondingCurve`.
///
/// # Example
///
/// ```
/// use magic_curves::ExponentialBondingCurve;
///
/// let curve = ExponentialBondingCurve::new(0.01, 0.02);
/// ```
pub fn new(base: f64, growth: f64) -> Self {
Self { base, growth }
}
}

impl BondingCurve<f64> for ExponentialBondingCurve {
/// Calculates the price based on the supply.
///
/// # Formula
///
/// ```ignore
/// f(x) = base * e^(growth * x)
/// ```
///
/// # Arguments
///
/// * `supply` - The current supply of tokens.
///
/// # Returns
///
/// The price of the token based on the supply.
fn calculate_price(&self, supply: u64) -> f64 {
self.base * E.powf(self.growth * supply as f64)
}

/// Calculates the price for a given amount of tokens.
///
/// # Formula
///
/// The integral of the exponential function is used:
/// ```ignore
/// F(x) = (base / growth) * (e^(growth * x) - e^(growth * start))
/// ```
///
/// # Arguments
///
/// * `starting_supply` - The current supply of tokens.
/// * `amount` - The amount of tokens to calculate the price for.
/// * `side` - The side of the operation (add or remove).
///
/// # Returns
///
/// The total price for the given amount of tokens.
fn calculate_price_many(&self, starting_supply: u64, amount: u64, side: OperationSide) -> f64 {
let start = starting_supply as f64;
let end = match side {
Expand Down
84 changes: 84 additions & 0 deletions crates/magic-curves/src/core/linear.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,85 @@
use super::{BondingCurve, BondingCurveError, BondingCurveWithCheckedOperations, OperationSide};

/// Represents a linear bonding curve.
///
/// This struct defines a linear bonding curve with a linear coefficient and a base price.
///
/// # Fields
///
/// * `linear`: The linear coefficient that determines the rate of price increase.
/// * `base`: The base price, which is the minimum price for the first token.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct LinearBondingCurve {
pub linear: u64,
pub base: u64,
}

impl LinearBondingCurve {
/// Creates a new `LinearBondingCurve` with the specified linear coefficient and base price.
///
/// # Arguments
///
/// * `linear` - The linear coefficient that determines the rate of price increase.
/// * `base` - The base price, which is the minimum price for the first token.
///
/// # Returns
///
/// A new instance of `LinearBondingCurve`.
///
/// # Example
///
/// ```
/// use magic_curves::LinearBondingCurve;
///
/// let curve = LinearBondingCurve::new(100, 1000);
/// ```
pub fn new(linear: u64, base: u64) -> Self {
Self { linear, base }
}
}

impl BondingCurve<u64> for LinearBondingCurve {
/// Calculates the price based on the supply.
///
/// # Formula
///
/// ```ignore
/// f(x) = linear * x + base
/// ```
///
/// # Arguments
///
/// * `supply` - The current supply of tokens.
///
/// # Returns
///
/// The price of the token based on the supply.
fn calculate_price(&self, supply: u64) -> u64 {
self.linear * supply + self.base
}

/// Calculates the price for a given amount of tokens.
///
/// # Formula
///
/// ```ignore
/// f(x) = (amount * (a1 + an)) / 2
/// ```
///
/// where:
///
/// - a1 = linear * starting_supply + base
/// - an = linear * (starting_supply + amount - 1) + base
///
/// # Arguments
///
/// * `starting_supply` - The current supply of tokens.
/// * `amount` - The amount of tokens to calculate the price for.
/// * `side` - The side of the operation (add or remove).
///
/// # Returns
///
/// The total price for the given amount of tokens.
fn calculate_price_many(&self, starting_supply: u64, amount: u64, side: OperationSide) -> u64 {
let a1 = self.linear * starting_supply + self.base;
let an = match side {
Expand All @@ -27,6 +91,15 @@ impl BondingCurve<u64> for LinearBondingCurve {
}

impl BondingCurveWithCheckedOperations<u64> for LinearBondingCurve {
/// Calculates the price based on the supply.
///
/// # Arguments
///
/// * `supply` - The current supply of tokens.
///
/// # Returns
///
/// The price of the token based on the supply. If the operation would cause an overflow, it returns an error.
fn calculate_price_checked(&self, supply: u64) -> Result<u64, BondingCurveError> {
let result = self
.linear
Expand All @@ -36,6 +109,17 @@ impl BondingCurveWithCheckedOperations<u64> for LinearBondingCurve {
result.ok_or(BondingCurveError::Overflow)
}

/// Calculates the price for a given amount of tokens.
///
/// # Arguments
///
/// * `starting_supply` - The current supply of tokens.
/// * `amount` - The amount of tokens to calculate the price for.
/// * `side` - The side of the operation (add or remove).
///
/// # Returns
///
/// The total price for the given amount of tokens. If the operation would cause an overflow, it returns an error.
fn calculate_price_many_checked(
&self,
starting_supply: u64,
Expand Down
79 changes: 66 additions & 13 deletions crates/magic-curves/src/core/logarithmic.rs
Original file line number Diff line number Diff line change
@@ -1,49 +1,102 @@
use super::BondingCurve;
use super::{BondingCurve, OperationSide};

/// Represents a logarithmic bonding curve.
///
/// This struct defines a logarithmic bonding curve with a base price and a growth rate.
///
/// # Fields
///
/// * `base`: The base price, which is the initial price for the first token.
/// * `growth`: The growth rate that determines how quickly the price increases.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct LogarithmicBondingCurve {
pub base: f64,
pub growth: f64,
}

impl LogarithmicBondingCurve {
/// Creates a new `LogarithmicBondingCurve` with the specified base price and growth rate.
///
/// # Arguments
///
/// * `base` - The base price, which is the initial price for the first token.
/// * `growth` - The growth rate that determines how quickly the price increases.
///
/// # Returns
///
/// A new instance of `LogarithmicBondingCurve`.
///
/// # Example
///
/// ```
/// use magic_curves::LogarithmicBondingCurve;
///
/// let curve = LogarithmicBondingCurve::new(0.02, 0.01);
/// ```
pub fn new(base: f64, growth: f64) -> Self {
Self { base, growth }
}
}

impl BondingCurve<f64> for LogarithmicBondingCurve {
/// Calculates the price based on the supply.
///
/// # Formula
///
/// ```ignore
/// f(x) = growth * ln(x) + base
/// ```
///
/// # Arguments
///
/// * `supply` - The current supply of tokens.
///
/// # Returns
///
/// The price of the token based on the supply.
fn calculate_price(&self, supply: u64) -> f64 {
if supply == 0 {
return self.base; // Avoid taking the log of 0
}
self.growth * (supply as f64).ln() + self.base
}

fn calculate_price_many(
&self,
starting_supply: u64,
amount: u64,
side: super::OperationSide,
) -> f64 {
/// Calculates the price for a given amount of tokens.
///
/// # Formula
///
/// The integral of the logarithmic function is used:
/// ```ignore
/// F(x) = growth * x * ln(x) - growth * x + base * x
/// ```
///
/// # Arguments
///
/// * `starting_supply` - The current supply of tokens.
/// * `amount` - The amount of tokens to calculate the price for.
/// * `side` - The side of the operation (add or remove).
///
/// # Returns
///
/// The total price for the given amount of tokens.
fn calculate_price_many(&self, starting_supply: u64, amount: u64, side: OperationSide) -> f64 {
let start = starting_supply as f64;
let end = match side {
super::OperationSide::Add => (starting_supply + amount) as f64,
super::OperationSide::Remove => (starting_supply - amount) as f64,
OperationSide::Add => (starting_supply + amount) as f64,
OperationSide::Remove => (starting_supply - amount) as f64,
};

// Calculate the integral of the logarithmic function
// The integral of (a * ln(x) + b) is (a * x * ln(x) - a * x + b * x)
let integral = |x: f64| self.growth * x * x.ln() - self.growth * x + self.base * x;

// Calculate the difference between the integrals at the end and start points
let price = match side {
super::OperationSide::Add => integral(end) - integral(start),
super::OperationSide::Remove => integral(start) - integral(end),
OperationSide::Add => integral(end) - integral(start),
OperationSide::Remove => integral(start) - integral(end),
};

// Handle the case where starting_supply is 0 for Add operation
if starting_supply == 0 && side == super::OperationSide::Add {
if starting_supply == 0 && side == OperationSide::Add {
price + self.base // Add base price for the first token
} else {
price
Expand Down
Loading

0 comments on commit b62021e

Please sign in to comment.