From c0bd84dc9c70b654daddda044fd468b6b8a69702 Mon Sep 17 00:00:00 2001 From: betterclever Date: Tue, 30 Jan 2024 01:03:06 +0530 Subject: [PATCH 1/9] v1.1.0 tag --- packages/dexter/Cargo.toml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/dexter/Cargo.toml b/packages/dexter/Cargo.toml index 804243c7..d05258fb 100644 --- a/packages/dexter/Cargo.toml +++ b/packages/dexter/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "dexter" -version = "1.0.0" -authors = ["AstroTechLabs"] +version = "1.1.0" +authors = ["Persistence Labs"] edition = "2021" -description = "DEX on Persistence tendermint chain" -repository = "https://github.com/persistenceOne/dexter" +description = "Dex optimized for liquid staked assets" +repository = "https://github.com/dexter-zone/dexter_core" +license = "MIT OR Apache-2.0" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] # for quicker tests, cargo test --lib From 910572c04e22eec512568c2d3c51af7e66c7e92a Mon Sep 17 00:00:00 2001 From: betterclever Date: Thu, 15 Feb 2024 12:13:08 +0530 Subject: [PATCH 2/9] added spot price function for stableswap pool --- contracts/pools/stable_pool/src/contract.rs | 31 +++++- contracts/pools/stable_pool/src/math.rs | 105 +++++++++++++++--- contracts/pools/weighted_pool/src/contract.rs | 36 ++++++ packages/dexter/src/pool.rs | 16 ++- 4 files changed, 172 insertions(+), 16 deletions(-) diff --git a/contracts/pools/stable_pool/src/contract.rs b/contracts/pools/stable_pool/src/contract.rs index 46699eb1..4289b104 100644 --- a/contracts/pools/stable_pool/src/contract.rs +++ b/contracts/pools/stable_pool/src/contract.rs @@ -11,10 +11,10 @@ use std::str::FromStr; use std::vec; use crate::error::ContractError; -use crate::math::{compute_d, AMP_PRECISION, MAX_AMP, MAX_AMP_CHANGE, MIN_AMP_CHANGING_TIME}; +use crate::math::{compute_d, calc_spot_price, AMP_PRECISION, MAX_AMP, MAX_AMP_CHANGE, MIN_AMP_CHANGING_TIME}; use crate::state::{get_precision, AssetScalingFactor, MathConfig, StablePoolParams, StablePoolUpdateParams, StableSwapConfig, Twap, CONFIG, MATHCONFIG, STABLESWAP_CONFIG, TWAPINFO, PRECISIONS}; use crate::utils::{accumulate_prices, compute_offer_amount, compute_swap}; -use dexter::pool::{return_exit_failure, return_join_failure, return_swap_failure, AfterExitResponse, AfterJoinResponse, Config, ConfigResponse, CumulativePriceResponse, CumulativePricesResponse, ExecuteMsg, ExitType, FeeResponse, InstantiateMsg, MigrateMsg, QueryMsg, ResponseType, SwapResponse, Trade, DEFAULT_SPREAD, update_fee, store_precisions}; +use dexter::pool::{return_exit_failure, return_join_failure, return_swap_failure, store_precisions, update_fee, AfterExitResponse, AfterJoinResponse, Config, ConfigResponse, CumulativePriceResponse, CumulativePricesResponse, ExecuteMsg, ExitType, FeeResponse, InstantiateMsg, MigrateMsg, QueryMsg, ResponseType, SpotPrice, SwapResponse, Trade, DEFAULT_SPREAD}; use dexter::asset::{Asset, AssetExchangeRate, AssetInfo, Decimal256Ext, DecimalAsset}; use dexter::helper::{calculate_underlying_fees, get_share_in_assets, select_pools, EventExt}; @@ -525,6 +525,9 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { offer_asset, ask_asset, } => to_json_binary(&query_cumulative_price(deps, env, offer_asset, ask_asset)?), + QueryMsg::SpotPrice { offer_asset, ask_asset } => { + to_json_binary(&query_spot_price(deps, env, offer_asset, ask_asset)?) + } QueryMsg::CumulativePrices {} => to_json_binary(&query_cumulative_prices(deps, env)?), } } @@ -1153,6 +1156,30 @@ pub fn query_cumulative_price( Ok(resp) } +pub fn query_spot_price( + deps: Deps, + env: Env, + offer_asset_info: AssetInfo, + ask_asset_info: AssetInfo, +) -> StdResult { + let config: Config = CONFIG.load(deps.storage)?; + let math_config: MathConfig = MATHCONFIG.load(deps.storage)?; + + let decimal_assets: Vec = transform_to_scaled_decimal_asset(deps, config.assets)?; + let fee = config.fee_info; + let amp = compute_current_amp(&math_config, &env)?; + + let spot_price = calc_spot_price( + &offer_asset_info, + &ask_asset_info, + &decimal_assets, + fee, + amp, + )?; + + Ok(spot_price) +} + /// ## Description /// Returns information about the cumulative prices in a [`CumulativePricesResponse`] object. /// ## Params diff --git a/contracts/pools/stable_pool/src/math.rs b/contracts/pools/stable_pool/src/math.rs index 3e154d88..05bf99be 100644 --- a/contracts/pools/stable_pool/src/math.rs +++ b/contracts/pools/stable_pool/src/math.rs @@ -1,6 +1,7 @@ use cosmwasm_std::{Decimal256, StdError, StdResult, Uint128, Uint256, Uint64}; use dexter::asset::{AssetInfo, Decimal256Ext, DecimalAsset}; use dexter::error::ContractError; +use dexter::pool::{FeeStructs, SpotPrice}; use itertools::Itertools; /// The maximum number of calculation steps for Newton's method. @@ -31,10 +32,7 @@ pub const AMP_PRECISION: u64 = 100; /// * **amp** is an object of type [`Uint64`]. /// * **pools** is a vector with values of type [`Decimal256`]. /// * **greatest_precision** object of type [`u8`]. -pub(crate) fn compute_d( - amp: Uint64, - pools: &[Decimal256], -) -> StdResult { +pub(crate) fn compute_d(amp: Uint64, pools: &[Decimal256]) -> StdResult { if pools.iter().any(|pool| pool.is_zero()) { return Ok(Decimal256::zero()); } @@ -72,11 +70,13 @@ pub(crate) fn compute_d( + (Decimal256::from_integer(n_coins.u64()) + Decimal256::one()) * d_p); if d >= d_prev { - if d - d_prev <= Decimal256::with_precision(Uint64::from(1u8), Decimal256::DECIMAL_PLACES)? + if d - d_prev + <= Decimal256::with_precision(Uint64::from(1u8), Decimal256::DECIMAL_PLACES)? { return Ok(d); } - } else if d_prev - d <= Decimal256::with_precision(Uint64::from(1u8), Decimal256::DECIMAL_PLACES)? + } else if d_prev - d + <= Decimal256::with_precision(Uint64::from(1u8), Decimal256::DECIMAL_PLACES)? { return Ok(d); } @@ -98,13 +98,15 @@ pub(crate) fn calc_y( to: &AssetInfo, new_amount: Decimal256, pools: &[DecimalAsset], - amp_: u64, + amp: u64, output_precision: u8, ) -> StdResult { - let amp = Uint64::from(amp_); + let amp = Uint64::from(amp); if from_asset.info.equal(to) { - return Err(StdError::generic_err(ContractError::SameAssets {}.to_string())); + return Err(StdError::generic_err( + ContractError::SameAssets {}.to_string(), + )); } let n_coins = Uint64::from(pools.len() as u8); @@ -113,8 +115,7 @@ pub(crate) fn calc_y( 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)?; let mut c = d; @@ -129,7 +130,8 @@ pub(crate) fn calc_y( c = c .checked_multiply_ratio( d, - pool_amount.to_uint256_with_precision(Decimal256::DECIMAL_PLACES)? * Uint256::from(n_coins), + pool_amount.to_uint256_with_precision(Decimal256::DECIMAL_PLACES)? + * Uint256::from(n_coins), ) .map_err(|_| StdError::generic_err("CheckedMultiplyRatioError"))?; sum += pool_amount; @@ -155,7 +157,7 @@ pub(crate) fn calc_y( let decimal_difference = Decimal256::DECIMAL_PLACES - output_precision as u32; // this is safe because ask_asset_precision is always <= 18 let precision_ratio = Uint256::from(10u8).pow(decimal_difference as u32); let y = y.checked_div(precision_ratio)?; - + return Ok(y.try_into()?); } } else if y_prev - y <= Uint256::from(1u8) { @@ -172,6 +174,83 @@ pub(crate) fn calc_y( Err(StdError::generic_err("y is not converging")) } +pub(crate) fn calc_spot_price( + from: &AssetInfo, + to: &AssetInfo, + pools: &[DecimalAsset], + fee: FeeStructs, + amp: u64, +) -> StdResult { + // first we figure out the amount of the from asset in the pool + let from_asset = pools.iter().find(|asset| asset.info.eq(from)).unwrap(); + let to_asset = pools.iter().find(|asset| asset.info.eq(to)).unwrap(); + + // now, since it's really hard to find the price derivative of the stableswap invariant, we'll just use the + // approximation as the price of a very very small trade. This is the same as the spot price. + // We will define a very small trade as 0.001% of the pool liquidity + // For most 6 decimal precision assets, even 1 unit = 1e6, so 0.001% = 1e6 / 1e5 = 1e = 10 units which is still + // a decent small trade size for having a good approximation without running into decimal precision issues. + // Also, since we always use 18 decimal precision in our calculations, we actually have decent precision in our + // calculations for having a very accurate spot price. + let from_asset_small_trade_amount = from_asset.amount.checked_mul(Decimal256::from_ratio( + Uint256::from(1u128), + Uint256::from(100000u128), + ))?; + let fee_on_trade = from_asset_small_trade_amount.checked_mul(Decimal256::from_ratio( + fee.total_fee_bps, + Uint256::from(10000u128), + ))?; + + let from_asset_small_trade_amount_after_fee = + from_asset_small_trade_amount.checked_sub(fee_on_trade)?; + + let new_from_asset = from_asset + .amount + .checked_add(from_asset_small_trade_amount)?; + let new_from_asset_after_fee_deduction = from_asset + .amount + .checked_add(from_asset_small_trade_amount_after_fee)?; + + let y = calc_y( + from_asset, + to, + new_from_asset, + pools, + amp, + Decimal256::DECIMAL_PLACES as u8, + )?; + + let y_including_fee = calc_y( + from_asset, + to, + new_from_asset_after_fee_deduction, + pools, + amp, + Decimal256::DECIMAL_PLACES as u8, + )?; + + let y_price_decimal = Decimal256::with_precision(y, Decimal256::DECIMAL_PLACES)?; + let y_price_including_fee_decimal = + Decimal256::with_precision(y_including_fee, Decimal256::DECIMAL_PLACES)?; + + let y_diff = to_asset.amount.checked_sub(y_price_decimal)?; + let y_diff_including_fee = to_asset.amount.checked_sub(y_price_including_fee_decimal)?; + + let spot_price = y_diff.checked_div(from_asset_small_trade_amount).unwrap(); + let spot_price_with_fee = y_diff_including_fee + .checked_div(from_asset_small_trade_amount) + .unwrap(); + + let spot_price = SpotPrice { + from: from.clone(), + to: to.clone(), + price: spot_price, + price_including_fee: spot_price_with_fee, + }; + + Ok(spot_price) +} + #[cfg(test)] mod tests { use super::*; diff --git a/contracts/pools/weighted_pool/src/contract.rs b/contracts/pools/weighted_pool/src/contract.rs index 626ccd92..890ba143 100644 --- a/contracts/pools/weighted_pool/src/contract.rs +++ b/contracts/pools/weighted_pool/src/contract.rs @@ -296,6 +296,9 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { max_spread, belief_price, )?), + QueryMsg::SpotPrice { offer_asset, ask_asset } => { + to_json_binary(&query_spot_price(deps, env, offer_asset, ask_asset)?) + } QueryMsg::CumulativePrice { offer_asset, ask_asset, @@ -304,6 +307,39 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { } } +fn query_spot_price( + deps: Deps, + _env: Env, + offer_asset: AssetInfo, + ask_asset: AssetInfo, +) -> StdResult { + // let config: Config = CONFIG.load(deps.storage)?; + // let twap: Twap = TWAPINFO.load(deps.storage)?; + + // let decimal_assets: Vec = + // transform_to_decimal_asset(deps.as_ref(), &config.assets); + + // let offer_pool = decimal_assets + // .iter() + // .find(|a| a.info.equal(&offer_asset)) + // .ok_or_else(|| StdError::generic_err("Asset not found"))?; + + // let ask_pool = decimal_assets + // .iter() + // .find(|a| a.info.equal(&ask_asset)) + // .ok_or_else(|| StdError::generic_err("Asset not found"))?; + + // let spot_price = offer_pool.amount / ask_pool.amount; + + // Ok(AssetExchangeRate { + // rate: spot_price, + // numerator: offer_pool.amount, + // denominator: ask_pool.amount, + // }) + + panic!("Not implemented") +} + /// ## Description /// Returns information about the controls settings in a [`ConfigResponse`] object. /// ## Params diff --git a/packages/dexter/src/pool.rs b/packages/dexter/src/pool.rs index 931f50cd..2d2a298b 100644 --- a/packages/dexter/src/pool.rs +++ b/packages/dexter/src/pool.rs @@ -4,7 +4,7 @@ use cosmwasm_schema::{cw_serde, QueryResponses}; use crate::asset::{Asset, AssetExchangeRate, AssetInfo}; use crate::vault::{PoolType, SwapType, NativeAssetPrecisionInfo}; -use cosmwasm_std::{Addr, Binary, Decimal, DepsMut, Env, Event, MessageInfo, Response, StdError, StdResult, Uint128}; +use cosmwasm_std::{Addr, Binary, Decimal, Decimal256, DepsMut, Env, Event, MessageInfo, Response, StdError, StdResult, Uint128}; use std::fmt::{Display, Formatter, Result}; use cw_storage_plus::{Item, Map}; use crate::helper::EventExt; @@ -172,6 +172,12 @@ pub enum QueryMsg { max_spread: Option, belief_price: Option, }, + /// ## Description - Returns the spot price of the asset in a [`SpotPrice`] object. + #[returns(SpotPrice)] + SpotPrice { + offer_asset: AssetInfo, + ask_asset: AssetInfo, + }, /// ## Description - Returns information about the cumulative price of the asset in a [`CumulativePriceResponse`] object. #[returns(CumulativePriceResponse)] CumulativePrice { @@ -281,6 +287,14 @@ pub struct CumulativePricesResponse { pub total_share: Uint128, } +#[cw_serde] +pub struct SpotPrice { + pub from: AssetInfo, + pub to: AssetInfo, + pub price: Decimal256, + pub price_including_fee: Decimal256 +} + // ----------------x----------------x----------------x----------------x----------------x---------------- // ----------------x----------------x Helper response functions x----------------x------------ // ----------------x----------------x----------------x----------------x----------------x---------------- From e9fdd0dda6ae8e38704267a0886a63dc7350d34d Mon Sep 17 00:00:00 2001 From: betterclever Date: Tue, 20 Feb 2024 12:03:31 +0530 Subject: [PATCH 3/9] add spot price functionality for weighted pool --- contracts/pools/weighted_pool/src/contract.rs | 61 ++++++++++++------- contracts/pools/weighted_pool/src/math.rs | 22 ++++++- 2 files changed, 58 insertions(+), 25 deletions(-) diff --git a/contracts/pools/weighted_pool/src/contract.rs b/contracts/pools/weighted_pool/src/contract.rs index 890ba143..8f184326 100644 --- a/contracts/pools/weighted_pool/src/contract.rs +++ b/contracts/pools/weighted_pool/src/contract.rs @@ -8,12 +8,12 @@ use cosmwasm_std::{ use cw2::set_contract_version; use dexter::asset::{Asset, AssetExchangeRate, AssetInfo, Decimal256Ext, DecimalAsset}; use dexter::helper::{calculate_underlying_fees, EventExt, select_pools}; -use dexter::pool::{return_exit_failure, return_join_failure, return_swap_failure, AfterExitResponse, AfterJoinResponse, Config, ConfigResponse, CumulativePriceResponse, CumulativePricesResponse, ExecuteMsg, FeeResponse, InstantiateMsg, MigrateMsg, QueryMsg, ResponseType, store_precisions, SwapResponse, Trade, update_fee, ExitType}; +use dexter::pool::{return_exit_failure, return_join_failure, return_swap_failure, store_precisions, update_fee, AfterExitResponse, AfterJoinResponse, Config, ConfigResponse, CumulativePriceResponse, CumulativePricesResponse, ExecuteMsg, ExitType, FeeResponse, InstantiateMsg, MigrateMsg, QueryMsg, ResponseType, SpotPrice, SwapResponse, Trade}; use dexter::querier::{query_supply, query_token_precision}; use dexter::vault::SwapType; use crate::error::ContractError; -use crate::math::get_normalized_weight; +use crate::math::{calc_spot_price, get_normalized_weight}; use crate::state::{get_precision, get_weight, store_weights, MathConfig, Twap, WeightedAsset, WeightedParams, CONFIG, MATHCONFIG, TWAPINFO, PRECISIONS}; use crate::utils::{ accumulate_prices, calc_single_asset_join, compute_offer_amount, compute_swap, @@ -312,32 +312,49 @@ fn query_spot_price( _env: Env, offer_asset: AssetInfo, ask_asset: AssetInfo, -) -> StdResult { - // let config: Config = CONFIG.load(deps.storage)?; - // let twap: Twap = TWAPINFO.load(deps.storage)?; +) -> StdResult { + let config: Config = CONFIG.load(deps.storage)?; + + let offer_asset_decimal = get_precision(deps.storage, &offer_asset)?; + let ask_asset_decimal = get_precision(deps.storage, &ask_asset)?; + + let pool_amount_offer_asset = config + .assets + .iter() + .find(|a| a.info.equal(&offer_asset)) + .ok_or_else(|| StdError::generic_err("Asset not found"))?; - // let decimal_assets: Vec = - // transform_to_decimal_asset(deps.as_ref(), &config.assets); + let pool_amount_ask_asset = config + .assets + .iter() + .find(|a| a.info.equal(&ask_asset)) + .ok_or_else(|| StdError::generic_err("Asset not found"))?; - // let offer_pool = decimal_assets - // .iter() - // .find(|a| a.info.equal(&offer_asset)) - // .ok_or_else(|| StdError::generic_err("Asset not found"))?; + let offer_decimal_asset = DecimalAsset { + info: offer_asset.clone(), + amount: Decimal256::with_precision(pool_amount_offer_asset.amount, offer_asset_decimal)?, + }; - // let ask_pool = decimal_assets - // .iter() - // .find(|a| a.info.equal(&ask_asset)) - // .ok_or_else(|| StdError::generic_err("Asset not found"))?; + let ask_decimal_asset = DecimalAsset { + info: ask_asset.clone(), + amount: Decimal256::with_precision(pool_amount_offer_asset.amount, ask_asset_decimal)?, + }; - // let spot_price = offer_pool.amount / ask_pool.amount; + let spot_price = calc_spot_price( + &offer_decimal_asset, + &ask_decimal_asset, + pool_amount_offer_asset.amount, + pool_amount_ask_asset.amount, + )?; - // Ok(AssetExchangeRate { - // rate: spot_price, - // numerator: offer_pool.amount, - // denominator: ask_pool.amount, - // }) + let spot_price_with_fee = spot_price - spot_price * Decimal256::from_ratio(config.fee_info.total_fee_bps, 10000u128); - panic!("Not implemented") + Ok(SpotPrice { + from: offer_asset, + to: ask_asset, + price: spot_price, + price_including_fee: spot_price_with_fee, + }) } /// ## Description diff --git a/contracts/pools/weighted_pool/src/math.rs b/contracts/pools/weighted_pool/src/math.rs index 9d458c6a..1ca51c8c 100644 --- a/contracts/pools/weighted_pool/src/math.rs +++ b/contracts/pools/weighted_pool/src/math.rs @@ -1,7 +1,7 @@ use crate::approx_pow::calculate_pow; use crate::state::WeightedAsset; -use cosmwasm_std::{Decimal, StdError, StdResult, Uint128}; -use dexter::helper::adjust_precision; +use cosmwasm_std::{Decimal, Decimal256, StdError, StdResult, Uint128}; +use dexter::{asset::{Decimal256Ext, DecimalAsset}, helper::adjust_precision}; // Referenced from Balancer Weighted pool implementation by Osmosis here - https://github.com/osmosis-labs/osmosis/blob/47a2366c5eeee474de9e1cb4777fab0ccfbb9592/x/gamm/pool-models/balancer/amm.go#L94 // solveConstantFunctionInvariant solves the constant function of an AMM @@ -40,7 +40,23 @@ pub fn solve_constant_function_invariant( }; let amount_y = token_balance_unknown_before.checked_mul(paranthetical)?; - return Ok(amount_y); + Ok(amount_y) +} + +pub fn calc_spot_price( + from_asset: &DecimalAsset, + to_asset: &DecimalAsset, + from_weight: Uint128, + to_weight: Uint128, +) -> StdResult { + let numerator = from_asset.amount.checked_div(Decimal256::from_integer(from_weight)) + .map_err(|e| StdError::generic_err(e.to_string()))?; + + let denominator = to_asset.amount.checked_div(Decimal256::from_integer(to_weight)) + .map_err(|e| StdError::generic_err(e.to_string()))?; + + let spot_price = numerator.checked_div(denominator).unwrap(); + Ok(spot_price) } /// ## Description - Inspired from Osmosis implementaton here - https://github.com/osmosis-labs/osmosis/blob/main/x/gamm/pool-models/balancer/amm.go#L116 From ec2798c7da81e605b653b91a8881080b5090d611 Mon Sep 17 00:00:00 2001 From: betterclever Date: Tue, 20 Feb 2024 14:14:53 +0530 Subject: [PATCH 4/9] upgrade dexter crate version --- packages/dexter/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dexter/Cargo.toml b/packages/dexter/Cargo.toml index d05258fb..f80bf2a1 100644 --- a/packages/dexter/Cargo.toml +++ b/packages/dexter/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dexter" -version = "1.1.0" +version = "1.2.0" authors = ["Persistence Labs"] edition = "2021" description = "Dex optimized for liquid staked assets" From fb468d20d1792cbad8e88f09d6271d8f601e07e8 Mon Sep 17 00:00:00 2001 From: betterclever Date: Wed, 21 Feb 2024 12:22:35 +0530 Subject: [PATCH 5/9] modify cumuluative price functions to use the spot price calculations --- contracts/pools/stable_pool/src/utils.rs | 45 +++++++------------ .../pools/stable_pool/tests/integration.rs | 12 ++--- contracts/pools/weighted_pool/src/contract.rs | 14 ++++-- contracts/pools/weighted_pool/src/math.rs | 26 ++++++++--- contracts/pools/weighted_pool/src/utils.rs | 37 +++++++-------- .../pools/weighted_pool/tests/integration.rs | 24 +++++----- packages/dexter/src/helper.rs | 14 +++++- packages/dexter/src/lib.rs | 13 ------ 8 files changed, 94 insertions(+), 91 deletions(-) diff --git a/contracts/pools/stable_pool/src/utils.rs b/contracts/pools/stable_pool/src/utils.rs index a90fa718..4cdc6a81 100644 --- a/contracts/pools/stable_pool/src/utils.rs +++ b/contracts/pools/stable_pool/src/utils.rs @@ -1,12 +1,12 @@ use cosmwasm_std::{Decimal, Decimal256, Deps, Env, StdResult, Storage, Uint128}; use dexter::asset::{Decimal256Ext, DecimalAsset}; -use dexter::helper::{select_pools, decimal2decimal256}; +use dexter::helper::decimal_to_decimal256; use dexter::vault::FEE_PRECISION; use crate::error::ContractError; -use crate::math::calc_y; -use crate::state::{MathConfig, STABLESWAP_CONFIG}; +use crate::math::{calc_spot_price, calc_y}; +use crate::state::{MathConfig, CONFIG}; use crate::state::{get_precision, Twap}; // --------x--------x--------x--------x--------x--------x--------x--------x--------- @@ -89,7 +89,7 @@ pub(crate) fn compute_offer_amount( let ask_precision = get_precision(storage, &ask_asset.info)?; let one_minus_commission = Decimal256::one() - - decimal2decimal256(Decimal::from_ratio(commission_rate, FEE_PRECISION))?; + - decimal_to_decimal256(Decimal::from_ratio(commission_rate, FEE_PRECISION))?; let inv_one_minus_commission = Decimal256::one() / one_minus_commission; // New offer pool amount here is returned with the greatest precision. @@ -191,9 +191,8 @@ pub fn accumulate_prices( twap: &mut Twap, pools: &[DecimalAsset], ) -> Result<(), ContractError> { - let stableswap_config = STABLESWAP_CONFIG.load(deps.storage)?; - let scaling_factors = stableswap_config.scaling_factors(); - + let config = CONFIG.load(deps.storage)?; + // Calculate time elapsed since last price update. let block_time = env.block.time.seconds(); if block_time <= twap.block_time_last { @@ -204,29 +203,19 @@ pub fn accumulate_prices( // Iterate over all asset pairs in the pool and accumulate prices. for (from, to, value) in twap.cumulative_prices.iter_mut() { - let offer_asset_scaling_factor = scaling_factors.get(&from).cloned().unwrap_or(Decimal256::one()); - let ask_asset_scaling_factor = scaling_factors.get(&to).cloned().unwrap_or(Decimal256::one()); - - let offer_asset = DecimalAsset { - info: from.clone(), - amount: Decimal256::one(), - }; - - // Offer asset scaled by the scaling factor - let offer_asset_scaled = offer_asset.with_scaling_factor(offer_asset_scaling_factor)?; - - let (offer_pool, ask_pool) = select_pools(from, to, pools).unwrap(); - let (return_amount, _) = compute_swap( - deps.storage, - &env, - &math_config, - &offer_asset_scaled, - &offer_pool, - &ask_pool, - pools, - ask_asset_scaling_factor, + let amp = compute_current_amp(&math_config, &env)?; + + let spot_price = calc_spot_price( + from, + to, + pools, + config.fee_info.clone(), + amp )?; + let ask_asset_precision = get_precision(deps.storage, &to)?; + let return_amount = spot_price.price_including_fee.to_uint128_with_precision(ask_asset_precision)?; + *value = value.wrapping_add(time_elapsed.checked_mul(return_amount)?); } diff --git a/contracts/pools/stable_pool/tests/integration.rs b/contracts/pools/stable_pool/tests/integration.rs index d953a982..bb362364 100644 --- a/contracts/pools/stable_pool/tests/integration.rs +++ b/contracts/pools/stable_pool/tests/integration.rs @@ -653,7 +653,7 @@ fn test_query_on_join_pool() { ask_info: AssetInfo::Token { contract_addr: token_instance0.clone(), }, - rate: Uint128::from(1000180000u128), + rate: Uint128::from(970173599820u128), }, AssetExchangeRate { offer_info: AssetInfo::NativeToken { @@ -662,7 +662,7 @@ fn test_query_on_join_pool() { ask_info: AssetInfo::Token { contract_addr: token_instance1.clone(), }, - rate: Uint128::from(1000180000u128), + rate: Uint128::from(970173599820u128), }, AssetExchangeRate { offer_info: AssetInfo::Token { @@ -671,7 +671,7 @@ fn test_query_on_join_pool() { ask_info: AssetInfo::NativeToken { denom: "axlusd".to_string(), }, - rate: Uint128::from(1000180000u128), + rate: Uint128::from(970173599820u128), }, AssetExchangeRate { offer_info: AssetInfo::Token { @@ -680,7 +680,7 @@ fn test_query_on_join_pool() { ask_info: AssetInfo::Token { contract_addr: token_instance1.clone(), }, - rate: Uint128::from(1000180000u128), + rate: Uint128::from(970173599820u128), }, AssetExchangeRate { offer_info: AssetInfo::Token { @@ -689,7 +689,7 @@ fn test_query_on_join_pool() { ask_info: AssetInfo::NativeToken { denom: "axlusd".to_string(), }, - rate: Uint128::from(1000180000u128), + rate: Uint128::from(970173599820u128), }, AssetExchangeRate { offer_info: AssetInfo::Token { @@ -698,7 +698,7 @@ fn test_query_on_join_pool() { ask_info: AssetInfo::Token { contract_addr: token_instance0.clone(), }, - rate: Uint128::from(1000180000u128), + rate: Uint128::from(970173599820u128), }, ], pool_twap_res.exchange_infos diff --git a/contracts/pools/weighted_pool/src/contract.rs b/contracts/pools/weighted_pool/src/contract.rs index 8f184326..f37dfdae 100644 --- a/contracts/pools/weighted_pool/src/contract.rs +++ b/contracts/pools/weighted_pool/src/contract.rs @@ -337,14 +337,22 @@ fn query_spot_price( let ask_decimal_asset = DecimalAsset { info: ask_asset.clone(), - amount: Decimal256::with_precision(pool_amount_offer_asset.amount, ask_asset_decimal)?, + amount: Decimal256::with_precision(pool_amount_ask_asset.amount, ask_asset_decimal)?, }; + println!( + "offer_decimal_asset: {:?}, ask_decimal_asset: {:?}", + offer_decimal_asset, ask_decimal_asset + ); + + let offer_weight = get_weight(deps.storage, &offer_asset)?; + let ask_weight = get_weight(deps.storage, &ask_asset)?; + let spot_price = calc_spot_price( &offer_decimal_asset, &ask_decimal_asset, - pool_amount_offer_asset.amount, - pool_amount_ask_asset.amount, + offer_weight, + ask_weight )?; let spot_price_with_fee = spot_price - spot_price * Decimal256::from_ratio(config.fee_info.total_fee_bps, 10000u128); diff --git a/contracts/pools/weighted_pool/src/math.rs b/contracts/pools/weighted_pool/src/math.rs index 1ca51c8c..782e5cfb 100644 --- a/contracts/pools/weighted_pool/src/math.rs +++ b/contracts/pools/weighted_pool/src/math.rs @@ -1,7 +1,7 @@ use crate::approx_pow::calculate_pow; use crate::state::WeightedAsset; use cosmwasm_std::{Decimal, Decimal256, StdError, StdResult, Uint128}; -use dexter::{asset::{Decimal256Ext, DecimalAsset}, helper::adjust_precision}; +use dexter::{asset::DecimalAsset, helper::{adjust_precision, decimal_to_decimal256}}; // Referenced from Balancer Weighted pool implementation by Osmosis here - https://github.com/osmosis-labs/osmosis/blob/47a2366c5eeee474de9e1cb4777fab0ccfbb9592/x/gamm/pool-models/balancer/amm.go#L94 // solveConstantFunctionInvariant solves the constant function of an AMM @@ -44,17 +44,29 @@ pub fn solve_constant_function_invariant( } pub fn calc_spot_price( - from_asset: &DecimalAsset, - to_asset: &DecimalAsset, - from_weight: Uint128, - to_weight: Uint128, + offer_asset_pool: &DecimalAsset, + ask_asset_pool: &DecimalAsset, + offer_asset_weight_weight: Decimal, + ask_asset_weight: Decimal, ) -> StdResult { - let numerator = from_asset.amount.checked_div(Decimal256::from_integer(from_weight)) + let offer_asset_weight_decimal_256 = decimal_to_decimal256(offer_asset_weight_weight)?; + let ask_asset_weight_decimal_256 = decimal_to_decimal256(ask_asset_weight)?; + + println!( + "offer_asset_pool.amount: {}, offer_asset_weight_decimal_256: {}, ask_asset_pool.amount: {}, ask_asset_weight_decimal_256: {}", + offer_asset_pool.amount, offer_asset_weight_decimal_256, ask_asset_pool.amount, ask_asset_weight_decimal_256 + ); + + let numerator = ask_asset_pool.amount.checked_div(ask_asset_weight_decimal_256) .map_err(|e| StdError::generic_err(e.to_string()))?; - let denominator = to_asset.amount.checked_div(Decimal256::from_integer(to_weight)) + let denominator = offer_asset_pool.amount.checked_div(offer_asset_weight_decimal_256) .map_err(|e| StdError::generic_err(e.to_string()))?; + if denominator.is_zero() { + return Ok(Decimal256::zero()); + } + let spot_price = numerator.checked_div(denominator).unwrap(); Ok(spot_price) } diff --git a/contracts/pools/weighted_pool/src/utils.rs b/contracts/pools/weighted_pool/src/utils.rs index 2252206f..7017d7a5 100644 --- a/contracts/pools/weighted_pool/src/utils.rs +++ b/contracts/pools/weighted_pool/src/utils.rs @@ -1,12 +1,12 @@ use std::str::FromStr; use cosmwasm_std::{Decimal, Decimal256, Deps, Env, StdError, StdResult, Storage, Uint128, Uint256}; -use dexter::asset::{Asset, DecimalAsset}; -use dexter::helper::{adjust_precision, decimal2decimal256, select_pools}; -use dexter::pool::{ResponseType}; +use dexter::asset::{Asset, Decimal256Ext, DecimalAsset}; +use dexter::helper::{adjust_precision, decimal256_to_decimal, decimal_to_decimal256, select_pools}; +use dexter::pool::ResponseType; use crate::error::ContractError; -use crate::math::{calc_minted_shares_given_single_asset_in, solve_constant_function_invariant}; +use crate::math::{calc_minted_shares_given_single_asset_in, solve_constant_function_invariant, calc_spot_price}; use crate::state::{get_precision, get_weight, Twap, WeightedAsset}; use dexter::vault::FEE_PRECISION; @@ -93,10 +93,10 @@ pub(crate) fn compute_offer_amount( let token_precision = get_precision(storage, &offer_pool.info)?; let one_minus_commission = Decimal256::one() - - decimal2decimal256(Decimal::from_ratio(commission_rate, FEE_PRECISION))?; + - decimal_to_decimal256(Decimal::from_ratio(commission_rate, FEE_PRECISION))?; let inv_one_minus_commission = Decimal256::one() / one_minus_commission; - let ask_asset_amount = Decimal::from_str(&ask_asset.amount.clone().to_string())?; + let ask_asset_amount = decimal256_to_decimal(ask_asset.amount)?; // Ask pool balance after swap let pool_post_swap_out_balance = @@ -162,28 +162,23 @@ pub fn accumulate_prices( // Iterate over all asset pairs in the pool and accumulate prices. for (from, to, value) in twap.cumulative_prices.iter_mut() { - let offer_asset = DecimalAsset { - info: from.clone(), - amount: Decimal256::one(), - }; - let from_weight = get_weight(deps.storage, from)?; let to_weight = get_weight(deps.storage, to)?; // retrieve the offer and ask asset pool's latest balances let (offer_pool, ask_pool) = select_pools(from, to, pools).unwrap(); - // Compute the current price of ask asset in base asset - let (return_amount, _) = compute_swap( - deps.storage, - &env, - &offer_asset, - &offer_pool, - from_weight, - &ask_pool, - to_weight, - )?; + let spot_price = calc_spot_price(&offer_pool, &ask_pool, from_weight, to_weight)?; + + let ask_asset_precision = get_precision(deps.storage, &ask_pool.info)?; + // we need to convert above decimal to Uint128 according to the precision of the ask asset + let return_amount = spot_price.to_uint128_with_precision(ask_asset_precision)?; + println!(); + println!("weight -> from: {}, to: {}", from_weight, to_weight); + println!("offer_pool -> amount: {:?}, info: {:?}", offer_pool.amount, offer_pool.info); + println!("ask_pool -> amount: {:?}, info: {:?}", ask_pool.amount, ask_pool.info); + println!("return_amount: {}", return_amount); // accumulate the price *value = value.wrapping_add(time_elapsed.checked_mul(return_amount)?); } diff --git a/contracts/pools/weighted_pool/tests/integration.rs b/contracts/pools/weighted_pool/tests/integration.rs index d5a49f6e..b5d5f1b6 100644 --- a/contracts/pools/weighted_pool/tests/integration.rs +++ b/contracts/pools/weighted_pool/tests/integration.rs @@ -667,7 +667,7 @@ fn test_query_on_join_pool() { ask_info: AssetInfo::Token { contract_addr: token_instance1.clone() }, - rate: Uint128::from(44296110000u128) + rate: Uint128::from(44296830000u128) }, AssetExchangeRate { offer_info: AssetInfo::Token { @@ -676,7 +676,7 @@ fn test_query_on_join_pool() { ask_info: AssetInfo::NativeToken { denom: "xprt".to_string() }, - rate: Uint128::from(74138940000u128) + rate: Uint128::from(74140290000u128) }, AssetExchangeRate { offer_info: AssetInfo::Token { @@ -685,7 +685,7 @@ fn test_query_on_join_pool() { ask_info: AssetInfo::Token { contract_addr: token_instance0.clone() }, - rate: Uint128::from(182850660000u128) + rate: Uint128::from(182857050000u128) }, AssetExchangeRate { offer_info: AssetInfo::Token { @@ -694,7 +694,7 @@ fn test_query_on_join_pool() { ask_info: AssetInfo::NativeToken { denom: "xprt".to_string() }, - rate: Uint128::from(150628950000u128) + rate: Uint128::from(150634260000u128) }, AssetExchangeRate { offer_info: AssetInfo::NativeToken { @@ -703,7 +703,7 @@ fn test_query_on_join_pool() { ask_info: AssetInfo::Token { contract_addr: token_instance0.clone() }, - rate: Uint128::from(109249920000u128) + rate: Uint128::from(109252260000u128) }, AssetExchangeRate { offer_info: AssetInfo::NativeToken { @@ -712,7 +712,7 @@ fn test_query_on_join_pool() { ask_info: AssetInfo::Token { contract_addr: token_instance1.clone() }, - rate: Uint128::from(53771400000u128) + rate: Uint128::from(53772570000u128) } ], pool_twap_res.exchange_infos @@ -1080,7 +1080,7 @@ fn test_query_on_join_pool() { ask_info: AssetInfo::Token { contract_addr: token_instance1.clone() }, - rate: Uint128::from(118599230000u128) + rate: Uint128::from(118601210000u128) }, AssetExchangeRate { offer_info: AssetInfo::Token { @@ -1089,7 +1089,7 @@ fn test_query_on_join_pool() { ask_info: AssetInfo::NativeToken { denom: "xprt".to_string() }, - rate: Uint128::from(142576390000u128) + rate: Uint128::from(142578970000u128) }, AssetExchangeRate { offer_info: AssetInfo::Token { @@ -1098,7 +1098,7 @@ fn test_query_on_join_pool() { ask_info: AssetInfo::Token { contract_addr: token_instance0.clone() }, - rate: Uint128::from(268981680000u128) + rate: Uint128::from(268989710000u128) }, AssetExchangeRate { offer_info: AssetInfo::Token { @@ -1107,7 +1107,7 @@ fn test_query_on_join_pool() { ask_info: AssetInfo::NativeToken { denom: "xprt".to_string() }, - rate: Uint128::from(224309220000u128) + rate: Uint128::from(224315890000u128) }, AssetExchangeRate { offer_info: AssetInfo::NativeToken { @@ -1116,7 +1116,7 @@ fn test_query_on_join_pool() { ask_info: AssetInfo::Token { contract_addr: token_instance0.clone() }, - rate: Uint128::from(202844490000u128) + rate: Uint128::from(202848720000u128) }, AssetExchangeRate { offer_info: AssetInfo::NativeToken { @@ -1125,7 +1125,7 @@ fn test_query_on_join_pool() { ask_info: AssetInfo::Token { contract_addr: token_instance1.clone() }, - rate: Uint128::from(140698510000u128) + rate: Uint128::from(140701430000u128) } ], pool_twap_res.exchange_infos diff --git a/packages/dexter/src/helper.rs b/packages/dexter/src/helper.rs index b0fb8c42..65ca9a81 100644 --- a/packages/dexter/src/helper.rs +++ b/packages/dexter/src/helper.rs @@ -315,7 +315,7 @@ pub fn get_share_in_assets(pools: Vec, amount: Uint128, total_share: Uint /// ## Description /// Converts [`Decimal`] to [`Decimal256`]. -pub fn decimal2decimal256(dec_value: Decimal) -> StdResult { +pub fn decimal_to_decimal256(dec_value: Decimal) -> StdResult { Decimal256::from_atomics(dec_value.atomics(), dec_value.decimal_places()).map_err(|_| { StdError::generic_err(format!( "Failed to convert Decimal {} to Decimal256", @@ -324,6 +324,18 @@ pub fn decimal2decimal256(dec_value: Decimal) -> StdResult { }) } +pub fn decimal256_to_decimal(dec_value: Decimal256) -> StdResult { + let value: Uint128 = dec_value.atomics().try_into() + .map_err(|_| StdError::generic_err(format!("Failed to convert Decimal256 {} to Decimal", dec_value)))?; + + Decimal::from_atomics(value, dec_value.decimal_places()).map_err(|_| { + StdError::generic_err(format!( + "Failed to convert Decimal256 {} to Decimal", + dec_value + )) + }) +} + /// ## Description /// Return a value using a newly specified precision. /// ## Params diff --git a/packages/dexter/src/lib.rs b/packages/dexter/src/lib.rs index 9efdb87a..4032a22f 100644 --- a/packages/dexter/src/lib.rs +++ b/packages/dexter/src/lib.rs @@ -52,18 +52,5 @@ mod decimal_checked_ops { } } -use cosmwasm_std::{Decimal, Decimal256, StdError, StdResult}; - -/// ## Description -/// Converts [`Decimal`] to [`Decimal256`]. -pub fn decimal2decimal256(dec_value: Decimal) -> StdResult { - Decimal256::from_atomics(dec_value.atomics(), dec_value.decimal_places()).map_err(|_| { - StdError::generic_err(format!( - "Failed to convert Decimal {} to Decimal256", - dec_value - )) - }) -} - pub use decimal_checked_ops::DecimalCheckedOps; pub use uints::U256; From 518dc42883cc3aad5059b015188495a6c57d62ad Mon Sep 17 00:00:00 2001 From: betterclever Date: Wed, 21 Feb 2024 18:06:37 +0530 Subject: [PATCH 6/9] added spot price test for stableswap pool --- contracts/pools/stable_pool/src/math.rs | 125 +++++++++++++++++++++++- packages/dexter/src/lib.rs | 1 + packages/dexter/src/macros.rs | 8 ++ 3 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 packages/dexter/src/macros.rs diff --git a/contracts/pools/stable_pool/src/math.rs b/contracts/pools/stable_pool/src/math.rs index 05bf99be..bc1fc09d 100644 --- a/contracts/pools/stable_pool/src/math.rs +++ b/contracts/pools/stable_pool/src/math.rs @@ -253,10 +253,133 @@ pub(crate) fn calc_spot_price( #[cfg(test)] mod tests { + use std::str::FromStr; + use super::*; - use dexter::asset::native_asset; + use dexter::{asset::{native_asset, Asset}, uint128_with_precision}; use sim::StableSwapModel; + fn decimal_asset_pools_with_precision(pools: Vec, precision: u8) -> Vec { + pools + .iter() + .map(|pool| pool.to_decimal_asset(precision).unwrap()) + .collect::>() + } + + #[test] + fn test_spot_price() { + + let amp = 100u64; + let amp_final = amp * AMP_PRECISION; + + let fee = FeeStructs { + total_fee_bps: 30, + }; + + let pools = vec![ + native_asset("test1".to_string(), uint128_with_precision!(100_000u128, 6)), + native_asset("test2".to_string(), uint128_with_precision!(100_000u128, 6)), + native_asset("test3".to_string(), uint128_with_precision!(100_000u128, 6)), + ]; + + let pools_decimal = decimal_asset_pools_with_precision(pools.clone(), 6); + let spot_price = calc_spot_price(&pools[0].info,&pools[1].info, &pools_decimal, fee.clone(), amp_final); + assert_eq!(spot_price.is_ok(), true); + assert_eq!(spot_price.unwrap().price, Decimal256::from_str("0.999999900990108804").unwrap()); + + // test opposite direction + let spot_price = calc_spot_price(&pools[1].info,&pools[0].info, &pools_decimal, fee.clone(), amp_final); + assert_eq!(spot_price.is_ok(), true); + assert_eq!(spot_price.unwrap().price, Decimal256::from_str("0.999999900990108804").unwrap()); + + + let pools = vec![ + native_asset("test1".to_string(), uint128_with_precision!(1000u128, 6)), + native_asset("test2".to_string(), uint128_with_precision!(1000u128, 6)), + native_asset("test3".to_string(), uint128_with_precision!(1000u128, 6)), + ]; + + + let pools_decimal = decimal_asset_pools_with_precision(pools.clone(), 6); + let spot_price = calc_spot_price(&pools[0].info,&pools[1].info, &pools_decimal, fee.clone(), amp_final); + assert_eq!(spot_price.is_ok(), true); + assert_eq!(spot_price.unwrap().price, Decimal256::from_str("0.9999999009901089").unwrap()); + + let pools = vec![ + native_asset("test1".to_string(), uint128_with_precision!(1u128, 6)), + native_asset("test2".to_string(), uint128_with_precision!(1u128, 6)), + native_asset("test3".to_string(), uint128_with_precision!(1u128, 6)), + ]; + + let pools_decimal = decimal_asset_pools_with_precision(pools.clone(), 6); + let spot_price = calc_spot_price(&pools[0].info,&pools[1].info, &pools_decimal, fee.clone(), amp_final); + assert_eq!(spot_price.is_ok(), true); + assert_eq!(spot_price.unwrap().price, Decimal256::from_str("0.9999999009902").unwrap()); + + let pools = vec![ + native_asset("test1".to_string(), uint128_with_precision!(1u128, 6)), + // 1/5th the liquidity of test1 for test2. Let's see the effect of this on the spot price. + native_asset("test2".to_string(), Uint128::from(200000u128)), + ]; + + let pools_decimal = decimal_asset_pools_with_precision(pools.clone(), 6); + let spot_price = calc_spot_price(&pools[0].info,&pools[1].info, &pools_decimal, fee.clone(), amp_final); + assert_eq!(spot_price.is_ok(), true); + assert_eq!(spot_price.unwrap().price, Decimal256::from_str("0.9594664670086").unwrap()); + + // test opposite direction + let spot_price = calc_spot_price(&pools[1].info,&pools[0].info, &pools_decimal, fee.clone(), amp_final); + assert_eq!(spot_price.is_ok(), true); + assert_eq!(spot_price.unwrap().price, Decimal256::from_str("1.0422433526755").unwrap()); + + let pools = vec![ + native_asset("test1".to_string(), uint128_with_precision!(1u128, 6)), + // 1/10th the liquidity of test1 for test2. Let's see the effect of this on the spot price. + native_asset("test2".to_string(), Uint128::from(100000u128)), + ]; + + let pools_decimal = decimal_asset_pools_with_precision(pools.clone(), 6); + let spot_price = calc_spot_price(&pools[0].info,&pools[1].info, &pools_decimal, fee.clone(), amp_final); + assert_eq!(spot_price.is_ok(), true); + assert_eq!(spot_price.unwrap().price, Decimal256::from_str("0.8748087775978").unwrap()); + + // test opposite direction + let spot_price = calc_spot_price(&pools[1].info,&pools[0].info, &pools_decimal, fee.clone(), amp_final); + assert_eq!(spot_price.is_ok(), true); + let spot_price = spot_price.unwrap(); + assert_eq!(spot_price.clone().price, Decimal256::from_str("1.143093026548").unwrap()); + assert_eq!(spot_price.price_including_fee, Decimal256::from_str("1.139663751743").unwrap()); + + + // let's try even smaller pools + let pools = vec![ + native_asset("test1".to_string(), Uint128::from(10u128)), + native_asset("test2".to_string(), Uint128::from(10u128)), + ]; + + + let pools_decimal = decimal_asset_pools_with_precision(pools.clone(), 6); + let spot_price = calc_spot_price(&pools[0].info,&pools[1].info, &pools_decimal, fee.clone(), amp_final); + assert_eq!(spot_price.is_ok(), true); + assert_eq!(spot_price.unwrap().price, Decimal256::from_str("0.99999991").unwrap()); + + + // let's try even smaller pools + let pools = vec![ + native_asset("test1".to_string(), uint128_with_precision!(1u64, 12)), + native_asset("test2".to_string(), uint128_with_precision!(1u64, 12)), + ]; + + let pools_decimal = decimal_asset_pools_with_precision(pools.clone(), 18); + + let spot_price = calc_spot_price(&pools[0].info,&pools[1].info, &pools_decimal, fee.clone(), amp_final); + assert_eq!(spot_price.is_ok(), true); + // simulation breaks at this value. + // with integer invariant calculation, we must be able to go below this value. + assert_eq!(spot_price.unwrap().price, Decimal256::from_str("1").unwrap()); + + } + #[test] fn test_compute_d() { // we multiply amp with AMP_PRECISION to avoid floating point arithmetic errors, so amp will always be >= AMP_PRECISION diff --git a/packages/dexter/src/lib.rs b/packages/dexter/src/lib.rs index 4032a22f..f40f90ba 100644 --- a/packages/dexter/src/lib.rs +++ b/packages/dexter/src/lib.rs @@ -10,6 +10,7 @@ pub mod querier; pub mod router; pub mod vault; pub mod constants; +pub mod macros; #[allow(clippy::all)] mod uints { diff --git a/packages/dexter/src/macros.rs b/packages/dexter/src/macros.rs new file mode 100644 index 00000000..b74187ce --- /dev/null +++ b/packages/dexter/src/macros.rs @@ -0,0 +1,8 @@ +#[macro_export] +macro_rules! uint128_with_precision { + ($value:expr, $precision:expr) => { + cosmwasm_std::Uint128::from($value) + .checked_mul(cosmwasm_std::Uint128::from(10u64).pow($precision as u32)) + .unwrap() + }; +} \ No newline at end of file From 0708c3fd3fbcb140d1b0d661b173897d879a2c3f Mon Sep 17 00:00:00 2001 From: betterclever Date: Thu, 22 Feb 2024 10:22:55 +0530 Subject: [PATCH 7/9] spot price tests for weighted pool --- contracts/pools/weighted_pool/src/math.rs | 133 +++++++++++++++++++++- 1 file changed, 128 insertions(+), 5 deletions(-) diff --git a/contracts/pools/weighted_pool/src/math.rs b/contracts/pools/weighted_pool/src/math.rs index 782e5cfb..bfe0027c 100644 --- a/contracts/pools/weighted_pool/src/math.rs +++ b/contracts/pools/weighted_pool/src/math.rs @@ -52,11 +52,6 @@ pub fn calc_spot_price( let offer_asset_weight_decimal_256 = decimal_to_decimal256(offer_asset_weight_weight)?; let ask_asset_weight_decimal_256 = decimal_to_decimal256(ask_asset_weight)?; - println!( - "offer_asset_pool.amount: {}, offer_asset_weight_decimal_256: {}, ask_asset_pool.amount: {}, ask_asset_weight_decimal_256: {}", - offer_asset_pool.amount, offer_asset_weight_decimal_256, ask_asset_pool.amount, ask_asset_weight_decimal_256 - ); - let numerator = ask_asset_pool.amount.checked_div(ask_asset_weight_decimal_256) .map_err(|e| StdError::generic_err(e.to_string()))?; @@ -129,3 +124,131 @@ fn fee_ratio(normalized_weight: Decimal, swap_fee: Decimal) -> Decimal { pub fn get_normalized_weight(weight: Uint128, total_weight: Uint128) -> Decimal { Decimal::from_ratio(weight, total_weight) } + + +#[cfg(test)] +mod test { + use std::str::FromStr; + + use cosmwasm_std::{Decimal, Decimal256}; + use dexter::{asset::{AssetInfo, DecimalAsset}, uint128_with_precision}; + + use super::calc_spot_price; + + #[test] + fn test_spot_price() { + + let offer_asset_pool = DecimalAsset { + amount: Decimal256::from_atomics(uint128_with_precision!(1000u128, 6), 6).unwrap(), + info: AssetInfo::native_token("test1".to_string()), + }; + let ask_asset_pool = DecimalAsset { + amount: Decimal256::from_atomics(uint128_with_precision!(1000u128, 6), 6).unwrap(), + info: AssetInfo::native_token("test2".to_string()), + }; + + let offer_asset_weight = Decimal::from_str("0.5").unwrap(); + let ask_asset_weight = Decimal::from_str("0.5").unwrap(); + + let spot_price = calc_spot_price( + &offer_asset_pool, + &ask_asset_pool, + offer_asset_weight, + ask_asset_weight, + ).unwrap(); + + assert_eq!(spot_price, Decimal256::from_str("1").unwrap()); + + // 1 asset liquidity is 50% of the other asset liquidity + let offer_asset_pool = DecimalAsset { + amount: Decimal256::from_atomics(uint128_with_precision!(1000u128, 6), 6).unwrap(), + info: AssetInfo::native_token("test1".to_string()), + }; + + let ask_asset_pool = DecimalAsset { + amount: Decimal256::from_atomics(uint128_with_precision!(500u128, 6), 6).unwrap(), + info: AssetInfo::native_token("test2".to_string()), + }; + + let offer_asset_weight = Decimal::from_str("0.5").unwrap(); + let ask_asset_weight = Decimal::from_str("0.5").unwrap(); + + let spot_price = calc_spot_price( + &offer_asset_pool, + &ask_asset_pool, + offer_asset_weight, + ask_asset_weight, + ).unwrap(); + + assert_eq!(spot_price, Decimal256::from_str("0.5").unwrap()); + + // same liuquidity but different weights + let offer_asset_pool = DecimalAsset { + amount: Decimal256::from_atomics(uint128_with_precision!(1000u128, 6), 6).unwrap(), + info: AssetInfo::native_token("test1".to_string()), + }; + + let ask_asset_pool = DecimalAsset { + amount: Decimal256::from_atomics(uint128_with_precision!(1000u128, 6), 6).unwrap(), + info: AssetInfo::native_token("test2".to_string()), + }; + + let offer_asset_weight = Decimal::from_str("0.1").unwrap(); + let ask_asset_weight = Decimal::from_str("0.9").unwrap(); + + let spot_price = calc_spot_price( + &offer_asset_pool, + &ask_asset_pool, + offer_asset_weight, + ask_asset_weight, + ).unwrap(); + + assert_eq!(spot_price, Decimal256::from_str("0.111111111111111111").unwrap()); + + // different liquidity and different weights + let offer_asset_pool = DecimalAsset { + amount: Decimal256::from_atomics(uint128_with_precision!(1000u128, 6), 6).unwrap(), + info: AssetInfo::native_token("test1".to_string()), + }; + + let ask_asset_pool = DecimalAsset { + amount: Decimal256::from_atomics(uint128_with_precision!(500u128, 6), 6).unwrap(), + info: AssetInfo::native_token("test2".to_string()), + }; + + let offer_asset_weight = Decimal::from_str("0.1").unwrap(); + let ask_asset_weight = Decimal::from_str("0.9").unwrap(); + + let spot_price = calc_spot_price( + &offer_asset_pool, + &ask_asset_pool, + offer_asset_weight, + ask_asset_weight, + ).unwrap(); + + assert_eq!(spot_price, Decimal256::from_str("0.055555555555555555").unwrap()); + + // 0 liquidity + let offer_asset_pool = DecimalAsset { + amount: Decimal256::from_atomics(uint128_with_precision!(0u128, 6), 6).unwrap(), + info: AssetInfo::native_token("test1".to_string()), + }; + + let ask_asset_pool = DecimalAsset { + amount: Decimal256::from_atomics(uint128_with_precision!(500u128, 6), 6).unwrap(), + info: AssetInfo::native_token("test2".to_string()), + }; + + let offer_asset_weight = Decimal::from_str("0.1").unwrap(); + let ask_asset_weight = Decimal::from_str("0.9").unwrap(); + + let spot_price = calc_spot_price( + &offer_asset_pool, + &ask_asset_pool, + offer_asset_weight, + ask_asset_weight, + ).unwrap(); + + assert_eq!(spot_price, Decimal256::from_str("0").unwrap()); + } +} \ No newline at end of file From 355dce9a23bcb0daebf3e449165a7653f2fe100a Mon Sep 17 00:00:00 2001 From: betterclever Date: Fri, 1 Mar 2024 17:13:06 +0530 Subject: [PATCH 8/9] stableswap base case spot price with debug logs --- contracts/governance_admin/tests/utils/mod.rs | 2 - contracts/pools/stable_pool/src/contract.rs | 25 +++- contracts/pools/stable_pool/src/math.rs | 133 ++++++++++++++++-- contracts/pools/stable_pool/src/utils.rs | 29 +++- .../pools/stable_pool/tests/integration.rs | 28 ++-- .../stable_pool/tests/test_scaling_factor.rs | 12 +- contracts/pools/weighted_pool/src/utils.rs | 6 - 7 files changed, 188 insertions(+), 47 deletions(-) diff --git a/contracts/governance_admin/tests/utils/mod.rs b/contracts/governance_admin/tests/utils/mod.rs index 514bb718..74715fc5 100644 --- a/contracts/governance_admin/tests/utils/mod.rs +++ b/contracts/governance_admin/tests/utils/mod.rs @@ -56,8 +56,6 @@ fn move_compiled_contract_to_artifacts() { ]) .output() .unwrap(); - - // println!("output: {:?}", output); } fn read_wasm_byte_code_at_path(path: &str) -> Vec { diff --git a/contracts/pools/stable_pool/src/contract.rs b/contracts/pools/stable_pool/src/contract.rs index 4289b104..79a24885 100644 --- a/contracts/pools/stable_pool/src/contract.rs +++ b/contracts/pools/stable_pool/src/contract.rs @@ -240,7 +240,11 @@ pub fn execute( ExecuteMsg::UpdateFee { total_fee_bps } => { update_fee(deps, env, info, total_fee_bps, CONFIG, CONTRACT_NAME).map_err(|e| e.into()) } - ExecuteMsg::UpdateLiquidity { assets } => execute_update_liquidity(deps, env, info, assets), + ExecuteMsg::UpdateLiquidity { assets } => { + println!("\n Update liquidity called, sender: {}", info.sender); + println!("Assets: {:?}", assets); + execute_update_liquidity(deps, env, info, assets) + } } } @@ -413,15 +417,20 @@ pub fn execute_update_liquidity( let decimal_assets: Vec = transform_to_scaled_decimal_asset(deps.as_ref(), config.assets.clone())?; + println!("Decimal assets: {:?}", decimal_assets); + // Accumulate prices for the assets in the pool - if accumulate_prices( + let res = accumulate_prices( deps.as_ref(), env.clone(), math_config, &mut twap, &decimal_assets, - ) - .is_ok() + ); + + println!("Accumulate prices result: {:?}", res); + + if res.is_ok() // TWAP computation can fail in certain edge cases (when pool is empty for eg), for which you need // to allow tx to be successful rather than failing the tx. Accumulated prices can be used to // calculate TWAP oracle prices later and letting the tx be successful even when price accumulation @@ -1164,14 +1173,22 @@ pub fn query_spot_price( ) -> StdResult { let config: Config = CONFIG.load(deps.storage)?; let math_config: MathConfig = MATHCONFIG.load(deps.storage)?; + let stableswap_config: StableSwapConfig = STABLESWAP_CONFIG.load(deps.storage)?; let decimal_assets: Vec = transform_to_scaled_decimal_asset(deps, config.assets)?; let fee = config.fee_info; let amp = compute_current_amp(&math_config, &env)?; + let offer_asset_scaling_factor = stableswap_config.get_scaling_factor_for(&offer_asset_info) + .unwrap_or(Decimal256::one()); + let ask_asset_scaling_factor = stableswap_config.get_scaling_factor_for(&ask_asset_info) + .unwrap_or(Decimal256::one()); + let spot_price = calc_spot_price( &offer_asset_info, &ask_asset_info, + &offer_asset_scaling_factor, + &ask_asset_scaling_factor, &decimal_assets, fee, amp, diff --git a/contracts/pools/stable_pool/src/math.rs b/contracts/pools/stable_pool/src/math.rs index bc1fc09d..b82395e3 100644 --- a/contracts/pools/stable_pool/src/math.rs +++ b/contracts/pools/stable_pool/src/math.rs @@ -177,6 +177,8 @@ pub(crate) fn calc_y( pub(crate) fn calc_spot_price( from: &AssetInfo, to: &AssetInfo, + from_asset_scaling_factor: &Decimal256, + to_asset_scaling_factor: &Decimal256, pools: &[DecimalAsset], fee: FeeStructs, amp: u64, @@ -185,6 +187,20 @@ pub(crate) fn calc_spot_price( let from_asset = pools.iter().find(|asset| asset.info.eq(from)).unwrap(); let to_asset = pools.iter().find(|asset| asset.info.eq(to)).unwrap(); + // if from asset amount is zero, then return 0 as the spot price + // this is becasuse ideally both will be zero if the pool is empty, but we'll just check for from_asset + + println!("\n\nfrom asset: {:?} to_asset: {:?}", from_asset, to_asset); + + if from_asset.amount.is_zero() { + return Ok(SpotPrice { + from: from.clone(), + to: to.clone(), + price: Decimal256::zero(), + price_including_fee: Decimal256::zero(), + }); + } + // now, since it's really hard to find the price derivative of the stableswap invariant, we'll just use the // approximation as the price of a very very small trade. This is the same as the spot price. // We will define a very small trade as 0.001% of the pool liquidity @@ -236,9 +252,19 @@ pub(crate) fn calc_spot_price( let y_diff = to_asset.amount.checked_sub(y_price_decimal)?; let y_diff_including_fee = to_asset.amount.checked_sub(y_price_including_fee_decimal)?; - let spot_price = y_diff.checked_div(from_asset_small_trade_amount).unwrap(); - let spot_price_with_fee = y_diff_including_fee - .checked_div(from_asset_small_trade_amount) + let y_diff_unscaled = y_diff.without_scaling_factor(*to_asset_scaling_factor)?; + + let y_diff_including_fee_scaled = y_diff_including_fee.without_scaling_factor(*to_asset_scaling_factor)?; + + let from_asset_small_trade_amount_unscaled = + from_asset_small_trade_amount.without_scaling_factor(*from_asset_scaling_factor)?; + + let spot_price = y_diff_unscaled + .checked_div(from_asset_small_trade_amount_unscaled) + .unwrap(); + + let spot_price_with_fee = y_diff_including_fee_scaled + .checked_div(from_asset_small_trade_amount_unscaled) .unwrap(); let spot_price = SpotPrice { @@ -283,12 +309,28 @@ mod tests { ]; let pools_decimal = decimal_asset_pools_with_precision(pools.clone(), 6); - let spot_price = calc_spot_price(&pools[0].info,&pools[1].info, &pools_decimal, fee.clone(), amp_final); + let spot_price = calc_spot_price( + &pools[0].info, + &pools[1].info, + &Decimal256::from_str("1").unwrap(), + &Decimal256::from_str("1").unwrap(), + &pools_decimal, + fee.clone(), + amp_final + ); assert_eq!(spot_price.is_ok(), true); assert_eq!(spot_price.unwrap().price, Decimal256::from_str("0.999999900990108804").unwrap()); // test opposite direction - let spot_price = calc_spot_price(&pools[1].info,&pools[0].info, &pools_decimal, fee.clone(), amp_final); + let spot_price = calc_spot_price( + &pools[0].info, + &pools[1].info, + &Decimal256::from_str("1").unwrap(), + &Decimal256::from_str("1").unwrap(), + &pools_decimal, + fee.clone(), + amp_final + ); assert_eq!(spot_price.is_ok(), true); assert_eq!(spot_price.unwrap().price, Decimal256::from_str("0.999999900990108804").unwrap()); @@ -301,7 +343,15 @@ mod tests { let pools_decimal = decimal_asset_pools_with_precision(pools.clone(), 6); - let spot_price = calc_spot_price(&pools[0].info,&pools[1].info, &pools_decimal, fee.clone(), amp_final); + let spot_price = calc_spot_price( + &pools[0].info, + &pools[1].info, + &Decimal256::from_str("1").unwrap(), + &Decimal256::from_str("1").unwrap(), + &pools_decimal, + fee.clone(), + amp_final + ); assert_eq!(spot_price.is_ok(), true); assert_eq!(spot_price.unwrap().price, Decimal256::from_str("0.9999999009901089").unwrap()); @@ -312,7 +362,15 @@ mod tests { ]; let pools_decimal = decimal_asset_pools_with_precision(pools.clone(), 6); - let spot_price = calc_spot_price(&pools[0].info,&pools[1].info, &pools_decimal, fee.clone(), amp_final); + let spot_price = calc_spot_price( + &pools[0].info, + &pools[1].info, + &Decimal256::from_str("1").unwrap(), + &Decimal256::from_str("1").unwrap(), + &pools_decimal, + fee.clone(), + amp_final + ); assert_eq!(spot_price.is_ok(), true); assert_eq!(spot_price.unwrap().price, Decimal256::from_str("0.9999999009902").unwrap()); @@ -323,12 +381,28 @@ mod tests { ]; let pools_decimal = decimal_asset_pools_with_precision(pools.clone(), 6); - let spot_price = calc_spot_price(&pools[0].info,&pools[1].info, &pools_decimal, fee.clone(), amp_final); + let spot_price = calc_spot_price( + &pools[0].info, + &pools[1].info, + &Decimal256::from_str("1").unwrap(), + &Decimal256::from_str("1").unwrap(), + &pools_decimal, + fee.clone(), + amp_final + ); assert_eq!(spot_price.is_ok(), true); assert_eq!(spot_price.unwrap().price, Decimal256::from_str("0.9594664670086").unwrap()); // test opposite direction - let spot_price = calc_spot_price(&pools[1].info,&pools[0].info, &pools_decimal, fee.clone(), amp_final); + let spot_price = calc_spot_price( + &pools[1].info, + &pools[0].info, + &Decimal256::from_str("1").unwrap(), + &Decimal256::from_str("1").unwrap(), + &pools_decimal, + fee.clone(), + amp_final + ); assert_eq!(spot_price.is_ok(), true); assert_eq!(spot_price.unwrap().price, Decimal256::from_str("1.0422433526755").unwrap()); @@ -339,14 +413,31 @@ mod tests { ]; let pools_decimal = decimal_asset_pools_with_precision(pools.clone(), 6); - let spot_price = calc_spot_price(&pools[0].info,&pools[1].info, &pools_decimal, fee.clone(), amp_final); + let spot_price = calc_spot_price( + &pools[0].info, + &pools[1].info, + &Decimal256::from_str("1").unwrap(), + &Decimal256::from_str("1").unwrap(), + &pools_decimal, + fee.clone(), + amp_final + ); assert_eq!(spot_price.is_ok(), true); assert_eq!(spot_price.unwrap().price, Decimal256::from_str("0.8748087775978").unwrap()); // test opposite direction - let spot_price = calc_spot_price(&pools[1].info,&pools[0].info, &pools_decimal, fee.clone(), amp_final); + let spot_price = calc_spot_price( + &pools[1].info, + &pools[0].info, + &Decimal256::from_str("1").unwrap(), + &Decimal256::from_str("1").unwrap(), + &pools_decimal, + fee.clone(), + amp_final + ); assert_eq!(spot_price.is_ok(), true); let spot_price = spot_price.unwrap(); + assert_eq!(spot_price.clone().price, Decimal256::from_str("1.143093026548").unwrap()); assert_eq!(spot_price.price_including_fee, Decimal256::from_str("1.139663751743").unwrap()); @@ -359,7 +450,15 @@ mod tests { let pools_decimal = decimal_asset_pools_with_precision(pools.clone(), 6); - let spot_price = calc_spot_price(&pools[0].info,&pools[1].info, &pools_decimal, fee.clone(), amp_final); + let spot_price = calc_spot_price( + &pools[0].info, + &pools[1].info, + &Decimal256::from_str("1").unwrap(), + &Decimal256::from_str("1").unwrap(), + &pools_decimal, + fee.clone(), + amp_final + ); assert_eq!(spot_price.is_ok(), true); assert_eq!(spot_price.unwrap().price, Decimal256::from_str("0.99999991").unwrap()); @@ -372,7 +471,15 @@ mod tests { let pools_decimal = decimal_asset_pools_with_precision(pools.clone(), 18); - let spot_price = calc_spot_price(&pools[0].info,&pools[1].info, &pools_decimal, fee.clone(), amp_final); + let spot_price = calc_spot_price( + &pools[0].info, + &pools[1].info, + &Decimal256::from_str("1").unwrap(), + &Decimal256::from_str("1").unwrap(), + &pools_decimal, + fee.clone(), + amp_final + ); assert_eq!(spot_price.is_ok(), true); // simulation breaks at this value. // with integer invariant calculation, we must be able to go below this value. diff --git a/contracts/pools/stable_pool/src/utils.rs b/contracts/pools/stable_pool/src/utils.rs index 4cdc6a81..6f7a3978 100644 --- a/contracts/pools/stable_pool/src/utils.rs +++ b/contracts/pools/stable_pool/src/utils.rs @@ -6,7 +6,7 @@ use dexter::vault::FEE_PRECISION; use crate::error::ContractError; use crate::math::{calc_spot_price, calc_y}; -use crate::state::{MathConfig, CONFIG}; +use crate::state::{MathConfig, CONFIG, STABLESWAP_CONFIG}; use crate::state::{get_precision, Twap}; // --------x--------x--------x--------x--------x--------x--------x--------x--------- @@ -191,32 +191,53 @@ pub fn accumulate_prices( twap: &mut Twap, pools: &[DecimalAsset], ) -> Result<(), ContractError> { - let config = CONFIG.load(deps.storage)?; + + let config = CONFIG.load(deps.storage)?; + let stable_swap_config = STABLESWAP_CONFIG.load(deps.storage)?; // Calculate time elapsed since last price update. let block_time = env.block.time.seconds(); + println!("block_time: {}", block_time); + if block_time <= twap.block_time_last { + println!("block_time <= twap.block_time_last. hence returning Ok"); return Ok(()); } let time_elapsed = Uint128::from(block_time - twap.block_time_last); + println!("\nCurrent twap cp: {:?}", twap.cumulative_prices); + println!("pools :{:?}", pools); // Iterate over all asset pairs in the pool and accumulate prices. for (from, to, value) in twap.cumulative_prices.iter_mut() { let amp = compute_current_amp(&math_config, &env)?; + let from_asset_scaling_factor = stable_swap_config + .get_scaling_factor_for(&from) + .unwrap_or(Decimal256::one()); + + let to_asset_scaling_factor = stable_swap_config + .get_scaling_factor_for(&to) + .unwrap_or(Decimal256::one()); let spot_price = calc_spot_price( from, to, + &from_asset_scaling_factor, + &to_asset_scaling_factor, pools, config.fee_info.clone(), amp )?; + // ).unwrap(); let ask_asset_precision = get_precision(deps.storage, &to)?; - let return_amount = spot_price.price_including_fee.to_uint128_with_precision(ask_asset_precision)?; - + let return_amount = spot_price.price.to_uint128_with_precision(ask_asset_precision)?; + + println!("value before: {}", value); + println!("time_elapsed: {}", time_elapsed); + println!("spot price: {:?}", spot_price); *value = value.wrapping_add(time_elapsed.checked_mul(return_amount)?); + println!("value after: {}", value); } // Update last block time. diff --git a/contracts/pools/stable_pool/tests/integration.rs b/contracts/pools/stable_pool/tests/integration.rs index bb362364..67c82c7e 100644 --- a/contracts/pools/stable_pool/tests/integration.rs +++ b/contracts/pools/stable_pool/tests/integration.rs @@ -653,7 +653,7 @@ fn test_query_on_join_pool() { ask_info: AssetInfo::Token { contract_addr: token_instance0.clone(), }, - rate: Uint128::from(970173599820u128), + rate: Uint128::from(89999910u128), }, AssetExchangeRate { offer_info: AssetInfo::NativeToken { @@ -662,7 +662,7 @@ fn test_query_on_join_pool() { ask_info: AssetInfo::Token { contract_addr: token_instance1.clone(), }, - rate: Uint128::from(970173599820u128), + rate: Uint128::from(89999910u128), }, AssetExchangeRate { offer_info: AssetInfo::Token { @@ -671,7 +671,7 @@ fn test_query_on_join_pool() { ask_info: AssetInfo::NativeToken { denom: "axlusd".to_string(), }, - rate: Uint128::from(970173599820u128), + rate: Uint128::from(89999910u128), }, AssetExchangeRate { offer_info: AssetInfo::Token { @@ -680,7 +680,7 @@ fn test_query_on_join_pool() { ask_info: AssetInfo::Token { contract_addr: token_instance1.clone(), }, - rate: Uint128::from(970173599820u128), + rate: Uint128::from(89999910u128), }, AssetExchangeRate { offer_info: AssetInfo::Token { @@ -689,7 +689,7 @@ fn test_query_on_join_pool() { ask_info: AssetInfo::NativeToken { denom: "axlusd".to_string(), }, - rate: Uint128::from(970173599820u128), + rate: Uint128::from(89999910u128), }, AssetExchangeRate { offer_info: AssetInfo::Token { @@ -698,7 +698,7 @@ fn test_query_on_join_pool() { ask_info: AssetInfo::Token { contract_addr: token_instance0.clone(), }, - rate: Uint128::from(970173599820u128), + rate: Uint128::from(89999910u128), }, ], pool_twap_res.exchange_infos @@ -1046,6 +1046,8 @@ fn test_on_exit_pool() { ) .unwrap(); + println!("\n\nCreating pool"); + let (vault_instance, pool_addr, lp_token_addr, token_instance0, token_instance1, _) = instantiate_contracts_instance(&mut app, &owner); mint_some_tokens( @@ -1091,6 +1093,7 @@ fn test_on_exit_pool() { auto_stake: None, assets: Some(assets_msg.clone()), }; + app.execute_contract( alice_address.clone(), token_instance0.clone(), @@ -1115,6 +1118,7 @@ fn test_on_exit_pool() { ) .unwrap(); + println!("\n\nJoining pool"); app.execute_contract( alice_address.clone(), vault_instance.clone(), @@ -1323,7 +1327,7 @@ fn test_on_exit_pool() { ask_info: AssetInfo::Token { contract_addr: token_instance0.clone(), }, - rate: Uint128::from(999999991900u128), + rate: Uint128::from(89999910u128), }, AssetExchangeRate { offer_info: AssetInfo::NativeToken { @@ -1332,7 +1336,7 @@ fn test_on_exit_pool() { ask_info: AssetInfo::Token { contract_addr: token_instance1.clone(), }, - rate: Uint128::from(999999991900u128), + rate: Uint128::from(89999910u128), }, AssetExchangeRate { offer_info: AssetInfo::Token { @@ -1341,7 +1345,7 @@ fn test_on_exit_pool() { ask_info: AssetInfo::NativeToken { denom: "axlusd".to_string() }, - rate: Uint128::from(999999991900u128), + rate: Uint128::from(89999910u128), }, AssetExchangeRate { offer_info: AssetInfo::Token { @@ -1350,7 +1354,7 @@ fn test_on_exit_pool() { ask_info: AssetInfo::Token { contract_addr: token_instance1.clone(), }, - rate: Uint128::from(999999991900u128), + rate: Uint128::from(89999910u128), }, AssetExchangeRate { offer_info: AssetInfo::Token { @@ -1359,7 +1363,7 @@ fn test_on_exit_pool() { ask_info: AssetInfo::NativeToken { denom: "axlusd".to_string() }, - rate: Uint128::from(999999991900u128), + rate: Uint128::from(89999910u128), }, AssetExchangeRate { offer_info: AssetInfo::Token { @@ -1368,7 +1372,7 @@ fn test_on_exit_pool() { ask_info: AssetInfo::Token { contract_addr: token_instance0.clone(), }, - rate: Uint128::from(999999991900u128), + rate: Uint128::from(89999910u128), } ], pool_twap_res.exchange_infos diff --git a/contracts/pools/stable_pool/tests/test_scaling_factor.rs b/contracts/pools/stable_pool/tests/test_scaling_factor.rs index d141d7f7..e4cb3570 100644 --- a/contracts/pools/stable_pool/tests/test_scaling_factor.rs +++ b/contracts/pools/stable_pool/tests/test_scaling_factor.rs @@ -682,12 +682,12 @@ fn test_swap_different_lsd_assets() { AssetExchangeRate { offer_info: st_atom_asset.clone(), ask_info: stk_atom_asset.clone(), - rate: Uint128::from(1_020_833_322_000u64), + rate: Uint128::from(1_020_833_232_000u64), }, AssetExchangeRate { offer_info: stk_atom_asset.clone(), ask_info: st_atom_asset.clone(), - rate: Uint128::from(979_592_000u64), + rate: Uint128::from(979_591_000u64), }, ], ); @@ -726,12 +726,12 @@ fn test_swap_different_lsd_assets() { AssetExchangeRate { offer_info: st_atom_asset.clone(), ask_info: stk_atom_asset.clone(), - rate: Uint128::from(1_122_916_674_800u64), + rate: Uint128::from(1_122_916_575_800u64), }, AssetExchangeRate { offer_info: stk_atom_asset.clone(), ask_info: st_atom_asset.clone(), - rate: Uint128::from(1_077_551_100u64), + rate: Uint128::from(1_077_550_100u64), }, ], ); @@ -776,12 +776,12 @@ fn test_swap_different_lsd_assets() { AssetExchangeRate { offer_info: st_atom_asset.clone(), ask_info: stk_atom_asset.clone(), - rate: Uint128::from(1_327_087_498_600u64), + rate: Uint128::from(1_327_087_381_400u64), }, AssetExchangeRate { offer_info: stk_atom_asset.clone(), ask_info: st_atom_asset.clone(), - rate: Uint128::from(1_273_465_300u64), + rate: Uint128::from(1_273_464_300u64), }, ], ); diff --git a/contracts/pools/weighted_pool/src/utils.rs b/contracts/pools/weighted_pool/src/utils.rs index 7017d7a5..5b7add55 100644 --- a/contracts/pools/weighted_pool/src/utils.rs +++ b/contracts/pools/weighted_pool/src/utils.rs @@ -174,12 +174,6 @@ pub fn accumulate_prices( // we need to convert above decimal to Uint128 according to the precision of the ask asset let return_amount = spot_price.to_uint128_with_precision(ask_asset_precision)?; - println!(); - println!("weight -> from: {}, to: {}", from_weight, to_weight); - println!("offer_pool -> amount: {:?}, info: {:?}", offer_pool.amount, offer_pool.info); - println!("ask_pool -> amount: {:?}, info: {:?}", ask_pool.amount, ask_pool.info); - println!("return_amount: {}", return_amount); - // accumulate the price *value = value.wrapping_add(time_elapsed.checked_mul(return_amount)?); } From cd0eeac77e52be27a647b4b3fcba80e09cd24355 Mon Sep 17 00:00:00 2001 From: betterclever Date: Fri, 1 Mar 2024 17:20:58 +0530 Subject: [PATCH 9/9] remove debugging logs --- contracts/pools/stable_pool/src/contract.rs | 8 ++------ contracts/pools/stable_pool/src/math.rs | 3 --- contracts/pools/stable_pool/src/utils.rs | 10 ++-------- contracts/pools/stable_pool/tests/integration.rs | 3 --- contracts/pools/weighted_pool/src/contract.rs | 5 ----- 5 files changed, 4 insertions(+), 25 deletions(-) diff --git a/contracts/pools/stable_pool/src/contract.rs b/contracts/pools/stable_pool/src/contract.rs index 79a24885..40e58b5c 100644 --- a/contracts/pools/stable_pool/src/contract.rs +++ b/contracts/pools/stable_pool/src/contract.rs @@ -241,8 +241,6 @@ pub fn execute( update_fee(deps, env, info, total_fee_bps, CONFIG, CONTRACT_NAME).map_err(|e| e.into()) } ExecuteMsg::UpdateLiquidity { assets } => { - println!("\n Update liquidity called, sender: {}", info.sender); - println!("Assets: {:?}", assets); execute_update_liquidity(deps, env, info, assets) } } @@ -417,8 +415,6 @@ pub fn execute_update_liquidity( let decimal_assets: Vec = transform_to_scaled_decimal_asset(deps.as_ref(), config.assets.clone())?; - println!("Decimal assets: {:?}", decimal_assets); - // Accumulate prices for the assets in the pool let res = accumulate_prices( deps.as_ref(), @@ -428,13 +424,13 @@ pub fn execute_update_liquidity( &decimal_assets, ); - println!("Accumulate prices result: {:?}", res); - if res.is_ok() // TWAP computation can fail in certain edge cases (when pool is empty for eg), for which you need // to allow tx to be successful rather than failing the tx. Accumulated prices can be used to // calculate TWAP oracle prices later and letting the tx be successful even when price accumulation // fails doesn't cause any issues. + // UPDATE: We have now handled the edge case of pool join operation so this should ideally never fail. + // But we keep this check here for safety, so the pool operations don't fail because of this { TWAPINFO.save(deps.storage, &twap)?; } diff --git a/contracts/pools/stable_pool/src/math.rs b/contracts/pools/stable_pool/src/math.rs index b82395e3..9e6110b6 100644 --- a/contracts/pools/stable_pool/src/math.rs +++ b/contracts/pools/stable_pool/src/math.rs @@ -189,9 +189,6 @@ pub(crate) fn calc_spot_price( // if from asset amount is zero, then return 0 as the spot price // this is becasuse ideally both will be zero if the pool is empty, but we'll just check for from_asset - - println!("\n\nfrom asset: {:?} to_asset: {:?}", from_asset, to_asset); - if from_asset.amount.is_zero() { return Ok(SpotPrice { from: from.clone(), diff --git a/contracts/pools/stable_pool/src/utils.rs b/contracts/pools/stable_pool/src/utils.rs index 6f7a3978..8e56540d 100644 --- a/contracts/pools/stable_pool/src/utils.rs +++ b/contracts/pools/stable_pool/src/utils.rs @@ -197,16 +197,14 @@ pub fn accumulate_prices( // Calculate time elapsed since last price update. let block_time = env.block.time.seconds(); - println!("block_time: {}", block_time); + // no need to update if the block time is less than the last block time + // as multiplier is 0 in that case if block_time <= twap.block_time_last { - println!("block_time <= twap.block_time_last. hence returning Ok"); return Ok(()); } let time_elapsed = Uint128::from(block_time - twap.block_time_last); - println!("\nCurrent twap cp: {:?}", twap.cumulative_prices); - println!("pools :{:?}", pools); // Iterate over all asset pairs in the pool and accumulate prices. for (from, to, value) in twap.cumulative_prices.iter_mut() { @@ -233,11 +231,7 @@ pub fn accumulate_prices( let ask_asset_precision = get_precision(deps.storage, &to)?; let return_amount = spot_price.price.to_uint128_with_precision(ask_asset_precision)?; - println!("value before: {}", value); - println!("time_elapsed: {}", time_elapsed); - println!("spot price: {:?}", spot_price); *value = value.wrapping_add(time_elapsed.checked_mul(return_amount)?); - println!("value after: {}", value); } // Update last block time. diff --git a/contracts/pools/stable_pool/tests/integration.rs b/contracts/pools/stable_pool/tests/integration.rs index 67c82c7e..31a3dd3b 100644 --- a/contracts/pools/stable_pool/tests/integration.rs +++ b/contracts/pools/stable_pool/tests/integration.rs @@ -1046,8 +1046,6 @@ fn test_on_exit_pool() { ) .unwrap(); - println!("\n\nCreating pool"); - let (vault_instance, pool_addr, lp_token_addr, token_instance0, token_instance1, _) = instantiate_contracts_instance(&mut app, &owner); mint_some_tokens( @@ -1118,7 +1116,6 @@ fn test_on_exit_pool() { ) .unwrap(); - println!("\n\nJoining pool"); app.execute_contract( alice_address.clone(), vault_instance.clone(), diff --git a/contracts/pools/weighted_pool/src/contract.rs b/contracts/pools/weighted_pool/src/contract.rs index f37dfdae..1dfa1643 100644 --- a/contracts/pools/weighted_pool/src/contract.rs +++ b/contracts/pools/weighted_pool/src/contract.rs @@ -340,11 +340,6 @@ fn query_spot_price( amount: Decimal256::with_precision(pool_amount_ask_asset.amount, ask_asset_decimal)?, }; - println!( - "offer_decimal_asset: {:?}, ask_decimal_asset: {:?}", - offer_decimal_asset, ask_decimal_asset - ); - let offer_weight = get_weight(deps.storage, &offer_asset)?; let ask_weight = get_weight(deps.storage, &ask_asset)?;