use crate::common::constants::WAD;
use crate::common::errors::PoolError;
use crate::common::maths::{
complement_fixed, div_down_fixed, div_up_fixed, mul_down_fixed, mul_up_fixed, pow_down_fixed,
pow_up_fixed,
};
use alloy_primitives::{uint, U256};
pub const MIN_WEIGHT: U256 = uint!(10000000000000000_U256);
pub const MAX_IN_RATIO: U256 = uint!(300000000000000000_U256); pub const MAX_OUT_RATIO: U256 = uint!(300000000000000000_U256);
pub const MAX_INVARIANT_RATIO: U256 = uint!(3000000000000000000_U256); pub const MIN_INVARIANT_RATIO: U256 = uint!(700000000000000000_U256);
pub fn compute_invariant_down(
normalized_weights: &[U256],
balances: &[U256],
) -> Result<U256, PoolError> {
let mut invariant = WAD;
for i in 0..normalized_weights.len() {
let pow_result = pow_down_fixed(&balances[i], &normalized_weights[i])?;
invariant = mul_down_fixed(&invariant, &pow_result)?;
}
if invariant == U256::ZERO {
return Err(PoolError::ZeroInvariant);
}
Ok(invariant)
}
pub fn compute_invariant_up(
normalized_weights: &[U256],
balances: &[U256],
) -> Result<U256, PoolError> {
let mut invariant = WAD;
for i in 0..normalized_weights.len() {
invariant = mul_up_fixed(
&invariant,
&pow_up_fixed(&balances[i], &normalized_weights[i])?,
)?;
}
if invariant == U256::ZERO {
return Err(PoolError::ZeroInvariant);
}
Ok(invariant)
}
pub fn compute_out_given_exact_in(
balance_in: &U256,
weight_in: &U256,
balance_out: &U256,
weight_out: &U256,
amount_in: &U256,
) -> Result<U256, PoolError> {
if amount_in > &mul_down_fixed(balance_in, &MAX_IN_RATIO)? {
return Err(PoolError::MaxInRatioExceeded);
}
let denominator = balance_in + amount_in;
let base = div_up_fixed(balance_in, &denominator)?;
let exponent = div_down_fixed(weight_in, weight_out)?;
let power = pow_up_fixed(&base, &exponent)?;
mul_down_fixed(balance_out, &complement_fixed(&power)?)
}
pub fn compute_in_given_exact_out(
balance_in: &U256,
weight_in: &U256,
balance_out: &U256,
weight_out: &U256,
amount_out: &U256,
) -> Result<U256, PoolError> {
if amount_out > &mul_down_fixed(balance_out, &MAX_OUT_RATIO)? {
return Err(PoolError::MaxOutRatioExceeded);
}
let base = div_up_fixed(balance_out, &(balance_out - amount_out))?;
let exponent = div_up_fixed(weight_out, weight_in)?;
let power = pow_up_fixed(&base, &exponent)?;
let ratio = power - WAD;
mul_up_fixed(balance_in, &ratio)
}
pub fn compute_balance_out_given_invariant(
current_balance: &U256,
weight: &U256,
invariant_ratio: &U256,
) -> Result<U256, PoolError> {
let balance_ratio = pow_up_fixed(invariant_ratio, &div_up_fixed(&WAD, weight)?)?;
mul_up_fixed(current_balance, &balance_ratio)
}