From 7e0a7454b8e7390d648c20fbbe30a4ef979093ad Mon Sep 17 00:00:00 2001 From: betterclever Date: Fri, 23 Feb 2024 14:13:18 +0530 Subject: [PATCH] integer based invariant calculation --- contracts/pools/stable_pool/src/math.rs | 67 ++++++++++--------- .../pools/stable_pool/tests/integration.rs | 14 ++-- .../stable_pool/tests/test_scaling_factor.rs | 4 +- contracts/vault/tests/pool_exit.rs | 6 +- 4 files changed, 47 insertions(+), 44 deletions(-) diff --git a/contracts/pools/stable_pool/src/math.rs b/contracts/pools/stable_pool/src/math.rs index 3e154d88..d61092c7 100644 --- a/contracts/pools/stable_pool/src/math.rs +++ b/contracts/pools/stable_pool/src/math.rs @@ -1,3 +1,5 @@ +use std::ops::Div; + use cosmwasm_std::{Decimal256, StdError, StdResult, Uint128, Uint256, Uint64}; use dexter::asset::{AssetInfo, Decimal256Ext, DecimalAsset}; use dexter::error::ContractError; @@ -39,50 +41,44 @@ pub(crate) fn compute_d( return Ok(Decimal256::zero()); } - // Sum of all the pools liquidity, Eq - xp: [1242000000, 1542000000, 1456000000] = 4240000000 - let sum_x = pools.iter().fold(Decimal256::zero(), |acc, x| acc + (*x)); + let sum_x = pools.iter().fold(Uint256::zero(), |acc, x| acc + x.atomics()); let n_coins = pools.len() as u8; - - // ann = amp * n Eq - 100 * 3 = 300 - let ann = Decimal256::from_integer(amp.checked_mul(n_coins.into())?.u64() / AMP_PRECISION); - let n_coins = Uint64::from(n_coins); + let ann = Uint256::from(amp.u64().div(AMP_PRECISION) * n_coins as u64); + let n_coins = Uint256::from(n_coins as u64); // Initial D = sum_x, which is the sum of all the pools liquidity let mut d = sum_x; - - // ann_sum_x = ann * sum_x - let ann_sum_x = ann * sum_x; + let ann_sum_x = ann.checked_mul(sum_x)?; // while abs(D - Dprev) > 1: for _ in 0..ITERATIONS { - // Start loop: D_P = D_P * D / (_x * N_COINS) - let d_p = pools - .iter() - .try_fold::<_, _, StdResult<_>>(d, |acc, pool| { - let denominator = pool.atomics().checked_mul(n_coins.into())?; - let print_calc_ = acc.checked_multiply_ratio(d, Decimal256::new(denominator)); - print_calc_ - })?; + + let mut dp = d; + for (_, pool) in pools.iter().enumerate() { + let denominator = pool.atomics().checked_mul(n_coins.into())?; + let fraction = (d, denominator); + dp = dp.checked_mul_floor(fraction).unwrap(); + } let d_prev = d; + + let numerator = (ann_sum_x + dp.checked_mul(n_coins).unwrap()).checked_mul(d)?; + let denominator = (ann - Uint256::one()).checked_mul(d)? + .checked_add(n_coins.checked_add(Uint256::one())?.checked_mul(dp)?)?; - d = (ann_sum_x + d_p * Decimal256::from_integer(n_coins.u64())) * d - / ((ann - Decimal256::one()) * d - + (Decimal256::from_integer(n_coins.u64()) + Decimal256::one()) * d_p); + d = numerator.checked_div(denominator)?; if d >= d_prev { - if d - d_prev <= Decimal256::with_precision(Uint64::from(1u8), Decimal256::DECIMAL_PLACES)? - { - return Ok(d); + if d - d_prev <= Uint256::from(1u8) { + return Ok(Decimal256::from_atomics(d, Decimal256::DECIMAL_PLACES).unwrap()); } - } else if d_prev - d <= Decimal256::with_precision(Uint64::from(1u8), Decimal256::DECIMAL_PLACES)? - { - return Ok(d); + } else if d_prev - d <= Uint256::from(1u8) { + return Ok(Decimal256::from_atomics(d, Decimal256::DECIMAL_PLACES).unwrap()); } } - Ok(d) + Ok(Decimal256::from_atomics(d, Decimal256::DECIMAL_PLACES).unwrap()) } /// ## Description @@ -109,12 +105,12 @@ pub(crate) fn calc_y( let n_coins = Uint64::from(pools.len() as u8); let ann = Uint256::from(amp.checked_mul(n_coins)?.u64() / AMP_PRECISION); - let mut sum = Decimal256::zero(); + let mut sum = Uint256::zero(); let pool_values = pools.iter().map(|asset| asset.amount).collect_vec(); // d is computed with the largest precision possible i.e Decimal256::DECIMAL_PLACES i.e 18 - let d = compute_d(amp, &pool_values)? - .to_uint256_with_precision(Decimal256::DECIMAL_PLACES)?; + let d = compute_d(amp, &pool_values)?.to_uint256_with_precision(Decimal256::DECIMAL_PLACES)?; + // println!("d: {:?}", d); let mut c = d; @@ -132,27 +128,31 @@ pub(crate) fn calc_y( pool_amount.to_uint256_with_precision(Decimal256::DECIMAL_PLACES)? * Uint256::from(n_coins), ) .map_err(|_| StdError::generic_err("CheckedMultiplyRatioError"))?; - sum += pool_amount; + sum += pool_amount.to_uint256_with_precision(Decimal256::DECIMAL_PLACES)?; } let c = c * d / (ann * Uint256::from(n_coins)); - let sum = sum.to_uint256_with_precision(Decimal256::DECIMAL_PLACES)?; + // let sum = sum.to_uint256_with_precision(Decimal256::DECIMAL_PLACES)?; let b = sum + d / ann; let mut y = d; + // println!("y: {}", y); let d = y; for _ in 0..ITERATIONS { let y_prev = y; y = (y * y + c) / (y + y + b - d); + // println!("iter: {}, y_new: {}", iter, y); if y >= y_prev { if y - y_prev <= Uint256::from(1u8) { // We need to scale the value from the MAX_PRECISION to the precision of the asset // We do this by dividing the value by the ratio of the two precisions let decimal_difference = Decimal256::DECIMAL_PLACES - output_precision as u32; // this is safe because ask_asset_precision is always <= 18 + // println!("decimal_difference: {}", decimal_difference); + let precision_ratio = Uint256::from(10u8).pow(decimal_difference as u32); let y = y.checked_div(precision_ratio)?; @@ -162,6 +162,8 @@ pub(crate) fn calc_y( // We need to scale the value from the MAX_PRECISION to the precision of the asset // We do this by dividing the value by the ratio of the two precisions let decimal_difference = Decimal256::DECIMAL_PLACES - output_precision as u32; // this is safe because ask_asset_precision is always <= 18 + // println!("decimal_difference: {}", decimal_difference); + let precision_ratio = Uint256::from(10u8).pow(decimal_difference as u32); let y = y.checked_div(precision_ratio)?; return Ok(y.try_into()?); @@ -174,6 +176,7 @@ pub(crate) fn calc_y( #[cfg(test)] mod tests { + use super::*; use dexter::asset::native_asset; use sim::StableSwapModel; diff --git a/contracts/pools/stable_pool/tests/integration.rs b/contracts/pools/stable_pool/tests/integration.rs index d953a982..095f99dd 100644 --- a/contracts/pools/stable_pool/tests/integration.rs +++ b/contracts/pools/stable_pool/tests/integration.rs @@ -764,7 +764,7 @@ fn test_query_on_join_pool() { ) .unwrap(); assert_eq!(ResponseType::Success {}, join_pool_query_res.response); - assert_eq!(Uint128::from(217_995_261_723_832u128), join_pool_query_res.new_shares); + assert_eq!(Uint128::from(217_995_261_723_840u128), join_pool_query_res.new_shares); // Execute AddLiquidity via the Vault contract let msg = VaultExecuteMsg::JoinPool { @@ -806,7 +806,7 @@ fn test_query_on_join_pool() { }, ) .unwrap(); - assert_eq!(Uint128::from(217_995_261_723_832u128), recepient_bal_res.balance); + assert_eq!(Uint128::from(217_995_261_723_840u128), recepient_bal_res.balance); let vault_bal_res: BalanceResponse = app .wrap() @@ -950,7 +950,7 @@ fn test_query_on_join_pool() { .unwrap(); assert_eq!(ResponseType::Success {}, join_pool_query_res.response); assert_eq!( - Uint128::from(3686487023559690549804u128), + Uint128::from(3686487023559696294465u128), join_pool_query_res.new_shares ); @@ -1015,7 +1015,7 @@ fn test_query_on_join_pool() { .unwrap(); assert_eq!(ResponseType::Success {}, join_pool_query_res.response); assert_eq!( - Uint128::from(1416837573911030650529u128), + Uint128::from(1416837573911032858392u128), join_pool_query_res.new_shares ); } @@ -1433,7 +1433,7 @@ fn test_on_exit_pool() { ); assert_eq!(ResponseType::Success {}, exit_pool_query_res.response); assert_eq!( - Uint128::from(479_662_097_799_569_595_469u128), + Uint128::from(479_662_097_799_569_595_515u128), exit_pool_query_res.burn_shares ); assert_eq!( @@ -1538,7 +1538,7 @@ fn test_on_exit_pool() { ); assert_eq!(ResponseType::Success {}, exit_pool_query_res.response); assert_eq!( - Uint128::from(1734283090619359785410u128), + Uint128::from(1734283090619359785679u128), exit_pool_query_res.burn_shares ); assert_eq!( @@ -1645,7 +1645,7 @@ fn test_on_exit_pool() { ); assert_eq!(ResponseType::Success {}, exit_pool_query_res.response); assert_eq!( - Uint128::from(1_976_713_420_765_243_272_086u128), + Uint128::from(1_976_713_420_765_243_272_248u128), exit_pool_query_res.burn_shares ); assert_eq!( diff --git a/contracts/pools/stable_pool/tests/test_scaling_factor.rs b/contracts/pools/stable_pool/tests/test_scaling_factor.rs index d141d7f7..6e7b45c1 100644 --- a/contracts/pools/stable_pool/tests/test_scaling_factor.rs +++ b/contracts/pools/stable_pool/tests/test_scaling_factor.rs @@ -963,7 +963,7 @@ fn test_5_asset_lsd_pool_with_different_precisions() { pool_addr.clone(), pool_id, assets_msg.clone(), - Uint128::from(5_072_169_964_407_537_367_290_383u128), + Uint128::from(5_072_169_964_407_537_367_258_707u128), ); // Swap 1 ustatom for uatom @@ -1071,7 +1071,7 @@ fn test_5_asset_lsd_pool_with_different_precisions() { pool_id, lp_token_addr.clone(), vec![Asset::new(atom_asset.clone(), Uint128::from(100_000_000_000u128))], - Uint128::from(100_206_787_474_015_742_826_455u128), + Uint128::from(100_206_787_474_015_742_838_214u128), Some(vec![ // Asset::new(wrapped_atom_asset.clone(), Uint128::from(18_684_894u128)), Asset::new(wrapped_atom_asset.clone(), Uint128::from(18_682_739u128)), diff --git a/contracts/vault/tests/pool_exit.rs b/contracts/vault/tests/pool_exit.rs index c210b533..c01a2f44 100644 --- a/contracts/vault/tests/pool_exit.rs +++ b/contracts/vault/tests/pool_exit.rs @@ -403,7 +403,7 @@ fn test_exit_pool() { ) .unwrap(); assert_eq!( - Uint128::from(394669089467585656459u128), + Uint128::from(394669089467585656489u128), cur_user_lp_balance.balance - new_user_lp_balance.balance ); @@ -669,7 +669,7 @@ fn test_exit_pool() { amount: Uint128::from(257_000000u128), }, ], - max_lp_to_burn: Some(Uint128::from(404_374980_780408_081409u128)), + max_lp_to_burn: Some(Uint128::from(404_374_980_780_408_081_342u128)), }, }) .unwrap(), @@ -679,5 +679,5 @@ fn test_exit_pool() { stable5_lp_token_addr.clone(), &exit_msg, &[] - ).unwrap_err().root_cause().to_string(), "MaxLpToBurnError - burn amount 404374980780408081410 is more than maximum LP to burn 404374980780408081409 allowed by the user"); + ).unwrap_err().root_cause().to_string(), "MaxLpToBurnError - burn amount 404374980780408081343 is more than maximum LP to burn 404374980780408081342 allowed by the user"); }