Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 110 additions & 0 deletions contracts/tradeflow/src/utils/math.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
use soroban_sdk::Env;
use super::fixed_point::*;

/// Calculates the amount out for a StableSwap invariant curve
///
/// The StableSwap invariant (similar to Curve Finance) concentrates liquidity around the $1.00 peg
/// for stablecoin pairs, drastically reducing slippage compared to constant-product AMMs.
///
/// The invariant formula is: A * (x + y) + x * y = k
/// where A is the amplification coefficient that determines how "stable" the pool behaves.
///
/// # Parameters:
/// - `amount_in`: Amount of tokens being deposited
/// - `reserve_in`: Current reserve of the input token
/// - `reserve_out`: Current reserve of the output token
/// - `amplification_coefficient`: Amplification parameter A (higher = more stable, less slippage)
///
/// # Returns:
/// - `u128`: Amount of output tokens (dummy value for now)
///
/// # Newton-Raphson Method:
/// The StableSwap curve requires solving a polynomial equation that cannot be expressed
/// in closed form. We use the Newton-Raphson iterative method to find the root:
///
/// 1. Start with an initial guess for the output amount
/// 2. Iteratively refine using: x_{n+1} = x_n - f(x_n) / f'(x_n)
/// 3. Where f(x) is the invariant equation and f'(x) is its derivative
/// 4. Continue until the change between iterations is below a tolerance threshold
///
/// The invariant we need to solve is:
/// A * (x + y) + x * y = A * (x_new + y_new) + x_new * y_new
///
/// Where x_new = x + amount_in and y_new = y - amount_out
///
/// This expands to a quadratic in terms of amount_out, which we solve iteratively.
pub fn calculate_stableswap_amount_out(
_env: &Env,
amount_in: u128,
reserve_in: u128,
reserve_out: u128,
amplification_coefficient: u128,
) -> u128 {
// Input validation - prevent division by zero and negative scenarios
if reserve_in == 0 || reserve_out == 0 {
panic!("Reserves cannot be zero");
}

if amount_in == 0 {
return 0;
}

if amplification_coefficient == 0 {
panic!("Amplification coefficient cannot be zero");
}

// TODO: Implement actual Newton-Raphson solver in future phase
// For now, return a dummy value as specified in requirements

// The dummy value is calculated as a simple proportion of the input
// This is NOT the correct StableSwap calculation, just a placeholder
let dummy_output = mul_div_down(_env, amount_in, reserve_out, reserve_in + amount_in);

dummy_output
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_stableswap_basic() {
let env = Env::default();

// Test basic scenario
let amount_in = 1000;
let reserve_in = 10000;
let reserve_out = 10000;
let amplification = 100; // Typical amplification coefficient

let result = calculate_stableswap_amount_out(&env, amount_in, reserve_in, reserve_out, amplification);

// Should return some positive amount (dummy calculation for now)
assert!(result > 0);
assert!(result < reserve_out); // Cannot withdraw more than reserve
}

#[test]
#[should_panic(expected = "Reserves cannot be zero")]
fn test_stableswap_zero_reserves() {
let env = Env::default();

calculate_stableswap_amount_out(&env, 1000, 0, 10000, 100);
}

#[test]
fn test_stableswap_zero_input() {
let env = Env::default();

let result = calculate_stableswap_amount_out(&env, 0, 10000, 10000, 100);
assert_eq!(result, 0);
}

#[test]
#[should_panic(expected = "Amplification coefficient cannot be zero")]
fn test_stableswap_zero_amplification() {
let env = Env::default();

calculate_stableswap_amount_out(&env, 1000, 10000, 10000, 0);
}
}
1 change: 1 addition & 0 deletions contracts/tradeflow/src/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod fixed_point;
pub mod math;
Loading