From 92daa489892bb6a0b5b10d9086d0dfc941e356e2 Mon Sep 17 00:00:00 2001 From: wangjj9219 <183318287@qq.com> Date: Wed, 8 Jun 2022 11:56:39 +0800 Subject: [PATCH] Convert rebase token amount when calculate swap amount for StableAsset (#2169) * swap_with_exact_target call * update * add tests * convert amount when calculate swap amount for StableAsset * update --- modules/aggregated-dex/Cargo.toml | 3 +- modules/aggregated-dex/src/lib.rs | 230 ++++++++---- modules/aggregated-dex/src/mock.rs | 370 +++----------------- modules/aggregated-dex/src/tests.rs | 524 +++++++++++++++++----------- runtime/acala/src/lib.rs | 1 + runtime/karura/src/lib.rs | 1 + runtime/mandala/src/lib.rs | 1 + 7 files changed, 552 insertions(+), 578 deletions(-) diff --git a/modules/aggregated-dex/Cargo.toml b/modules/aggregated-dex/Cargo.toml index a4d715fc1a..b315b4ddae 100644 --- a/modules/aggregated-dex/Cargo.toml +++ b/modules/aggregated-dex/Cargo.toml @@ -18,9 +18,9 @@ support = { package = "module-support", path = "../support", default-features = primitives = { package = "acala-primitives", path = "../../primitives", default-features = false } nutsfinance-stable-asset = { path = "../../ecosystem-modules/stable-asset/lib/stable-asset", version = "0.1.0", default-features = false } module-dex = { package = "module-dex", path = "../dex", default-features = false } +orml-tokens = { path = "../../orml/tokens", default-features = false } [dev-dependencies] -orml-tokens = { path = "../../orml/tokens" } sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.22" } sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.22" } pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.22" } @@ -36,6 +36,7 @@ std = [ "frame-system/std", "sp-std/std", "orml-traits/std", + "orml-tokens/std", "support/std", "primitives/std", "nutsfinance-stable-asset/std", diff --git a/modules/aggregated-dex/src/lib.rs b/modules/aggregated-dex/src/lib.rs index ace34fb9fc..af678d9976 100644 --- a/modules/aggregated-dex/src/lib.rs +++ b/modules/aggregated-dex/src/lib.rs @@ -25,6 +25,7 @@ use frame_support::{pallet_prelude::*, transactional}; use frame_system::pallet_prelude::*; use nutsfinance_stable_asset::{traits::StableAsset as StableAssetT, PoolTokenIndex, StableAssetPoolId}; +use orml_tokens::ConvertBalance; use primitives::{Balance, CurrencyId}; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; @@ -75,6 +76,8 @@ pub mod module { #[pallet::constant] type SwapPathLimit: Get; + type RebaseTokenAmountConvertor: ConvertBalance; + type WeightInfo: WeightInfo; } @@ -124,8 +127,8 @@ pub mod module { pub fn swap_with_exact_supply( origin: OriginFor, paths: Vec, - supply_amount: Balance, - min_target_amount: Balance, + #[pallet::compact] supply_amount: Balance, + #[pallet::compact] min_target_amount: Balance, ) -> DispatchResult { let who = ensure_signed(origin)?; let paths: BoundedVec = @@ -134,6 +137,26 @@ pub mod module { Ok(()) } + #[pallet::weight(::WeightInfo::swap_with_exact_supply( + paths.iter().fold(0, |u, swap_path| match swap_path { + SwapPath::Dex(v) => u + (v.len() as u32), + SwapPath::Taiga(_, _, _) => u + 1 + }) + ))] + #[transactional] + pub fn swap_with_exact_target( + origin: OriginFor, + paths: Vec, + #[pallet::compact] target_amount: Balance, + #[pallet::compact] max_supply_amount: Balance, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + let paths: BoundedVec = + paths.try_into().map_err(|_| Error::::InvalidSwapPath)?; + let _ = Self::do_aggregated_swap(&who, &paths, SwapLimit::ExactTarget(max_supply_amount, target_amount))?; + Ok(()) + } + /// Update the aggregated swap paths for AggregatedSwap to swap TokenA to TokenB. /// /// Requires `GovernanceOrigin` @@ -169,6 +192,110 @@ pub mod module { } impl Pallet { + fn taiga_get_best_route( + supply_currency_id: CurrencyId, + target_currency_id: CurrencyId, + supply_amount: Balance, + ) -> Option<(StableAssetPoolId, PoolTokenIndex, PoolTokenIndex, Balance)> { + T::StableAsset::get_best_route( + supply_currency_id, + target_currency_id, + T::RebaseTokenAmountConvertor::convert_balance(supply_amount, supply_currency_id), + ) + .map(|(pool_id, input_index, output_index, output_amount)| { + ( + pool_id, + input_index, + output_index, + T::RebaseTokenAmountConvertor::convert_balance_back(output_amount, target_currency_id), + ) + }) + } + + fn taiga_get_swap_input_amount( + pool_id: StableAssetPoolId, + input_asset_index: PoolTokenIndex, + output_asset_index: PoolTokenIndex, + output_amount: Balance, + ) -> Option<(Balance, Balance)> { + let pool_info = T::StableAsset::pool(pool_id)?; + let input_currency_id = pool_info.assets.get(input_asset_index as usize)?; + let output_currency_id = pool_info.assets.get(output_asset_index as usize)?; + + T::StableAsset::get_swap_input_amount( + pool_id, + input_asset_index, + output_asset_index, + T::RebaseTokenAmountConvertor::convert_balance(output_amount, *output_currency_id), + ) + .map(|swap_result| { + ( + T::RebaseTokenAmountConvertor::convert_balance_back(swap_result.dx, *input_currency_id), + T::RebaseTokenAmountConvertor::convert_balance_back(swap_result.dy, *output_currency_id), + ) + }) + } + + fn taiga_get_swap_output_amount( + pool_id: StableAssetPoolId, + input_asset_index: PoolTokenIndex, + output_asset_index: PoolTokenIndex, + input_amount: Balance, + ) -> Option<(Balance, Balance)> { + let pool_info = T::StableAsset::pool(pool_id)?; + let input_currency_id = pool_info.assets.get(input_asset_index as usize)?; + let output_currency_id = pool_info.assets.get(output_asset_index as usize)?; + + T::StableAsset::get_swap_output_amount( + pool_id, + input_asset_index, + output_asset_index, + T::RebaseTokenAmountConvertor::convert_balance(input_amount, *input_currency_id), + ) + .map(|swap_result| { + ( + T::RebaseTokenAmountConvertor::convert_balance_back(swap_result.dx, *input_currency_id), + T::RebaseTokenAmountConvertor::convert_balance_back(swap_result.dy, *output_currency_id), + ) + }) + } + + fn taiga_swap( + who: &T::AccountId, + pool_id: StableAssetPoolId, + input_asset_index: PoolTokenIndex, + output_asset_index: PoolTokenIndex, + input_amount: Balance, + min_output_amount: Balance, + ) -> sp_std::result::Result<(Balance, Balance), DispatchError> { + let pool_info = T::StableAsset::pool(pool_id).ok_or(Error::::InvalidPoolId)?; + let asset_length = pool_info.assets.len() as u32; + let input_currency_id = pool_info + .assets + .get(input_asset_index as usize) + .ok_or(Error::::InvalidTokenIndex)?; + let output_currency_id = pool_info + .assets + .get(output_asset_index as usize) + .ok_or(Error::::InvalidTokenIndex)?; + + T::StableAsset::swap( + who, + pool_id, + input_asset_index, + output_asset_index, + T::RebaseTokenAmountConvertor::convert_balance(input_amount, *input_currency_id), + T::RebaseTokenAmountConvertor::convert_balance(min_output_amount, *output_currency_id), + asset_length, + ) + .map(|(dx, dy)| { + ( + T::RebaseTokenAmountConvertor::convert_balance_back(dx, *input_currency_id), + T::RebaseTokenAmountConvertor::convert_balance_back(dy, *output_currency_id), + ) + }) + } + fn check_swap_paths(paths: &[SwapPath]) -> sp_std::result::Result<(CurrencyId, CurrencyId), DispatchError> { ensure!(!paths.is_empty(), Error::::InvalidSwapPath); let mut supply_currency_id: Option = None; @@ -247,13 +374,14 @@ impl Pallet { } SwapPath::Taiga(pool_id, supply_asset_index, target_asset_index) => { // use the output of the previous swap as input. - output_amount = T::StableAsset::get_swap_output_amount( + let (_, actual_output_amount) = Self::taiga_get_swap_output_amount( *pool_id, *supply_asset_index, *target_asset_index, output_amount, - ) - .map(|swap_result| swap_result.dy)?; + )?; + + output_amount = actual_output_amount; } } } @@ -277,13 +405,15 @@ impl Pallet { input_amount = supply_amount; } SwapPath::Taiga(pool_id, supply_asset_index, target_asset_index) => { - input_amount = T::StableAsset::get_swap_input_amount( + // calculate the input amount + let (actual_input_amount, _) = Self::taiga_get_swap_input_amount( *pool_id, *supply_asset_index, *target_asset_index, input_amount, - ) - .map(|swap_result| swap_result.dx)?; + )?; + + input_amount = actual_input_amount; } } } @@ -328,18 +458,14 @@ impl Pallet { output_amount = actual_target; } SwapPath::Taiga(pool_id, supply_asset_index, target_asset_index) => { - let pool_info = T::StableAsset::pool(*pool_id).ok_or(Error::::InvalidPoolId)?; - let asset_length = pool_info.assets.len() as u32; - // use the output of the previous swap as input. - let (_, actual_target) = T::StableAsset::swap( + let (_, actual_target) = Self::taiga_swap( who, *pool_id, *supply_asset_index, *target_asset_index, output_amount, Zero::zero(), - asset_length, )?; output_amount = actual_target; @@ -353,43 +479,12 @@ impl Pallet { Ok((exact_supply_amount, output_amount)) } // Calculate the supply amount first, then execute swap with ExactSupply - SwapLimit::ExactTarget(max_supply_amount, exact_target_amount) => { - let mut input_amount: Balance = exact_target_amount; - - for path in paths.iter().rev() { - match path { - SwapPath::Dex(dex_path) => { - // calculate the supply amount - let (supply_amount, _) = T::DEX::get_swap_amount( - dex_path, - SwapLimit::ExactTarget(Balance::max_value(), input_amount), - ) - .ok_or(Error::::CannotSwap)?; - - input_amount = supply_amount; - } - SwapPath::Taiga(pool_id, supply_asset_index, target_asset_index) => { - let swap_result = T::StableAsset::get_swap_input_amount( - *pool_id, - *supply_asset_index, - *target_asset_index, - input_amount, - ) - .ok_or(Error::::CannotSwap)?; - - input_amount = swap_result.dx; - } - } - } - - // the result must meet the SwapLimit. - ensure!( - !input_amount.is_zero() && input_amount <= max_supply_amount, - Error::::CannotSwap - ); + SwapLimit::ExactTarget(_max_supply_amount, exact_target_amount) => { + let (supply_amount, _) = + Self::get_aggregated_swap_amount(paths, swap_limit).ok_or(Error::::CannotSwap)?; // actually swap by `ExactSupply` limit - Self::do_aggregated_swap(who, paths, SwapLimit::ExactSupply(input_amount, exact_target_amount)) + Self::do_aggregated_swap(who, paths, SwapLimit::ExactSupply(supply_amount, exact_target_amount)) } } } @@ -434,6 +529,10 @@ impl Swap for DexSwap { /// Swap by Taiga pool. pub struct TaigaSwap(PhantomData); impl Swap for TaigaSwap { + // !!! Note: if ths limit is `ExactTarget` and the `max_supply_amount` will cause overflow in + // StableAsset, will return `None`. Because the `get_best_route` of StableAsset treats it as the + // actual input amount. However, it will fail so will not cause loss. Maybe need to modiry + // StableAsset impl to avoid this risk. fn get_swap_amount( supply_currency_id: CurrencyId, target_currency_id: CurrencyId, @@ -442,25 +541,30 @@ impl Swap for TaigaSwap { match limit { SwapLimit::ExactSupply(supply_amount, min_target_amount) => { let (pool_id, input_index, output_index, _) = - T::StableAsset::get_best_route(supply_currency_id, target_currency_id, supply_amount)?; + Pallet::::taiga_get_best_route(supply_currency_id, target_currency_id, supply_amount)?; - if let Some(swap_result) = - T::StableAsset::get_swap_output_amount(pool_id, input_index, output_index, supply_amount) + if let Some((input_amount, output_amount)) = + Pallet::::taiga_get_swap_output_amount(pool_id, input_index, output_index, supply_amount) { - if swap_result.dy >= min_target_amount { - return Some((swap_result.dx, swap_result.dy)); + if output_amount >= min_target_amount { + return Some((input_amount, output_amount)); } } } SwapLimit::ExactTarget(max_supply_amount, target_amount) => { let (pool_id, input_index, output_index, _) = - T::StableAsset::get_best_route(supply_currency_id, target_currency_id, max_supply_amount)?; + Pallet::::taiga_get_best_route(supply_currency_id, target_currency_id, max_supply_amount)?; - if let Some(swap_result) = - T::StableAsset::get_swap_input_amount(pool_id, input_index, output_index, target_amount) + if let Some((input_amount, _)) = + Pallet::::taiga_get_swap_input_amount(pool_id, input_index, output_index, target_amount) { - if !swap_result.dx.is_zero() && swap_result.dx <= max_supply_amount { - return Some((swap_result.dx, swap_result.dy)); + if !input_amount.is_zero() && input_amount <= max_supply_amount { + // actually swap by `ExactSupply` limit + return Self::get_swap_amount( + supply_currency_id, + target_currency_id, + SwapLimit::ExactSupply(input_amount, target_amount), + ); } } } @@ -486,22 +590,18 @@ impl Swap for TaigaSwap { }; let (pool_id, input_index, output_index, _) = - T::StableAsset::get_best_route(supply_currency_id, target_currency_id, min_target_amount) + Pallet::::taiga_get_best_route(supply_currency_id, target_currency_id, supply_amount) .ok_or(Error::::CannotSwap)?; - let pool_info = T::StableAsset::pool(pool_id).ok_or(Error::::InvalidPoolId)?; - let asset_length = pool_info.assets.len() as u32; - - let (actual_supply, actual_target) = T::StableAsset::swap( + let (actual_supply, actual_target) = Pallet::::taiga_swap( who, pool_id, input_index, output_index, supply_amount, min_target_amount, - asset_length, )?; - ensure!(actual_target >= min_target_amount, Error::::CannotSwap); + ensure!(actual_target >= min_target_amount, Error::::CannotSwap); Ok((actual_supply, actual_target)) } } diff --git a/modules/aggregated-dex/src/mock.rs b/modules/aggregated-dex/src/mock.rs index ee99fd7da8..4bb4c93fdd 100644 --- a/modules/aggregated-dex/src/mock.rs +++ b/modules/aggregated-dex/src/mock.rs @@ -22,17 +22,16 @@ use super::*; use frame_support::{ - ord_parameter_types, parameter_types, - traits::{ConstU32, ConstU64, Everything, Nothing}, + match_types, ord_parameter_types, parameter_types, + traits::{ConstU128, ConstU32, ConstU64, Everything, Nothing}, PalletId, }; -use frame_system::{EnsureSignedBy, RawOrigin}; -use nutsfinance_stable_asset::{RedeemProportionResult, StableAssetPoolInfo, SwapResult}; +use frame_system::EnsureSignedBy; pub use orml_traits::{parameter_type_with_key, MultiCurrency}; use primitives::{Amount, TokenSymbol, TradingPair}; use sp_runtime::{ testing::{Header, H256}, - traits::IdentityLookup, + traits::{Bounded, IdentityLookup}, AccountId32, FixedPointNumber, }; pub use support::ExchangeRate; @@ -122,340 +121,82 @@ impl module_dex::Config for Runtime { type OnLiquidityPoolUpdated = (); } -#[derive(Clone)] -pub struct TaigaSwapStatus { - pub currency_id_0: CurrencyId, - pub currency_id_1: CurrencyId, - pub stable_asset_id: CurrencyId, - pub exchange_rate_1_for_0: ExchangeRate, +pub struct EnsurePoolAssetId; +impl nutsfinance_stable_asset::traits::ValidateAssetId for EnsurePoolAssetId { + fn validate(currency_id: CurrencyId) -> bool { + matches!(currency_id, CurrencyId::StableAssetPoolToken(_)) + } } -pub struct MockStableAsset; -impl StableAssetT for MockStableAsset { +pub struct ConvertBalanceHoma; +impl orml_tokens::ConvertBalance for ConvertBalanceHoma { type AssetId = CurrencyId; - type AtLeast64BitUnsigned = Balance; - type Balance = Balance; - type AccountId = AccountId; - type BlockNumber = BlockNumber; - - fn pool_count() -> StableAssetPoolId { - unimplemented!() - } - - fn pool( - _id: StableAssetPoolId, - ) -> Option> { - TaigaConfig::get().map(|taiga_config| StableAssetPoolInfo { - pool_asset: taiga_config.stable_asset_id, - assets: vec![taiga_config.currency_id_0, taiga_config.currency_id_1], - precisions: vec![], - mint_fee: Default::default(), - swap_fee: Default::default(), - redeem_fee: Default::default(), - total_supply: Default::default(), - a: Default::default(), - a_block: Default::default(), - future_a: Default::default(), - future_a_block: Default::default(), - balances: Default::default(), - fee_recipient: BOB, - account_id: BOB, - yield_recipient: BOB, - precision: Default::default(), - }) - } - - fn create_pool( - _pool_asset: Self::AssetId, - _assets: Vec, - _precisions: Vec, - _mint_fee: Self::Balance, - _swap_fee: Self::Balance, - _redeem_fee: Self::Balance, - _initial_a: Self::Balance, - _fee_recipient: Self::AccountId, - _yield_recipient: Self::AccountId, - _precision: Self::Balance, - ) -> DispatchResult { - unimplemented!() - } - - fn mint( - _who: &Self::AccountId, - _pool_id: StableAssetPoolId, - _amounts: Vec, - _min_mint_amount: Self::Balance, - ) -> DispatchResult { - unimplemented!() - } - fn swap( - who: &Self::AccountId, - _pool_id: StableAssetPoolId, - i: PoolTokenIndex, - j: PoolTokenIndex, - dx: Self::Balance, - min_dy: Self::Balance, - _asset_length: u32, - ) -> sp_std::result::Result<(Self::Balance, Self::Balance), DispatchError> { - if let Some(taiga_config) = TaigaConfig::get() { - let (supply_currency_id, target_currency_id, swap_exchange_rate) = match (i, j) { - (0, 1) => ( - taiga_config.currency_id_0, - taiga_config.currency_id_1, - taiga_config.exchange_rate_1_for_0, - ), - (1, 0) => ( - taiga_config.currency_id_1, - taiga_config.currency_id_0, - taiga_config.exchange_rate_1_for_0.reciprocal().unwrap(), - ), - _ => return Err(Error::::CannotSwap.into()), - }; - let actual_target = swap_exchange_rate.saturating_mul_int(dx); - ensure!(actual_target >= min_dy, Error::::CannotSwap); - - Tokens::withdraw(supply_currency_id, who, dx)?; - Tokens::deposit(target_currency_id, who, actual_target)?; - - Ok((dx, actual_target)) - } else { - Err(Error::::CannotSwap.into()) + fn convert_balance(balance: Balance, asset_id: CurrencyId) -> Balance { + match asset_id { + LDOT => ExchangeRate::saturating_from_rational(1, 10) + .checked_mul_int(balance) + .unwrap_or(Bounded::max_value()), + _ => balance, } } - fn redeem_proportion( - _who: &Self::AccountId, - _pool_id: StableAssetPoolId, - _amount: Self::Balance, - _min_redeem_amounts: Vec, - ) -> DispatchResult { - unimplemented!() - } - - fn redeem_single( - _who: &Self::AccountId, - _pool_id: StableAssetPoolId, - _amount: Self::Balance, - _i: PoolTokenIndex, - _min_redeem_amount: Self::Balance, - _asset_length: u32, - ) -> DispatchResult { - unimplemented!() - } - - fn redeem_multi( - _who: &Self::AccountId, - _pool_id: StableAssetPoolId, - _amounts: Vec, - _max_redeem_amount: Self::Balance, - ) -> DispatchResult { - unimplemented!() - } - - fn collect_fee( - _pool_id: StableAssetPoolId, - _pool_info: &mut StableAssetPoolInfo< - Self::AssetId, - Self::Balance, - Self::Balance, - Self::AccountId, - Self::BlockNumber, - >, - ) -> DispatchResult { - unimplemented!() - } - - fn update_balance( - _pool_id: StableAssetPoolId, - _pool_info: &mut StableAssetPoolInfo< - Self::AssetId, - Self::Balance, - Self::Balance, - Self::AccountId, - Self::BlockNumber, - >, - ) -> DispatchResult { - unimplemented!() - } - - fn collect_yield( - _pool_id: StableAssetPoolId, - _pool_info: &mut StableAssetPoolInfo< - Self::AssetId, - Self::Balance, - Self::Balance, - Self::AccountId, - Self::BlockNumber, - >, - ) -> DispatchResult { - unimplemented!() - } - - fn modify_a(_pool_id: StableAssetPoolId, _a: Self::Balance, _future_a_block: Self::BlockNumber) -> DispatchResult { - unimplemented!() - } - - fn get_collect_yield_amount( - _pool_info: &StableAssetPoolInfo< - Self::AssetId, - Self::Balance, - Self::Balance, - Self::AccountId, - Self::BlockNumber, - >, - ) -> Option> { - unimplemented!() - } - - fn get_balance_update_amount( - _pool_info: &StableAssetPoolInfo< - Self::AssetId, - Self::Balance, - Self::Balance, - Self::AccountId, - Self::BlockNumber, - >, - ) -> Option> { - unimplemented!() - } - - fn get_redeem_proportion_amount( - _pool_info: &StableAssetPoolInfo< - Self::AssetId, - Self::Balance, - Self::Balance, - Self::AccountId, - Self::BlockNumber, - >, - _amount_bal: Self::Balance, - ) -> Option> { - unimplemented!() - } - - fn get_best_route( - input_asset: Self::AssetId, - output_asset: Self::AssetId, - input_amount: Self::Balance, - ) -> Option<(StableAssetPoolId, PoolTokenIndex, PoolTokenIndex, Self::Balance)> { - TaigaConfig::get().and_then(|taiga_config| { - if input_asset == taiga_config.currency_id_0 && output_asset == taiga_config.currency_id_1 { - Some(( - 0, - 0, - 1, - taiga_config.exchange_rate_1_for_0.saturating_mul_int(input_amount), - )) - } else if output_asset == taiga_config.currency_id_0 && input_asset == taiga_config.currency_id_1 { - Some(( - 0, - 1, - 0, - taiga_config - .exchange_rate_1_for_0 - .reciprocal() - .unwrap() - .saturating_mul_int(input_amount), - )) - } else { - None - } - }) - } - - fn get_swap_output_amount( - _pool_id: StableAssetPoolId, - input_index: PoolTokenIndex, - output_index: PoolTokenIndex, - dx_bal: Self::Balance, - ) -> Option> { - TaigaConfig::get().and_then(|taiga_config| { - let input_to_output_rate = match (input_index, output_index) { - (0, 1) => taiga_config.exchange_rate_1_for_0, - (1, 0) => taiga_config.exchange_rate_1_for_0.reciprocal().unwrap(), - _ => return None, - }; - let target_amount = input_to_output_rate.saturating_mul_int(dx_bal); - - Some(SwapResult { - dx: dx_bal, - dy: target_amount, - ..Default::default() - }) - }) - } - - fn get_swap_input_amount( - _pool_id: StableAssetPoolId, - input_index: PoolTokenIndex, - output_index: PoolTokenIndex, - dy_bal: Self::Balance, - ) -> Option> { - TaigaConfig::get().and_then(|taiga_config| { - let output_to_input_rate = match (input_index, output_index) { - (0, 1) => taiga_config.exchange_rate_1_for_0.reciprocal().unwrap(), - (1, 0) => taiga_config.exchange_rate_1_for_0, - _ => return None, - }; - let supply_amount = output_to_input_rate.saturating_mul_int(dy_bal); - - Some(SwapResult { - dx: supply_amount, - dy: dy_bal, - ..Default::default() - }) - }) + fn convert_balance_back(balance: Balance, asset_id: CurrencyId) -> Balance { + match asset_id { + LDOT => ExchangeRate::saturating_from_rational(10, 1) + .checked_mul_int(balance) + .unwrap_or(Bounded::max_value()), + _ => balance, + } } } -pub fn set_taiga_swap(currency_id_0: CurrencyId, currency_id_1: CurrencyId, exchange_rate_1_for_0: ExchangeRate) { - TaigaConfig::set(Some(TaigaSwapStatus { - currency_id_0, - currency_id_1, - stable_asset_id: STABLE_ASSET, - exchange_rate_1_for_0, - })); +match_types! { + pub type IsLiquidToken: impl Contains = { + CurrencyId::Token(TokenSymbol::LDOT) + }; } -pub fn set_dex_swap_joint_list(joints: Vec>) { - DexSwapJointList::set(joints); +type RebaseTokens = orml_tokens::Combiner< + AccountId, + IsLiquidToken, + orml_tokens::Mapper, + Tokens, +>; + +parameter_types! { + pub const StableAssetPalletId: PalletId = PalletId(*b"nuts/sta"); } -pub fn inject_liquidity( - currency_id_a: CurrencyId, - currency_id_b: CurrencyId, - max_amount_a: Balance, - max_amount_b: Balance, -) -> Result<(), &'static str> { - // set balance - Tokens::deposit(currency_id_a, &BOB, max_amount_a)?; - Tokens::deposit(currency_id_b, &BOB, max_amount_b)?; - - let _ = Dex::enable_trading_pair(RawOrigin::Signed(BOB.clone()).into(), currency_id_a, currency_id_b); - Dex::add_liquidity( - RawOrigin::Signed(BOB).into(), - currency_id_a, - currency_id_b, - max_amount_a, - max_amount_b, - Default::default(), - false, - )?; - - Ok(()) +impl nutsfinance_stable_asset::Config for Runtime { + type Event = Event; + type AssetId = CurrencyId; + type Balance = Balance; + type Assets = RebaseTokens; + type PalletId = StableAssetPalletId; + + type AtLeast64BitUnsigned = u128; + type FeePrecision = ConstU128<10_000_000_000>; // 10 decimals + type APrecision = ConstU128<100>; // 2 decimals + type PoolAssetLimit = ConstU32<5>; + type SwapExactOverAmount = ConstU128<100>; + type WeightInfo = (); + type ListingOrigin = EnsureSignedBy; + type EnsurePoolAssetId = EnsurePoolAssetId; } parameter_types! { pub static DexSwapJointList: Vec> = vec![]; - pub static TaigaConfig: Option = None; + pub const GetLiquidCurrencyId: CurrencyId = LDOT; } impl Config for Runtime { type DEX = Dex; - type StableAsset = MockStableAsset; + type StableAsset = StableAsset; type GovernanceOrigin = EnsureSignedBy; type DexSwapJointList = DexSwapJointList; type SwapPathLimit = ConstU32<3>; + type RebaseTokenAmountConvertor = ConvertBalanceHoma; type WeightInfo = (); } @@ -472,6 +213,7 @@ frame_support::construct_runtime!( AggregatedDex: aggregated_dex::{Pallet, Call, Storage}, Dex: module_dex::{Pallet, Call, Storage, Config, Event}, Tokens: orml_tokens::{Pallet, Storage, Event, Config}, + StableAsset: nutsfinance_stable_asset::{Pallet, Call, Storage, Event}, } ); diff --git a/modules/aggregated-dex/src/tests.rs b/modules/aggregated-dex/src/tests.rs index 3d5e06417c..26c826ed5a 100644 --- a/modules/aggregated-dex/src/tests.rs +++ b/modules/aggregated-dex/src/tests.rs @@ -23,7 +23,92 @@ use super::*; use frame_support::{assert_noop, assert_ok}; use mock::*; -use sp_runtime::{traits::BadOrigin, FixedPointNumber}; +use nutsfinance_stable_asset::traits::StableAsset as StableAssetT; +use sp_runtime::traits::BadOrigin; + +fn set_dex_swap_joint_list(joints: Vec>) { + DexSwapJointList::set(joints); +} + +fn inject_liquidity( + currency_id_a: CurrencyId, + currency_id_b: CurrencyId, + max_amount_a: Balance, + max_amount_b: Balance, +) -> Result<(), &'static str> { + // set balance + Tokens::deposit(currency_id_a, &BOB, max_amount_a)?; + Tokens::deposit(currency_id_b, &BOB, max_amount_b)?; + + let _ = Dex::enable_trading_pair(Origin::signed(BOB.clone()), currency_id_a, currency_id_b); + Dex::add_liquidity( + Origin::signed(BOB), + currency_id_a, + currency_id_b, + max_amount_a, + max_amount_b, + Default::default(), + false, + )?; + + Ok(()) +} + +fn inital_taiga_dot_ldot_pool() -> DispatchResult { + ::create_pool( + STABLE_ASSET, + vec![DOT, LDOT], + vec![1u128, 1u128], + 0, + 0, + 0, + 3000u128, + BOB, + BOB, + 10_000_000_000u128, + )?; + + Tokens::deposit(DOT, &BOB, 100_000_000_000u128)?; + Tokens::deposit(LDOT, &BOB, 1_000_000_000_000u128)?; + + ::mint(&BOB, 0, vec![100_000_000_000u128, 100_000_000_000u128], 0)?; + + Ok(()) +} + +#[test] +fn rebase_token_amount_convert_work() { + ExtBuilder::default().build().execute_with(|| { + assert_ok!(inital_taiga_dot_ldot_pool()); + + assert_eq!( + AggregatedDex::taiga_get_best_route(DOT, LDOT, 100_000_000u128), + Some((0, 0, 1, 999_983_600u128)) + ); + assert_eq!( + AggregatedDex::taiga_get_best_route(LDOT, DOT, 1_000_000_000u128), + Some((0, 1, 0, 99_998_360u128)) + ); + + assert_eq!( + AggregatedDex::taiga_get_swap_input_amount(0, 0, 1, 999_983_600u128), + Some((100_000_098u128, 999_983_600u128)) + ); + assert_eq!( + AggregatedDex::taiga_get_swap_output_amount(0, 0, 1, 100_000_000u128), + Some((100_000_000u128, 999_983_600u128)) + ); + + assert_eq!(Tokens::free_balance(DOT, &ALICE), 100_000_000_000u128); + assert_eq!(Tokens::free_balance(LDOT, &ALICE), 0); + assert_eq!( + AggregatedDex::taiga_swap(&ALICE, 0, 0, 1, 100_000_000u128, 0), + Ok((100_000_000u128, 999_983_600u128)) + ); + assert_eq!(Tokens::free_balance(DOT, &ALICE), 99_900_000_000u128); + assert_eq!(Tokens::free_balance(LDOT, &ALICE), 999_983_600u128); + }); +} #[test] fn dex_swap_get_swap_amount_work() { @@ -148,36 +233,44 @@ fn taiga_swap_get_swap_amount_work() { None ); - set_taiga_swap(DOT, LDOT, ExchangeRate::saturating_from_rational(10, 1)); + assert_ok!(inital_taiga_dot_ldot_pool()); assert_eq!( TaigaSwap::::get_swap_amount(DOT, AUSD, SwapLimit::ExactSupply(1_000_000_000u128, 0)), None ); assert_eq!( TaigaSwap::::get_swap_amount(DOT, LDOT, SwapLimit::ExactSupply(1_000_000_000u128, 0)), - Some((1_000_000_000u128, 10_000_000_000u128)) + Some((1_000_000_000u128, 9_998_360_750u128)) ); assert_eq!( TaigaSwap::::get_swap_amount( DOT, LDOT, - SwapLimit::ExactSupply(1_000_000_000u128, 10_000_000_001u128) + SwapLimit::ExactSupply(1_000_000_000u128, 9_998_360_751u128) ), None ); assert_eq!( - TaigaSwap::::get_swap_amount(DOT, AUSD, SwapLimit::ExactTarget(u128::MAX, 10_000_000_000u128)), + TaigaSwap::::get_swap_amount( + DOT, + AUSD, + SwapLimit::ExactTarget(10_000_000_000u128, 10_000_000_000u128) + ), None ); assert_eq!( - TaigaSwap::::get_swap_amount(DOT, LDOT, SwapLimit::ExactTarget(u128::MAX, 10_000_000_000u128)), - Some((1_000_000_000u128, 10_000_000_000u128)) + TaigaSwap::::get_swap_amount( + DOT, + LDOT, + SwapLimit::ExactTarget(2_000_000_000u128, 9_998_360_750u128) + ), + Some((1_000_000_098u128, 9_998_361_730u128)) ); assert_eq!( TaigaSwap::::get_swap_amount( DOT, LDOT, - SwapLimit::ExactTarget(999_999_999u128, 10_000_000_000u128) + SwapLimit::ExactTarget(1_000_000_097u128, 9_998_360_750u128) ), None ); @@ -185,9 +278,9 @@ fn taiga_swap_get_swap_amount_work() { TaigaSwap::::get_swap_amount( LDOT, DOT, - SwapLimit::ExactTarget(100_000_000_000u128, 1_000_000_001u128) + SwapLimit::ExactTarget(100_000_000_000u128, 1_000_000_000u128) ), - Some((10_000_000_010u128, 1_000_000_001u128)) + Some((10_001_640_760u128, 1_000_000_098u128)) ); }); } @@ -196,64 +289,58 @@ fn taiga_swap_get_swap_amount_work() { fn taiga_swap_swap_work() { ExtBuilder::default().build().execute_with(|| { assert_noop!( - TaigaSwap::::swap( - &ALICE, - LDOT, - DOT, - SwapLimit::ExactSupply(1_000_000_000u128, 10_000_000_001u128) - ), + TaigaSwap::::swap(&ALICE, DOT, LDOT, SwapLimit::ExactSupply(1_000_000_000u128, 0)), Error::::CannotSwap ); assert_noop!( TaigaSwap::::swap( &ALICE, - LDOT, DOT, - SwapLimit::ExactTarget(1_000_000_000u128, 10_000_000_001u128) + LDOT, + SwapLimit::ExactTarget(10_000_000_000u128, 9_998_360_750u128) ), Error::::CannotSwap ); - set_taiga_swap(DOT, LDOT, ExchangeRate::saturating_from_rational(10, 1)); + assert_ok!(inital_taiga_dot_ldot_pool()); assert_eq!(Tokens::free_balance(DOT, &ALICE), 100_000_000_000u128); assert_eq!(Tokens::free_balance(LDOT, &ALICE), 0); - assert_ok!(TaigaSwap::::swap( - &ALICE, - DOT, - LDOT, - SwapLimit::ExactSupply(1_000_000_000u128, 10_000_000_000u128) - )); + assert_eq!( + TaigaSwap::::swap(&ALICE, DOT, LDOT, SwapLimit::ExactSupply(1_000_000_000u128, 0)), + Ok((1_000_000_000u128, 9_998_360_750u128)) + ); assert_eq!(Tokens::free_balance(DOT, &ALICE), 99_000_000_000u128); - assert_eq!(Tokens::free_balance(LDOT, &ALICE), 10_000_000_000u128); + assert_eq!(Tokens::free_balance(LDOT, &ALICE), 9_998_360_750u128); assert_noop!( TaigaSwap::::swap( &ALICE, DOT, LDOT, - SwapLimit::ExactSupply(1_000_000_000u128, 10_000_000_001u128) + SwapLimit::ExactSupply(1_000_000_000u128, 10_000_000_000u128) ), - Error::::CannotSwap + nutsfinance_stable_asset::Error::::SwapUnderMin ); - assert_eq!(Tokens::free_balance(DOT, &ALICE), 99_000_000_000u128); - assert_eq!(Tokens::free_balance(LDOT, &ALICE), 10_000_000_000u128); - assert_ok!(TaigaSwap::::swap( - &ALICE, - DOT, - LDOT, - SwapLimit::ExactTarget(10_000_000_000u128, 10_000_000_000u128) - )); - assert_eq!(Tokens::free_balance(DOT, &ALICE), 98_000_000_000u128); - assert_eq!(Tokens::free_balance(LDOT, &ALICE), 20_000_000_000u128); + assert_eq!( + TaigaSwap::::swap( + &ALICE, + DOT, + LDOT, + SwapLimit::ExactTarget(2_000_000_000u128, 10_000_000_000u128) + ), + Ok((1_000_492_274u128, 10_000_000_980u128)) + ); + assert_eq!(Tokens::free_balance(DOT, &ALICE), 97_999_507_726u128); + assert_eq!(Tokens::free_balance(LDOT, &ALICE), 19_998_361_730u128); assert_noop!( TaigaSwap::::swap( &ALICE, DOT, LDOT, - SwapLimit::ExactTarget(999_999_999u128, 10_000_000_000u128) + SwapLimit::ExactTarget(1_000_000_000u128, 10_000_000_000u128) ), Error::::CannotSwap ); @@ -276,50 +363,66 @@ fn either_dex_or_taiga_swap_get_swap_amount_work() { None ); assert_eq!( - DexSwap::::get_swap_amount(DOT, LDOT, SwapLimit::ExactTarget(u128::MAX, 10_000_000_000u128)), + DexSwap::::get_swap_amount( + DOT, + LDOT, + SwapLimit::ExactTarget(2_000_000_000u128, 10_000_000_000u128) + ), None ); assert_eq!( - TaigaSwap::::get_swap_amount(DOT, LDOT, SwapLimit::ExactTarget(u128::MAX, 10_000_000_000u128)), + TaigaSwap::::get_swap_amount( + DOT, + LDOT, + SwapLimit::ExactTarget(2_000_000_000u128, 10_000_000_000u128) + ), None ); assert_eq!( EitherDexOrTaigaSwap::::get_swap_amount( DOT, LDOT, - SwapLimit::ExactTarget(u128::MAX, 10_000_000_000u128) + SwapLimit::ExactTarget(2_000_000_000u128, 10_000_000_000u128) ), None ); - set_taiga_swap(DOT, LDOT, ExchangeRate::saturating_from_rational(10, 1)); + assert_ok!(inital_taiga_dot_ldot_pool()); assert_eq!( DexSwap::::get_swap_amount(DOT, LDOT, SwapLimit::ExactSupply(1_000_000_000u128, 0)), None ); assert_eq!( TaigaSwap::::get_swap_amount(DOT, LDOT, SwapLimit::ExactSupply(1_000_000_000u128, 0)), - Some((1_000_000_000u128, 10_000_000_000u128)) + Some((1_000_000_000u128, 9_998_360_750u128)) ); assert_eq!( EitherDexOrTaigaSwap::::get_swap_amount(DOT, LDOT, SwapLimit::ExactSupply(1_000_000_000u128, 0)), - Some((1_000_000_000u128, 10_000_000_000u128)) + Some((1_000_000_000u128, 9_998_360_750u128)) ); assert_eq!( - DexSwap::::get_swap_amount(DOT, LDOT, SwapLimit::ExactTarget(u128::MAX, 10_000_000_000u128)), + DexSwap::::get_swap_amount( + DOT, + LDOT, + SwapLimit::ExactTarget(2_000_000_000u128, 10_000_000_000u128) + ), None ); assert_eq!( - TaigaSwap::::get_swap_amount(DOT, LDOT, SwapLimit::ExactTarget(u128::MAX, 10_000_000_000u128)), - Some((1_000_000_000u128, 10_000_000_000u128)) + TaigaSwap::::get_swap_amount( + DOT, + LDOT, + SwapLimit::ExactTarget(2_000_000_000u128, 10_000_000_000u128) + ), + Some((1_000_164_076u128, 10_000_000_980u128)) ); assert_eq!( EitherDexOrTaigaSwap::::get_swap_amount( DOT, LDOT, - SwapLimit::ExactTarget(u128::MAX, 10_000_000_000u128) + SwapLimit::ExactTarget(2_000_000_000u128, 10_000_000_000u128) ), - Some((1_000_000_000u128, 10_000_000_000u128)) + Some((1_000_164_076u128, 10_000_000_980u128)) ); assert_ok!(inject_liquidity(DOT, LDOT, 1_000_000_000u128, 30_000_000_000u128)); @@ -329,7 +432,7 @@ fn either_dex_or_taiga_swap_get_swap_amount_work() { ); assert_eq!( TaigaSwap::::get_swap_amount(DOT, LDOT, SwapLimit::ExactSupply(1_000_000_000u128, 0)), - Some((1_000_000_000u128, 10_000_000_000u128)) + Some((1_000_000_000u128, 9_998_360_750u128)) ); assert_eq!( EitherDexOrTaigaSwap::::get_swap_amount(DOT, LDOT, SwapLimit::ExactSupply(1_000_000_000u128, 0)), @@ -339,7 +442,7 @@ fn either_dex_or_taiga_swap_get_swap_amount_work() { DexSwap::::get_swap_amount( DOT, LDOT, - SwapLimit::ExactTarget(1_000_000_000u128, 10_000_000_000u128) + SwapLimit::ExactTarget(2_000_000_000u128, 10_000_000_000u128) ), Some((500_000_001u128, 10_000_000_000u128)) ); @@ -347,15 +450,15 @@ fn either_dex_or_taiga_swap_get_swap_amount_work() { TaigaSwap::::get_swap_amount( DOT, LDOT, - SwapLimit::ExactTarget(1_000_000_000u128, 10_000_000_000u128) + SwapLimit::ExactTarget(2_000_000_000u128, 10_000_000_000u128) ), - Some((1_000_000_000u128, 10_000_000_000u128)) + Some((1_000_164_076u128, 10_000_000_980u128)) ); assert_eq!( EitherDexOrTaigaSwap::::get_swap_amount( DOT, LDOT, - SwapLimit::ExactTarget(1_000_000_000u128, 10_000_000_000u128) + SwapLimit::ExactTarget(2_000_000_000u128, 10_000_000_000u128) ), Some((500_000_001u128, 10_000_000_000u128)) ); @@ -366,27 +469,35 @@ fn either_dex_or_taiga_swap_get_swap_amount_work() { ); assert_eq!( TaigaSwap::::get_swap_amount(DOT, LDOT, SwapLimit::ExactSupply(10_000_000_000u128, 0)), - Some((10_000_000_000u128, 100_000_000_000u128)) + Some((10_000_000_000u128, 99_834_740_530u128)) ); assert_eq!( EitherDexOrTaigaSwap::::get_swap_amount(DOT, LDOT, SwapLimit::ExactSupply(10_000_000_000u128, 0)), - Some((10_000_000_000u128, 100_000_000_000u128)) + Some((10_000_000_000u128, 99_834_740_530u128)) ); assert_eq!( - DexSwap::::get_swap_amount(DOT, LDOT, SwapLimit::ExactTarget(u128::MAX, 30_000_000_000u128)), + DexSwap::::get_swap_amount( + DOT, + LDOT, + SwapLimit::ExactTarget(10_000_000_000u128, 30_000_000_000u128) + ), None ); assert_eq!( - TaigaSwap::::get_swap_amount(DOT, LDOT, SwapLimit::ExactTarget(u128::MAX, 30_000_000_000u128)), - Some((3_000_000_000u128, 30_000_000_000u128)) + TaigaSwap::::get_swap_amount( + DOT, + LDOT, + SwapLimit::ExactTarget(10_000_000_000u128, 30_000_000_000u128) + ), + Some((3_001_477_523u128, 30_000_000_980u128)) ); assert_eq!( EitherDexOrTaigaSwap::::get_swap_amount( DOT, LDOT, - SwapLimit::ExactTarget(u128::MAX, 30_000_000_000u128) + SwapLimit::ExactTarget(10_000_000_000u128, 30_000_000_000u128) ), - Some((3_000_000_000u128, 30_000_000_000u128)) + Some((3_001_477_523u128, 30_000_000_980u128)) ); }); } @@ -403,12 +514,12 @@ fn either_dex_or_taiga_swap_swap_work() { &ALICE, DOT, LDOT, - SwapLimit::ExactTarget(u128::MAX, 10_000_000_000u128) + SwapLimit::ExactTarget(2_000_000_000u128, 10_000_000_000u128) ), Error::::CannotSwap ); - set_taiga_swap(DOT, LDOT, ExchangeRate::saturating_from_rational(10, 1)); + assert_ok!(inital_taiga_dot_ldot_pool()); assert_eq!(Tokens::free_balance(DOT, &ALICE), 100_000_000_000u128); assert_eq!(Tokens::free_balance(LDOT, &ALICE), 0); @@ -417,55 +528,55 @@ fn either_dex_or_taiga_swap_swap_work() { &ALICE, DOT, LDOT, - SwapLimit::ExactSupply(1_000_000_000u128, 10_000_000_001u128) + SwapLimit::ExactSupply(1_000_000_000u128, 10_000_000_000u128) ), Error::::CannotSwap ); - assert_ok!(EitherDexOrTaigaSwap::::swap( - &ALICE, - DOT, - LDOT, - SwapLimit::ExactSupply(1_000_000_000u128, 10_000_000_000u128) - )); + assert_eq!( + EitherDexOrTaigaSwap::::swap( + &ALICE, + DOT, + LDOT, + SwapLimit::ExactSupply(1_000_000_000u128, 9_000_000_000u128) + ), + Ok((1_000_000_000u128, 9_998_360_750u128)) + ); assert_eq!(Tokens::free_balance(DOT, &ALICE), 99_000_000_000u128); - assert_eq!(Tokens::free_balance(LDOT, &ALICE), 10_000_000_000u128); + assert_eq!(Tokens::free_balance(LDOT, &ALICE), 9_998_360_750u128); assert_noop!( EitherDexOrTaigaSwap::::swap( &ALICE, DOT, LDOT, - SwapLimit::ExactTarget(999_999_999u128, 10_000_000_000u128) + SwapLimit::ExactTarget(1_000_000_000u128, 9_998_360_750u128) ), Error::::CannotSwap ); - assert_ok!(EitherDexOrTaigaSwap::::swap( - &ALICE, - DOT, - LDOT, - SwapLimit::ExactTarget(1_000_000_000u128, 10_000_000_000u128) - )); - assert_eq!(Tokens::free_balance(DOT, &ALICE), 98_000_000_000u128); - assert_eq!(Tokens::free_balance(LDOT, &ALICE), 20_000_000_000u128); + assert_eq!( + EitherDexOrTaigaSwap::::swap( + &ALICE, + DOT, + LDOT, + SwapLimit::ExactTarget(2_000_000_000u128, 10_000_000_000u128) + ), + Ok((1_000_492_274u128, 10_000_000_980u128)) + ); + assert_eq!(Tokens::free_balance(DOT, &ALICE), 97_999_507_726u128); + assert_eq!(Tokens::free_balance(LDOT, &ALICE), 19_998_361_730u128); assert_ok!(inject_liquidity(DOT, LDOT, 100_000_000_000u128, 2_000_000_000_000u128)); - assert_ok!(EitherDexOrTaigaSwap::::swap( - &ALICE, - DOT, - LDOT, - SwapLimit::ExactSupply(1_000_000_000u128, 10_000_000_000u128) - )); - assert_eq!(Tokens::free_balance(DOT, &ALICE), 97_000_000_000u128); - assert_eq!(Tokens::free_balance(LDOT, &ALICE), 39_801_980_198u128); - - assert_ok!(EitherDexOrTaigaSwap::::swap( - &ALICE, - DOT, - LDOT, - SwapLimit::ExactTarget(1_000_000_000u128, 10_000_000_000u128) - )); - assert_eq!(Tokens::free_balance(DOT, &ALICE), 964_873_611_73u128); - assert_eq!(Tokens::free_balance(LDOT, &ALICE), 49_801_980_198u128); + assert_eq!( + EitherDexOrTaigaSwap::::swap( + &ALICE, + DOT, + LDOT, + SwapLimit::ExactSupply(1_000_000_000u128, 10_000_000_000u128) + ), + Ok((1_000_000_000u128, 19_801_980_198u128)) + ); + assert_eq!(Tokens::free_balance(DOT, &ALICE), 96_999_507_726u128); + assert_eq!(Tokens::free_balance(LDOT, &ALICE), 39_800_341_928u128); }); } @@ -499,7 +610,7 @@ fn check_swap_paths_work() { Error::::InvalidSwapPath ); - set_taiga_swap(DOT, LDOT, ExchangeRate::saturating_from_rational(10, 1)); + assert_ok!(inital_taiga_dot_ldot_pool()); assert_ok!(AggregatedDex::check_swap_paths(&vec![SwapPath::Taiga(0, 0, 1)])); assert_noop!( AggregatedDex::check_swap_paths(&vec![SwapPath::Taiga(0, 2, 0)]), @@ -589,32 +700,32 @@ fn get_aggregated_swap_amount_work() { None ); - set_taiga_swap(DOT, LDOT, ExchangeRate::saturating_from_rational(10, 1)); + assert_ok!(inital_taiga_dot_ldot_pool()); assert_eq!( AggregatedDex::get_aggregated_swap_amount( &vec![SwapPath::Taiga(0, 0, 1)], SwapLimit::ExactSupply(1_000_000_000u128, 0) ), - Some((1_000_000_000u128, 10_000_000_000u128)) + Some((1_000_000_000u128, 9_998_360_750u128)) ); assert_eq!( AggregatedDex::get_aggregated_swap_amount( &vec![SwapPath::Taiga(0, 0, 1)], - SwapLimit::ExactSupply(1_000_000_000u128, 10_000_000_001u128) + SwapLimit::ExactSupply(1_000_000_000u128, 10_000_000_000u128) ), None ); assert_eq!( AggregatedDex::get_aggregated_swap_amount( &vec![SwapPath::Taiga(0, 0, 1)], - SwapLimit::ExactTarget(1_000_000_000u128, 10_000_000_000u128) + SwapLimit::ExactTarget(2_000_000_000u128, 10_000_000_000u128) ), - Some((1_000_000_000u128, 10_000_000_000u128)) + Some((1_000_164_076u128, 10_000_000_980u128)) ); assert_eq!( AggregatedDex::get_aggregated_swap_amount( &vec![SwapPath::Taiga(0, 0, 1)], - SwapLimit::ExactTarget(999_999_999u128, 10_000_000_000u128) + SwapLimit::ExactTarget(1_000_000_000u128, 10_000_000_000u128) ), None ); @@ -624,26 +735,26 @@ fn get_aggregated_swap_amount_work() { &vec![SwapPath::Taiga(0, 0, 1), SwapPath::Dex(vec![LDOT, AUSD])], SwapLimit::ExactSupply(1_000_000_000u128, 0) ), - Some((1_000_000_000u128, 1_818_181_818_181u128)) + Some((1_000_000_000u128, 1_817_910_863_730u128)) ); assert_eq!( AggregatedDex::get_aggregated_swap_amount( &vec![SwapPath::Taiga(0, 0, 1), SwapPath::Dex(vec![LDOT, AUSD])], - SwapLimit::ExactSupply(1_000_000_000u128, 1_818_181_818_182u128) + SwapLimit::ExactSupply(1_000_000_000u128, 1_817_910_863_731u128) ), None ); assert_eq!( AggregatedDex::get_aggregated_swap_amount( &vec![SwapPath::Taiga(0, 0, 1), SwapPath::Dex(vec![LDOT, AUSD])], - SwapLimit::ExactTarget(1_000_000_000u128, 1_818_181_818_181u128) + SwapLimit::ExactTarget(2_000_000_000u128, 1_817_910_863_730u128) ), - Some((1_000_000_000u128, 1_818_181_818_181u128)) + Some((1_000_000_098u128, 1_817_911_025_719u128)) ); assert_eq!( AggregatedDex::get_aggregated_swap_amount( &vec![SwapPath::Taiga(0, 0, 1), SwapPath::Dex(vec![LDOT, AUSD])], - SwapLimit::ExactTarget(999_999_999u128, 1_818_181_818_181u128) + SwapLimit::ExactTarget(1_000_000_097u128, 1_817_910_863_730u128) ), None ); @@ -651,35 +762,21 @@ fn get_aggregated_swap_amount_work() { assert_eq!( AggregatedDex::get_aggregated_swap_amount( &vec![SwapPath::Dex(vec![AUSD, LDOT]), SwapPath::Taiga(0, 1, 0)], - SwapLimit::ExactSupply(1_818_181_818_181u128, 0) - ), - Some((1_818_181_818_181u128, 833_333_333u128)) - ); - assert_eq!( - AggregatedDex::get_aggregated_swap_amount( - &vec![SwapPath::Dex(vec![AUSD, LDOT]), SwapPath::Taiga(0, 1, 0)], - SwapLimit::ExactSupply(2_222_222_222_223u128, 1_000_000_000u128) - ), - Some((2_222_222_222_223u128, 1_000_000_000u128)) - ); - assert_eq!( - AggregatedDex::get_aggregated_swap_amount( - &vec![SwapPath::Dex(vec![AUSD, LDOT]), SwapPath::Taiga(0, 1, 0)], - SwapLimit::ExactSupply(2_222_222_222_222u128, 1_000_000_000u128) + SwapLimit::ExactSupply(1_817_910_863_730u128, 0) ), - None + Some((1_817_910_863_730u128, 833_105_687u128)) ); assert_eq!( AggregatedDex::get_aggregated_swap_amount( &vec![SwapPath::Dex(vec![AUSD, LDOT]), SwapPath::Taiga(0, 1, 0)], - SwapLimit::ExactTarget(2_222_222_222_223u128, 1_000_000_000u128) + SwapLimit::ExactTarget(3_000_000_000_000u128, 1_000_000_000u128) ), - Some((2_222_222_222_223u128, 1_000_000_000u128)) + Some((2_222_627_355_534u128, 1_000_000_098u128)) ); assert_eq!( AggregatedDex::get_aggregated_swap_amount( &vec![SwapPath::Dex(vec![AUSD, LDOT]), SwapPath::Taiga(0, 1, 0)], - SwapLimit::ExactTarget(2_222_222_222_222u128, 1_000_000_000u128) + SwapLimit::ExactTarget(2_222_627_355_533u128, 1_000_000_000u128) ), None ); @@ -714,7 +811,7 @@ fn do_aggregated_swap_work() { Error::::InvalidPoolId ); - set_taiga_swap(DOT, LDOT, ExchangeRate::saturating_from_rational(10, 1)); + assert_ok!(inital_taiga_dot_ldot_pool()); assert_noop!( AggregatedDex::do_aggregated_swap( &ALICE, @@ -734,22 +831,28 @@ fn do_aggregated_swap_work() { assert_eq!(Tokens::free_balance(DOT, &ALICE), 100_000_000_000u128); assert_eq!(Tokens::free_balance(LDOT, &ALICE), 0); - assert_ok!(AggregatedDex::do_aggregated_swap( - &ALICE, - &vec![SwapPath::Taiga(0, 0, 1)], - SwapLimit::ExactSupply(1_000_000_000u128, 0) - )); + assert_eq!( + AggregatedDex::do_aggregated_swap( + &ALICE, + &vec![SwapPath::Taiga(0, 0, 1)], + SwapLimit::ExactSupply(1_000_000_000u128, 0) + ), + Ok((1_000_000_000u128, 9_998_360_750u128)) + ); assert_eq!(Tokens::free_balance(DOT, &ALICE), 99_000_000_000u128); - assert_eq!(Tokens::free_balance(LDOT, &ALICE), 10_000_000_000u128); + assert_eq!(Tokens::free_balance(LDOT, &ALICE), 9_998_360_750u128); assert_eq!(Tokens::free_balance(AUSD, &ALICE), 0); - assert_ok!(AggregatedDex::do_aggregated_swap( - &ALICE, - &vec![SwapPath::Taiga(0, 0, 1)], - SwapLimit::ExactTarget(u128::MAX, 10_000_000_000u128) - )); - assert_eq!(Tokens::free_balance(DOT, &ALICE), 98_000_000_000u128); - assert_eq!(Tokens::free_balance(LDOT, &ALICE), 20_000_000_000u128); + assert_eq!( + AggregatedDex::do_aggregated_swap( + &ALICE, + &vec![SwapPath::Taiga(0, 0, 1)], + SwapLimit::ExactTarget(2_000_000_000u128, 10_000_000_000u128) + ), + Ok((1_000_492_274u128, 10_000_000_980u128)) + ); + assert_eq!(Tokens::free_balance(DOT, &ALICE), 97_999_507_726u128); + assert_eq!(Tokens::free_balance(LDOT, &ALICE), 19_998_361_730u128); assert_eq!(Tokens::free_balance(AUSD, &ALICE), 0); assert_ok!(inject_liquidity( @@ -767,45 +870,57 @@ fn do_aggregated_swap_work() { Error::::CannotSwap ); - assert_ok!(AggregatedDex::do_aggregated_swap( - &ALICE, - &vec![SwapPath::Dex(vec![LDOT, AUSD])], - SwapLimit::ExactSupply(1_000_000_000u128, 0) - )); - assert_eq!(Tokens::free_balance(DOT, &ALICE), 98_000_000_000u128); - assert_eq!(Tokens::free_balance(LDOT, &ALICE), 19_000_000_000u128); + assert_eq!( + AggregatedDex::do_aggregated_swap( + &ALICE, + &vec![SwapPath::Dex(vec![LDOT, AUSD])], + SwapLimit::ExactSupply(1_000_000_000u128, 0) + ), + Ok((1_000_000_000u128, 198_019_801_980u128)) + ); + assert_eq!(Tokens::free_balance(DOT, &ALICE), 97_999_507_726u128); + assert_eq!(Tokens::free_balance(LDOT, &ALICE), 18_998_361_730u128); assert_eq!(Tokens::free_balance(AUSD, &ALICE), 198_019_801_980u128); - assert_ok!(AggregatedDex::do_aggregated_swap( - &ALICE, - &vec![SwapPath::Dex(vec![LDOT, AUSD])], - SwapLimit::ExactTarget(1_000_000_000u128, 10_000_000_000u128) - )); - assert_eq!(Tokens::free_balance(DOT, &ALICE), 98_000_000_000u128); - assert_eq!(Tokens::free_balance(LDOT, &ALICE), 18_948_969_229u128); + assert_eq!( + AggregatedDex::do_aggregated_swap( + &ALICE, + &vec![SwapPath::Dex(vec![LDOT, AUSD])], + SwapLimit::ExactTarget(1_000_000_000u128, 10_000_000_000u128) + ), + Ok((51_030_771u128, 10_000_000_090u128)) + ); + assert_eq!(Tokens::free_balance(DOT, &ALICE), 97_999_507_726u128); + assert_eq!(Tokens::free_balance(LDOT, &ALICE), 18_947_330_959u128); // actually swap by ExactSupply, actual target amount may be slightly more than exact target amount // of limit assert_eq!(Tokens::free_balance(AUSD, &ALICE), 208_019_802_070u128); - assert_ok!(AggregatedDex::do_aggregated_swap( - &ALICE, - &vec![SwapPath::Taiga(0, 0, 1), SwapPath::Dex(vec![LDOT, AUSD])], - SwapLimit::ExactSupply(1_000_000_000u128, 0) - )); - assert_eq!(Tokens::free_balance(DOT, &ALICE), 97_000_000_000u128); - assert_eq!(Tokens::free_balance(LDOT, &ALICE), 18_948_969_229u128); - assert_eq!(Tokens::free_balance(AUSD, &ALICE), 1_990_261_719_188u128); + assert_eq!( + AggregatedDex::do_aggregated_swap( + &ALICE, + &vec![SwapPath::Taiga(0, 0, 1), SwapPath::Dex(vec![LDOT, AUSD])], + SwapLimit::ExactSupply(1_000_000_000u128, 0) + ), + Ok((1_000_000_000u128, 1_780_911_406_971u128)) + ); + assert_eq!(Tokens::free_balance(DOT, &ALICE), 96_999_507_726u128); + assert_eq!(Tokens::free_balance(LDOT, &ALICE), 18_947_330_959u128); + assert_eq!(Tokens::free_balance(AUSD, &ALICE), 1_988_931_209_041u128); - assert_ok!(AggregatedDex::do_aggregated_swap( - &ALICE, - &vec![SwapPath::Taiga(0, 0, 1), SwapPath::Dex(vec![LDOT, AUSD])], - SwapLimit::ExactTarget(1_000_000_000_000u128, 1_000_000_000_000u128) - )); - assert_eq!(Tokens::free_balance(DOT, &ALICE), 96_347_132_631u128); - assert_eq!(Tokens::free_balance(LDOT, &ALICE), 18_948_969_229u128); + assert_eq!( + AggregatedDex::do_aggregated_swap( + &ALICE, + &vec![SwapPath::Taiga(0, 0, 1), SwapPath::Dex(vec![LDOT, AUSD])], + SwapLimit::ExactTarget(1_000_000_000_000u128, 1_000_000_000_000u128) + ), + Ok((653_482_016u128, 1_000_000_140_971u128)) + ); + assert_eq!(Tokens::free_balance(DOT, &ALICE), 96_346_025_710u128); + assert_eq!(Tokens::free_balance(LDOT, &ALICE), 18_947_330_959u128); // actually swap by ExactSupply, actual target amount may be slightly more than exact target amount // of limit - assert_eq!(Tokens::free_balance(AUSD, &ALICE), 2_990_261_719_330u128); + assert_eq!(Tokens::free_balance(AUSD, &ALICE), 2_988_931_350_012u128); }); } @@ -834,7 +949,7 @@ fn update_aggregated_swap_paths_work() { Error::::InvalidPoolId ); - set_taiga_swap(DOT, LDOT, ExchangeRate::saturating_from_rational(10, 1)); + assert_ok!(inital_taiga_dot_ldot_pool()); assert_noop!( AggregatedDex::update_aggregated_swap_paths( @@ -920,14 +1035,14 @@ fn aggregated_swap_get_swap_amount_work() { Some((3_000_000_000u128, 22_500_000_000u128)) ); - set_taiga_swap(DOT, LDOT, ExchangeRate::saturating_from_rational(10, 1)); + assert_ok!(inital_taiga_dot_ldot_pool()); assert_eq!( AggregatedSwap::::get_swap_amount(DOT, LDOT, SwapLimit::ExactSupply(1_000_000_000u128, 0)), Some((1_000_000_000u128, 15_000_000_000u128)) ); assert_eq!( AggregatedSwap::::get_swap_amount(DOT, LDOT, SwapLimit::ExactSupply(3_000_000_000u128, 0)), - Some((3_000_000_000u128, 30_000_000_000u128)) + Some((3_000_000_000u128, 29_985_240_300u128)) ); assert_ok!(inject_liquidity(LDOT, AUSD, 30_000_000_000u128, 60_000_000_000u128)); @@ -946,7 +1061,7 @@ fn aggregated_swap_get_swap_amount_work() { )); assert_eq!( AggregatedSwap::::get_swap_amount(DOT, AUSD, SwapLimit::ExactSupply(3_000_000_000u128, 0)), - Some((3_000_000_000u128, 30_000_000_000u128)) + Some((3_000_000_000u128, 29_992_618_334u128)) ); assert_eq!( AggregatedSwap::::get_swap_amount(AUSD, DOT, SwapLimit::ExactSupply(30_000_000_000u128, 0)), @@ -966,16 +1081,20 @@ fn aggregated_swap_get_swap_amount_work() { ); assert_eq!( AggregatedSwap::::get_swap_amount(LDOT, DOT, SwapLimit::ExactSupply(10_000_000_000u128, 0)), - Some((10_000_000_000u128, 1_000_000_000u128)) + Some((10_000_000_000u128, 999_836_075u128)) ); assert_eq!( AggregatedSwap::::get_swap_amount(AUSD, DOT, SwapLimit::ExactSupply(30_000_000_000u128, 0)), - Some((30_000_000_000u128, 1_000_000_000u128)) + Some((30_000_000_000u128, 999_836_075u128)) ); assert_eq!( - AggregatedSwap::::get_swap_amount(LDOT, DOT, SwapLimit::ExactTarget(u128::MAX, 1_000_000_000u128)), - Some((10_000_000_000u128, 1_000_000_000u128)) + AggregatedSwap::::get_swap_amount( + LDOT, + DOT, + SwapLimit::ExactTarget(20_000_000_000u128, 1_000_000_000u128) + ), + Some((10_001_640_760u128, 1_000_000_098u128)) ); assert_eq!( AggregatedSwap::::get_swap_amount( @@ -987,7 +1106,7 @@ fn aggregated_swap_get_swap_amount_work() { ); assert_eq!( AggregatedSwap::::get_swap_amount(AUSD, DOT, SwapLimit::ExactTarget(u128::MAX, 1_000_000_000u128)), - Some((30_000_000_001u128, 1_000_000_000u128)) + Some((30_007_384_026u128, 1_000_000_098u128)) ); }); } @@ -1022,15 +1141,18 @@ fn aggregated_swap_swap_work() { assert_eq!(Tokens::free_balance(DOT, &ALICE), 99_000_000_000u128); assert_eq!(Tokens::free_balance(LDOT, &ALICE), 15_000_000_000u128); - set_taiga_swap(DOT, LDOT, ExchangeRate::saturating_from_rational(10, 1)); - assert_ok!(AggregatedSwap::::swap( - &ALICE, - DOT, - LDOT, - SwapLimit::ExactSupply(1_000_000_000u128, 10_000_000_000u128) - )); + assert_ok!(inital_taiga_dot_ldot_pool()); + assert_eq!( + AggregatedSwap::::swap( + &ALICE, + DOT, + LDOT, + SwapLimit::ExactSupply(1_000_000_000u128, 9_000_000_000u128) + ), + Ok((1_000_000_000u128, 9_998_360_750u128)) + ); assert_eq!(Tokens::free_balance(DOT, &ALICE), 98_000_000_000u128); - assert_eq!(Tokens::free_balance(LDOT, &ALICE), 25_000_000_000u128); + assert_eq!(Tokens::free_balance(LDOT, &ALICE), 24_998_360_750u128); assert_ok!(inject_liquidity(LDOT, AUSD, 30_000_000_000u128, 60_000_000_000u128)); @@ -1048,14 +1170,20 @@ fn aggregated_swap_swap_work() { )); assert_eq!(Tokens::free_balance(AUSD, &ALICE), 0); - assert_ok!(AggregatedSwap::::swap( - &ALICE, - DOT, - AUSD, - SwapLimit::ExactSupply(3_000_000_000u128, 0) - )); + assert_eq!( + AggregatedSwap::::swap(&ALICE, DOT, AUSD, SwapLimit::ExactSupply(3_000_000_000u128, 0)), + Ok((3_000_000_000u128, 29_987_688_109u128)) + ); assert_eq!(Tokens::free_balance(DOT, &ALICE), 95_000_000_000u128); - assert_eq!(Tokens::free_balance(LDOT, &ALICE), 25_000_000_000u128); - assert_eq!(Tokens::free_balance(AUSD, &ALICE), 30_000_000_000u128); + assert_eq!(Tokens::free_balance(LDOT, &ALICE), 24_998_360_750u128); + assert_eq!(Tokens::free_balance(AUSD, &ALICE), 29_987_688_109u128); + + assert_eq!( + AggregatedSwap::::swap(&ALICE, DOT, AUSD, SwapLimit::ExactTarget(u128::MAX, 10_000_000_000u128)), + Ok((3_002_366_414u128, 10_000_000_216u128)) + ); + assert_eq!(Tokens::free_balance(DOT, &ALICE), 91_997_633_586u128); + assert_eq!(Tokens::free_balance(LDOT, &ALICE), 24_998_360_750u128); + assert_eq!(Tokens::free_balance(AUSD, &ALICE), 39_987_688_325u128); }); } diff --git a/runtime/acala/src/lib.rs b/runtime/acala/src/lib.rs index 30654a5b66..26addc905a 100644 --- a/runtime/acala/src/lib.rs +++ b/runtime/acala/src/lib.rs @@ -1104,6 +1104,7 @@ impl module_aggregated_dex::Config for Runtime { type GovernanceOrigin = EnsureRootOrHalfGeneralCouncil; type DexSwapJointList = AlternativeSwapPathJointList; type SwapPathLimit = ConstU32<3>; + type RebaseTokenAmountConvertor = ConvertBalanceHoma; type WeightInfo = (); } diff --git a/runtime/karura/src/lib.rs b/runtime/karura/src/lib.rs index 7792f56c7c..f2f0127a1a 100644 --- a/runtime/karura/src/lib.rs +++ b/runtime/karura/src/lib.rs @@ -1117,6 +1117,7 @@ impl module_aggregated_dex::Config for Runtime { type GovernanceOrigin = EnsureRootOrHalfGeneralCouncil; type DexSwapJointList = AlternativeSwapPathJointList; type SwapPathLimit = ConstU32<3>; + type RebaseTokenAmountConvertor = ConvertBalanceHoma; type WeightInfo = (); } diff --git a/runtime/mandala/src/lib.rs b/runtime/mandala/src/lib.rs index 8d727e5fbe..7ce88ee955 100644 --- a/runtime/mandala/src/lib.rs +++ b/runtime/mandala/src/lib.rs @@ -1163,6 +1163,7 @@ impl module_aggregated_dex::Config for Runtime { type GovernanceOrigin = EnsureRootOrHalfGeneralCouncil; type DexSwapJointList = AlternativeSwapPathJointList; type SwapPathLimit = ConstU32<3>; + type RebaseTokenAmountConvertor = ConvertBalanceHoma; type WeightInfo = (); }