From 4930ee2bf242419e2808d0406de7db33cb6b8ba0 Mon Sep 17 00:00:00 2001 From: Kerber0x Date: Thu, 2 May 2024 11:35:55 +0100 Subject: [PATCH 1/7] chore: cleanup and refactor --- .../pool-manager/src/contract.rs | 55 ++++-------- .../pool-manager/src/liquidity/commands.rs | 20 +++-- .../pool-manager/src/manager/commands.rs | 6 +- .../pool-manager/src/manager/update_config.rs | 4 +- .../liquidity_hub/pool-manager/src/queries.rs | 4 +- .../pool-manager/src/router/commands.rs | 4 +- .../liquidity_hub/pool-manager/src/state.rs | 34 ++++++-- .../pool-manager/src/swap/commands.rs | 84 ++++++++----------- .../src/tests/integration_tests.rs | 58 ++++++++----- .../pool-manager/src/tests/suite.rs | 9 +- packages/white-whale-std/src/common.rs | 15 +++- packages/white-whale-std/src/pool_manager.rs | 40 +++++---- 12 files changed, 178 insertions(+), 155 deletions(-) diff --git a/contracts/liquidity_hub/pool-manager/src/contract.rs b/contracts/liquidity_hub/pool-manager/src/contract.rs index e27b12ec4..d7a2beb75 100644 --- a/contracts/liquidity_hub/pool-manager/src/contract.rs +++ b/contracts/liquidity_hub/pool-manager/src/contract.rs @@ -5,8 +5,8 @@ use crate::helpers::{ use crate::queries::{get_pair, get_swap_route, get_swap_route_creator, get_swap_routes}; use crate::router::commands::{add_swap_routes, remove_swap_routes}; use crate::state::{ - Config, SingleSideLiquidityProvisionBuffer, MANAGER_CONFIG, PAIR_COUNTER, - TMP_SINGLE_SIDE_LIQUIDITY_PROVISION, + Config, SingleSideLiquidityProvisionBuffer, CONFIG, PAIR_COUNTER, + SINGLE_SIDE_LIQUIDITY_PROVISION_BUFFER, }; use crate::{liquidity, manager, queries, router, swap}; #[cfg(not(feature = "library"))] @@ -44,7 +44,7 @@ pub fn instantiate( swaps_enabled: true, }, }; - MANAGER_CONFIG.save(deps.storage, &config)?; + CONFIG.save(deps.storage, &config)?; // initialize vault counter PAIR_COUNTER.save(deps.storage, &0u64)?; cw_ownable::initialize_owner(deps.storage, deps.api, Some(info.sender.as_str()))?; @@ -63,12 +63,12 @@ pub fn reply(deps: DepsMut, env: Env, msg: Reply) -> Result { - let to_addr = to.map(|addr| deps.api.addr_validate(&addr)).transpose()?; - - swap::commands::swap( - deps, - env, - info.clone(), - info.sender, - offer_asset, - ask_asset_denom, - belief_price, - max_spread, - to_addr, - pair_identifier, - ) - } + } => swap::commands::swap( + deps, + env, + info.clone(), + info.sender, + ask_asset_denom, + belief_price, + max_spread, + receiver, + pair_identifier, + ), ExecuteMsg::WithdrawLiquidity { pair_identifier } => { liquidity::commands::withdraw_liquidity(deps, env, info, pair_identifier) } @@ -182,21 +176,6 @@ pub fn execute( max_spread, ) } - // ExecuteMsg::ExecuteSwapOperation { - // operation, - // to, - // max_spread, - // } => { - // let api = deps.api; - // router::commands::execute_swap_operation( - // deps, - // env, - // info, - // operation, - // optional_addr_validate(api, to)?.map(|v| v.to_string()), - // max_spread, - // ) - // } ExecuteMsg::AddSwapRoutes { swap_routes } => { add_swap_routes(deps, info.sender, swap_routes) } diff --git a/contracts/liquidity_hub/pool-manager/src/liquidity/commands.rs b/contracts/liquidity_hub/pool-manager/src/liquidity/commands.rs index d0f413195..0a1bd3075 100644 --- a/contracts/liquidity_hub/pool-manager/src/liquidity/commands.rs +++ b/contracts/liquidity_hub/pool-manager/src/liquidity/commands.rs @@ -5,6 +5,7 @@ use cosmwasm_std::{ use cosmwasm_std::{Decimal, OverflowError, Uint128}; use white_whale_std::coin::aggregate_coins; +use white_whale_std::common::validate_addr_or_default; use white_whale_std::pool_manager::ExecuteMsg; use white_whale_std::pool_network::asset::PairType; use white_whale_std::pool_network::{ @@ -17,7 +18,7 @@ use crate::{ state::get_pair_by_identifier, }; use crate::{ - state::{MANAGER_CONFIG, PAIRS}, + state::{CONFIG, PAIRS}, ContractError, }; // After writing create_pair I see this can get quite verbose so attempting to @@ -26,7 +27,8 @@ use crate::contract::SINGLE_SIDE_LIQUIDITY_PROVISION_REPLY_ID; use crate::helpers::aggregate_outgoing_fees; use crate::queries::query_simulation; use crate::state::{ - LiquidityProvisionData, SingleSideLiquidityProvisionBuffer, TMP_SINGLE_SIDE_LIQUIDITY_PROVISION, + LiquidityProvisionData, SingleSideLiquidityProvisionBuffer, + SINGLE_SIDE_LIQUIDITY_PROVISION_BUFFER, }; pub const MAX_ASSETS_PER_POOL: usize = 4; @@ -43,7 +45,7 @@ pub fn provide_liquidity( unlocking_duration: Option, lock_position_identifier: Option, ) -> Result { - let config = MANAGER_CONFIG.load(deps.storage)?; + let config = CONFIG.load(deps.storage)?; // check if the deposit feature is enabled ensure!( config.feature_toggle.deposits_enabled, @@ -66,7 +68,10 @@ pub fn provide_liquidity( ContractError::AssetMismatch {} ); - let receiver = receiver.unwrap_or_else(|| info.sender.to_string()); + let receiver = + validate_addr_or_default(&deps.as_ref(), receiver, info.sender.clone()).to_string(); + + //let receiver = receiver.unwrap_or_else(|| info.sender.to_string()); // check if the user is providing liquidity with a single asset let is_single_asset_provision = deposits.len() == 1usize; @@ -121,7 +126,7 @@ pub fn provide_liquidity( StdError::generic_err("Spread limit exceeded") ); - TMP_SINGLE_SIDE_LIQUIDITY_PROVISION.save( + SINGLE_SIDE_LIQUIDITY_PROVISION_BUFFER.save( deps.storage, &SingleSideLiquidityProvisionBuffer { receiver, @@ -147,11 +152,10 @@ pub fn provide_liquidity( wasm_execute( env.contract.address.into_string(), &ExecuteMsg::Swap { - offer_asset: swap_half.clone(), ask_asset_denom: ask_denom, belief_price: None, max_spread, - to: None, + receiver: None, pair_identifier, }, vec![swap_half], @@ -324,7 +328,7 @@ pub fn withdraw_liquidity( info: MessageInfo, pair_identifier: String, ) -> Result { - let config = MANAGER_CONFIG.load(deps.storage)?; + let config = CONFIG.load(deps.storage)?; // check if the withdraw feature is enabled if !config.feature_toggle.withdrawals_enabled { return Err(ContractError::OperationDisabled( diff --git a/contracts/liquidity_hub/pool-manager/src/manager/commands.rs b/contracts/liquidity_hub/pool-manager/src/manager/commands.rs index 68d9f31dc..0b048abbc 100644 --- a/contracts/liquidity_hub/pool-manager/src/manager/commands.rs +++ b/contracts/liquidity_hub/pool-manager/src/manager/commands.rs @@ -5,7 +5,7 @@ use white_whale_std::{fee::PoolFee, pool_network::asset::PairType, whale_lair::f use crate::state::{get_pair_by_identifier, PAIR_COUNTER}; use crate::{ - state::{Config, MANAGER_CONFIG, PAIRS}, + state::{Config, CONFIG, PAIRS}, ContractError, }; @@ -86,9 +86,9 @@ pub fn create_pair( pair_identifier: Option, ) -> Result { // Load config for pool creation fee - let config: Config = MANAGER_CONFIG.load(deps.storage)?; + let config: Config = CONFIG.load(deps.storage)?; - // Check if fee was provided and is sufficientd + // Check if fee was provided and is sufficient if !config.pool_creation_fee.amount.is_zero() { // verify fee payment let amount = cw_utils::must_pay(&info, &config.pool_creation_fee.denom)?; diff --git a/contracts/liquidity_hub/pool-manager/src/manager/update_config.rs b/contracts/liquidity_hub/pool-manager/src/manager/update_config.rs index 5bc62acaa..c0d906962 100644 --- a/contracts/liquidity_hub/pool-manager/src/manager/update_config.rs +++ b/contracts/liquidity_hub/pool-manager/src/manager/update_config.rs @@ -1,7 +1,7 @@ use cosmwasm_std::{Coin, DepsMut, MessageInfo, Response}; use white_whale_std::pool_manager::{Config, FeatureToggle}; -use crate::{state::MANAGER_CONFIG, ContractError}; +use crate::{state::CONFIG, ContractError}; pub fn update_config( deps: DepsMut, @@ -13,7 +13,7 @@ pub fn update_config( // permission check cw_ownable::assert_owner(deps.storage, &info.sender)?; - MANAGER_CONFIG.update(deps.storage, |mut config| { + CONFIG.update(deps.storage, |mut config| { if let Some(whale_lair_addr) = whale_lair_addr { let whale_lair_addr = deps.api.addr_validate(&whale_lair_addr)?; config.bonding_manager_addr = whale_lair_addr; diff --git a/contracts/liquidity_hub/pool-manager/src/queries.rs b/contracts/liquidity_hub/pool-manager/src/queries.rs index 183d3dcdc..c831e138f 100644 --- a/contracts/liquidity_hub/pool-manager/src/queries.rs +++ b/contracts/liquidity_hub/pool-manager/src/queries.rs @@ -8,7 +8,7 @@ use white_whale_std::pool_manager::{ }; use white_whale_std::pool_network::asset::PairType; -use crate::state::{MANAGER_CONFIG, PAIRS}; +use crate::state::{CONFIG, PAIRS}; use crate::{ helpers::{self, calculate_stableswap_y, StableSwapDirection}, state::get_pair_by_identifier, @@ -18,7 +18,7 @@ use crate::{math::Decimal256Helper, state::SWAP_ROUTES}; /// Query the config of the contract. pub fn query_config(deps: Deps) -> Result { - Ok(MANAGER_CONFIG.load(deps.storage)?) + Ok(CONFIG.load(deps.storage)?) } /// Query the native asset decimals diff --git a/contracts/liquidity_hub/pool-manager/src/router/commands.rs b/contracts/liquidity_hub/pool-manager/src/router/commands.rs index 1b64d3633..284d75b96 100644 --- a/contracts/liquidity_hub/pool-manager/src/router/commands.rs +++ b/contracts/liquidity_hub/pool-manager/src/router/commands.rs @@ -7,7 +7,7 @@ use white_whale_std::whale_lair; use crate::{ helpers::simulate_swap_operations, - state::{SwapOperations, MANAGER_CONFIG, SWAP_ROUTES}, + state::{SwapOperations, CONFIG, SWAP_ROUTES}, swap::perform_swap::perform_swap, ContractError, }; @@ -43,7 +43,7 @@ pub fn execute_swap_operations( to: Option, max_spread: Option, ) -> Result { - let config = MANAGER_CONFIG.load(deps.storage)?; + let config = CONFIG.load(deps.storage)?; // check if the swap feature is enabled if !config.feature_toggle.swaps_enabled { return Err(ContractError::OperationDisabled("swap".to_string())); diff --git a/contracts/liquidity_hub/pool-manager/src/state.rs b/contracts/liquidity_hub/pool-manager/src/state.rs index 32a2ebcaa..29f6e2b3c 100644 --- a/contracts/liquidity_hub/pool-manager/src/state.rs +++ b/contracts/liquidity_hub/pool-manager/src/state.rs @@ -11,11 +11,21 @@ use crate::ContractError; /// provision is completed #[cw_serde] pub struct SingleSideLiquidityProvisionBuffer { + /// The receiver of the LP pub receiver: String, + /// The expected offer asset balance in the contract after the single side liquidity provision + /// is done. Used for validations. pub expected_offer_asset_balance_in_contract: Coin, + /// The expected ask asset balance in the contract after the single side liquidity provision + /// is done. Used for validations. pub expected_ask_asset_balance_in_contract: Coin, + /// Half of the offer asset, i.e. the amount of the offer asset that is going to be swapped + /// for the ask asset so the LP is provided in balanced proportions. pub offer_asset_half: Coin, + /// The expected ask asset after half of the offer asset is swapped for the ask asset. This is + /// computed via a swap simulation. pub expected_ask_asset: Coin, + /// The remaining data for the liquidity provision. pub liquidity_provision_data: LiquidityProvisionData, } @@ -23,15 +33,25 @@ pub struct SingleSideLiquidityProvisionBuffer { /// single asset. #[cw_serde] pub struct LiquidityProvisionData { + /// The maximum allowable spread between the bid and ask prices for the pair. + /// When provided, if the spread exceeds this value, the liquidity provision will not be + /// executed. pub max_spread: Option, + /// A percentage value representing the acceptable slippage for the operation. + /// When provided, if the slippage exceeds this value, the liquidity provision will not be + /// executed. pub slippage_tolerance: Option, + /// The identifier for the pair to provide liquidity for. pub pair_identifier: String, + /// The amount of time in seconds to unlock tokens if taking part on the incentives. If not passed, + /// the tokens will not be locked and the LP tokens will be returned to the user. pub unlocking_duration: Option, + /// The identifier of the position to lock the LP tokens in the incentive manager, if any. pub lock_position_identifier: Option, } -pub const TMP_SINGLE_SIDE_LIQUIDITY_PROVISION: Item = - Item::new("tmp_single_side_liquidity_provision"); +pub const SINGLE_SIDE_LIQUIDITY_PROVISION_BUFFER: Item = + Item::new("single_side_liquidity_provision_buffer"); pub const PAIRS: IndexedMap<&str, PairInfo, PairIndexes> = IndexedMap::new( "pairs", @@ -42,7 +62,6 @@ pub const PAIRS: IndexedMap<&str, PairInfo, PairIndexes> = IndexedMap::new( pub struct PairIndexes<'a> { pub lp_asset: UniqueIndex<'a, String, PairInfo, String>, - // pub asset_info: MultiIndex<'a, String, NPairInfo, String>, } impl<'a> IndexList for PairIndexes<'a> { @@ -62,16 +81,17 @@ pub fn get_pair_by_identifier( .ok_or(ContractError::UnExistingPair {}) } -// Swap routes are used to establish defined routes for a given fee -// token to a desired fee token and is used for fee collection +/// Swap routes are used to establish defined routes for a given fee +/// token to a desired fee token and is used for fee collection #[cw_serde] pub struct SwapOperations { - // creator of the swap route, can remove it later + /// creator of the swap route, can remove it later pub creator: String, + /// The operations to be executed for a given swap. pub swap_operations: Vec, } pub const SWAP_ROUTES: Map<(&str, &str), SwapOperations> = Map::new("swap_routes"); -pub const MANAGER_CONFIG: Item = Item::new("manager_config"); +pub const CONFIG: Item = Item::new("config"); pub const PAIR_COUNTER: Item = Item::new("vault_count"); diff --git a/contracts/liquidity_hub/pool-manager/src/swap/commands.rs b/contracts/liquidity_hub/pool-manager/src/swap/commands.rs index d5a60f322..12460065c 100644 --- a/contracts/liquidity_hub/pool-manager/src/swap/commands.rs +++ b/contracts/liquidity_hub/pool-manager/src/swap/commands.rs @@ -1,42 +1,37 @@ -use crate::{state::MANAGER_CONFIG, ContractError}; +use crate::{state::CONFIG, ContractError}; use cosmwasm_std::{ - ensure, to_json_binary, Addr, BankMsg, Coin, CosmosMsg, DepsMut, Env, MessageInfo, Response, - WasmMsg, + ensure, wasm_execute, Addr, BankMsg, CosmosMsg, DepsMut, Env, MessageInfo, Response, }; pub const MAX_ASSETS_PER_POOL: usize = 4; use crate::state::get_pair_by_identifier; use cosmwasm_std::Decimal; +use white_whale_std::common::validate_addr_or_default; use white_whale_std::whale_lair; use super::perform_swap::perform_swap; #[allow(clippy::too_many_arguments)] pub fn swap( - deps: DepsMut, + mut deps: DepsMut, _env: Env, info: MessageInfo, sender: Addr, - offer_asset: Coin, ask_asset_denom: String, belief_price: Option, max_spread: Option, - to: Option, + receiver: Option, pair_identifier: String, ) -> Result { - let config = MANAGER_CONFIG.load(deps.storage)?; + let config = CONFIG.load(deps.storage)?; // check if the swap feature is enabled ensure!( config.feature_toggle.swaps_enabled, ContractError::OperationDisabled("swap".to_string()) ); - // todo remove this, not needed. You can just swap whatever it is sent in info.funds, just worth - // veritying the asset is the same as the one in the pool - if cw_utils::one_coin(&info)? != offer_asset { - return Err(ContractError::AssetMismatch {}); - } + let offer_asset = cw_utils::one_coin(&info)?; // verify that the assets sent match the ones from the pool let pair = get_pair_by_identifier(&deps.as_ref(), &pair_identifier)?; @@ -52,7 +47,7 @@ pub fn swap( // perform the swap let swap_result = perform_swap( - deps, + deps.branch(), offer_asset.clone(), pair_identifier, belief_price, @@ -61,12 +56,13 @@ pub fn swap( // add messages let mut messages: Vec = vec![]; - let receiver = to.unwrap_or_else(|| sender.clone()); + + let receiver = validate_addr_or_default(&deps.as_ref(), receiver, info.sender); // first we add the swap result if !swap_result.return_asset.amount.is_zero() { messages.push(CosmosMsg::Bank(BankMsg::Send { - to_address: receiver.to_string(), + to_address: receiver.clone().into_string(), amount: vec![swap_result.return_asset.clone()], })); } @@ -78,53 +74,47 @@ pub fn swap( })); } if !swap_result.protocol_fee_asset.amount.is_zero() { - messages.push(CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: config.bonding_manager_addr.to_string(), - msg: to_json_binary(&whale_lair::ExecuteMsg::FillRewards { - assets: vec![swap_result.protocol_fee_asset.clone()], - })?, - funds: vec![swap_result.protocol_fee_asset.clone()], - })); + messages.push( + wasm_execute( + config.bonding_manager_addr.to_string(), + &whale_lair::ExecuteMsg::FillRewards { + assets: vec![swap_result.protocol_fee_asset.clone()], + }, + vec![swap_result.protocol_fee_asset.clone()], + )? + .into(), + ); } - //todo remove, this stays within the pool. Verify this with a test with multiple (duplicated) - // pools, see how the swap fees behave - // if !swap_result.swap_fee_asset.amount.is_zero() { - // messages.push(CosmosMsg::Bank(BankMsg::Send { - // to_address: config.bonding_manager_addr.to_string(), - // amount: vec![swap_result.swap_fee_asset.clone()], - // })); - // } - Ok(Response::new().add_messages(messages).add_attributes(vec![ - ("action", "swap"), - ("sender", sender.as_str()), - ("receiver", receiver.as_str()), - ("offer_denom", &offer_asset.denom), - ("ask_denom", &swap_result.return_asset.denom), - ("offer_amount", &offer_asset.amount.to_string()), - ( - "return_amount", - &swap_result.return_asset.amount.to_string(), - ), - ("spread_amount", &swap_result.spread_amount.to_string()), + ("action", "swap".to_string()), + ("sender", sender.into_string()), + ("receiver", receiver.into_string()), + ("offer_denom", offer_asset.denom), + ("ask_denom", swap_result.return_asset.denom), + ("offer_amount", offer_asset.amount.to_string()), + ("return_amount", swap_result.return_asset.amount.to_string()), + ("spread_amount", swap_result.spread_amount.to_string()), ( "swap_fee_amount", - &swap_result.swap_fee_asset.amount.to_string(), + swap_result.swap_fee_asset.amount.to_string(), ), ( "protocol_fee_amount", - &swap_result.protocol_fee_asset.amount.to_string(), + swap_result.protocol_fee_asset.amount.to_string(), ), ( "burn_fee_amount", - &swap_result.burn_fee_asset.amount.to_string(), + swap_result.burn_fee_asset.amount.to_string(), ), #[cfg(feature = "osmosis")] ( "osmosis_fee_amount", - &swap_result.osmosis_fee_amount.to_string(), + swap_result.osmosis_fee_amount.to_string(), + ), + ( + "swap_type", + swap_result.pair_info.pair_type.get_label().to_string(), ), - ("swap_type", swap_result.pair_info.pair_type.get_label()), ])) } diff --git a/contracts/liquidity_hub/pool-manager/src/tests/integration_tests.rs b/contracts/liquidity_hub/pool-manager/src/tests/integration_tests.rs index bd75c667f..6de17eddd 100644 --- a/contracts/liquidity_hub/pool-manager/src/tests/integration_tests.rs +++ b/contracts/liquidity_hub/pool-manager/src/tests/integration_tests.rs @@ -90,6 +90,7 @@ fn deposit_and_withdraw_sanity_check() { None, None, None, + None, vec![ Coin { denom: "uwhale".to_string(), @@ -407,6 +408,7 @@ mod router { None, None, None, + None, vec![ Coin { denom: "uwhale".to_string(), @@ -431,6 +433,7 @@ mod router { None, None, None, + None, vec![ Coin { denom: "uluna".to_string(), @@ -600,6 +603,7 @@ mod router { None, None, None, + None, vec![ Coin { denom: "uwhale".to_string(), @@ -624,6 +628,7 @@ mod router { None, None, None, + None, vec![ Coin { denom: "uluna".to_string(), @@ -743,6 +748,7 @@ mod router { None, None, None, + None, vec![ Coin { denom: "uwhale".to_string(), @@ -767,6 +773,7 @@ mod router { None, None, None, + None, vec![ Coin { denom: "uluna".to_string(), @@ -903,6 +910,7 @@ mod router { None, None, None, + None, vec![ Coin { denom: "uwhale".to_string(), @@ -927,6 +935,7 @@ mod router { None, None, None, + None, vec![ Coin { denom: "uluna".to_string(), @@ -1129,6 +1138,7 @@ mod router { None, None, None, + None, vec![ Coin { denom: "uwhale".to_string(), @@ -1153,6 +1163,7 @@ mod router { None, None, None, + None, vec![ Coin { denom: "uluna".to_string(), @@ -1292,6 +1303,7 @@ mod router { None, None, None, + None, vec![ Coin { denom: "uwhale".to_string(), @@ -1312,6 +1324,7 @@ mod router { None, None, None, + None, vec![ Coin { denom: "uluna".to_string(), @@ -1456,6 +1469,7 @@ mod router { None, None, None, + None, vec![ Coin { denom: "uwhale".to_string(), @@ -1476,6 +1490,7 @@ mod router { None, None, None, + None, vec![ Coin { denom: "uluna".to_string(), @@ -1654,6 +1669,7 @@ mod router { None, None, None, + None, vec![ Coin { denom: "uwhale".to_string(), @@ -1678,6 +1694,7 @@ mod router { None, None, None, + None, vec![ Coin { denom: "uluna".to_string(), @@ -1865,6 +1882,7 @@ mod swapping { None, None, None, + None, vec![ Coin { denom: "uwhale".to_string(), @@ -1918,10 +1936,6 @@ mod swapping { // Now lets try a swap suite.swap( creator.clone(), - Coin { - denom: "uwhale".to_string(), - amount: Uint128::from(1000u128), - }, "uluna".to_string(), None, None, @@ -1978,10 +1992,6 @@ mod swapping { // Now lets try a swap suite.swap( creator.clone(), - Coin { - denom: "uluna".to_string(), - amount: Uint128::from(simulated_offer_amount.borrow().u128()), - }, "uwhale".to_string(), None, None, @@ -2087,6 +2097,7 @@ mod swapping { None, None, None, + None, vec![ Coin { denom: "uwhale".to_string(), @@ -2119,10 +2130,6 @@ mod swapping { // Now lets try a swap suite.swap( creator.clone(), - Coin { - denom: "uwhale".to_string(), - amount: Uint128::from(1000u128), - }, "uluna".to_string(), None, None, @@ -2179,10 +2186,6 @@ mod swapping { // Now lets try a swap suite.swap( creator.clone(), - Coin { - denom: "uluna".to_string(), - amount: Uint128::from(simulated_offer_amount.borrow().u128()), - }, "uwhale".to_string(), None, None, @@ -2288,6 +2291,7 @@ mod swapping { None, None, None, + None, vec![ Coin { denom: "uwhale".to_string(), @@ -2321,10 +2325,6 @@ mod swapping { // Total -> 9,900,693 (Returned Amount) + 99,010 (Spread)(0.009x%) + 198 (Swap Fee) + 99 (Protocol Fee) = 10,000,000 uLUNA suite.swap( creator.clone(), - Coin { - denom: "uwhale".to_string(), - amount: Uint128::from(10000000u128), - }, "uluna".to_string(), None, Some(Decimal::percent(1)), @@ -2586,6 +2586,7 @@ mod locking_lp { Some(86_400u64), None, None, + None, vec![ Coin { denom: "uwhale".to_string(), @@ -2652,6 +2653,7 @@ mod locking_lp { Some(200_000u64), None, None, + None, vec![ Coin { denom: "uwhale".to_string(), @@ -2775,6 +2777,7 @@ mod locking_lp { Some(86_400u64), Some("incentive_identifier".to_string()), None, + None, vec![ Coin { denom: "uwhale".to_string(), @@ -2841,6 +2844,7 @@ mod locking_lp { Some(200_000u64), Some("incentive_identifier".to_string()), None, + None, vec![ Coin { denom: "uwhale".to_string(), @@ -2965,7 +2969,7 @@ mod provide_liquidity { creator.clone(), "whale-uluna".to_string(), None, - None, + None,None, None, vec![], |result| { @@ -2981,7 +2985,7 @@ mod provide_liquidity { creator.clone(), "whale-uluna".to_string(), None, - None, + None,None, None, vec![Coin { denom: "uosmo".to_string(), @@ -3000,7 +3004,7 @@ mod provide_liquidity { creator.clone(), "whale-uluna".to_string(), None, - None, + None,None, None, vec![Coin { denom: "uwhale".to_string(), @@ -3026,6 +3030,7 @@ mod provide_liquidity { None, None, None, + None, vec![ Coin { denom: "uosmo".to_string(), @@ -3051,6 +3056,7 @@ mod provide_liquidity { None, None, None, + None, vec![ Coin { denom: "uwhale".to_string(), @@ -3089,6 +3095,7 @@ mod provide_liquidity { None, None, None, + None, vec![ Coin { denom: "uwhale".to_string(), @@ -3114,6 +3121,7 @@ mod provide_liquidity { None, None, Some(Decimal::percent(50)), + None, vec![ Coin { denom: "uwhale".to_string(), @@ -3412,6 +3420,7 @@ mod provide_liquidity { None, None, None, + None, vec![ Coin { denom: "uwhale".to_string(), @@ -3439,6 +3448,7 @@ mod provide_liquidity { None, None, Some(Decimal::percent(50)), + None, vec![Coin { denom: "uwhale".to_string(), amount: Uint128::from(1_760u128), @@ -3457,6 +3467,7 @@ mod provide_liquidity { None, None, Some(Decimal::percent(50)), + None, vec![Coin { denom: "uwhale".to_string(), amount: Uint128::from(10_000u128), @@ -3475,6 +3486,7 @@ mod provide_liquidity { None, None, Some(Decimal::percent(50)), + None, vec![Coin { denom: "uwhale".to_string(), amount: Uint128::from(1_000u128), diff --git a/contracts/liquidity_hub/pool-manager/src/tests/suite.rs b/contracts/liquidity_hub/pool-manager/src/tests/suite.rs index 39a5da6fb..c952224e9 100644 --- a/contracts/liquidity_hub/pool-manager/src/tests/suite.rs +++ b/contracts/liquidity_hub/pool-manager/src/tests/suite.rs @@ -321,6 +321,7 @@ impl TestingSuite { unlocking_duration: Option, lock_position_identifier: Option, max_spread: Option, + receiver: Option, funds: Vec, result: impl Fn(Result), ) -> &mut Self { @@ -328,7 +329,7 @@ impl TestingSuite { pair_identifier, slippage_tolerance: None, max_spread, - receiver: None, + receiver, unlocking_duration, lock_position_identifier, }; @@ -346,21 +347,19 @@ impl TestingSuite { pub(crate) fn swap( &mut self, sender: Addr, - offer_asset: Coin, ask_asset_denom: String, belief_price: Option, max_spread: Option, - to: Option, + receiver: Option, pair_identifier: String, funds: Vec, result: impl Fn(Result), ) -> &mut Self { let msg = white_whale_std::pool_manager::ExecuteMsg::Swap { - offer_asset, ask_asset_denom, belief_price, max_spread, - to, + receiver, pair_identifier, }; diff --git a/packages/white-whale-std/src/common.rs b/packages/white-whale-std/src/common.rs index 9e971497a..6f8ddd569 100644 --- a/packages/white-whale-std/src/common.rs +++ b/packages/white-whale-std/src/common.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{Addr, DepsMut, Env, MessageInfo, Response, StdError, StdResult, Storage}; +use cosmwasm_std::{Addr, Deps, DepsMut, Env, MessageInfo, Response, StdError, StdResult, Storage}; use cw_ownable::{Action, OwnershipError}; use cw_storage_plus::Item; @@ -31,3 +31,16 @@ pub fn update_ownership( .add_attributes(ownership.into_attributes()) }) } + +/// Validates a [String] address or returns the default address if the validation fails. +pub fn validate_addr_or_default(deps: &Deps, unvalidated: Option, default: Addr) -> Addr { + unvalidated + .map_or_else( + || Some(default.clone()), + |recv| match deps.api.addr_validate(&recv) { + Ok(validated) => Some(validated), + Err(_) => None, + }, + ) + .unwrap_or(default) +} diff --git a/packages/white-whale-std/src/pool_manager.rs b/packages/white-whale-std/src/pool_manager.rs index bfa8dc092..29b947025 100644 --- a/packages/white-whale-std/src/pool_manager.rs +++ b/packages/white-whale-std/src/pool_manager.rs @@ -129,18 +129,33 @@ pub struct MigrateMsg {} #[cw_ownable_execute] #[cw_serde] pub enum ExecuteMsg { + //todo maybe to rename to CreatePool? + /// Creates a new pair. CreatePair { + /// The asset denoms for the pair. asset_denoms: Vec, + /// The decimals for the given asset denoms, provided in the same order as `asset_denoms`. asset_decimals: Vec, + /// The fees for the pool. pool_fees: PoolFee, + /// The type of pair to create. pair_type: PairType, + /// The identifier for the pair. pair_identifier: Option, }, /// Provides liquidity to the pool ProvideLiquidity { + /// A percentage value representing the acceptable slippage for the operation. + /// When provided, if the slippage exceeds this value, the liquidity provision will not be + /// executed. slippage_tolerance: Option, + /// The maximum allowable spread between the bid and ask prices for the pair. + /// When provided, if the spread exceeds this value, the liquidity provision will not be + /// executed. max_spread: Option, + /// The receiver of the LP receiver: Option, + /// The identifier for the pair to provide liquidity for. pair_identifier: String, /// The amount of time in seconds to unlock tokens if taking part on the incentives. If not passed, /// the tokens will not be locked and the LP tokens will be returned to the user. @@ -150,12 +165,17 @@ pub enum ExecuteMsg { }, /// Swap an offer asset to the other Swap { - //todo remove offer_asset, take it from info.funds - offer_asset: Coin, + /// The return asset of the swap. ask_asset_denom: String, + /// The belief price of the swap. belief_price: Option, + /// The maximum spread to incur when performing the swap. If the spread exceeds this value, + /// the swap will not be executed. max_spread: Option, - to: Option, + /// The recipient of the output tokens. If not provided, the tokens will be sent to the sender + /// of the message. + receiver: Option, + /// The identifier for the pair to swap in. pair_identifier: String, }, /// Withdraws liquidity from the pool. @@ -179,20 +199,6 @@ pub enum ExecuteMsg { /// If left unspecified, there is no limit to what spread the transaction can incur. max_spread: Option, }, - // /// Swap the offer to ask token. This message can only be called internally by the router contract. - // ExecuteSwapOperation { - // operation: SwapOperation, - // to: Option, - // max_spread: Option, - // }, - // /// Checks if the swap amount exceeds the minimum_receive. This message can only be called - // /// internally by the router contract. - // AssertMinimumReceive { - // asset_info: AssetInfo, - // prev_balance: Uint128, - // minimum_receive: Uint128, - // receiver: String, - // }, /// Adds swap routes to the router. AddSwapRoutes { swap_routes: Vec }, /// Removes swap routes from the router. From 790f5630e9308881af8656bdda1a2dd264d24baf Mon Sep 17 00:00:00 2001 From: Kerber0x Date: Thu, 2 May 2024 12:02:45 +0100 Subject: [PATCH 2/7] refactor: errors cleanup --- .../pool-manager/src/contract.rs | 8 +- .../liquidity_hub/pool-manager/src/error.rs | 40 ++-- .../liquidity_hub/pool-manager/src/helpers.rs | 138 ++++---------- .../pool-manager/src/liquidity/commands.rs | 14 +- .../pool-manager/src/manager/commands.rs | 4 +- .../liquidity_hub/pool-manager/src/math.rs | 2 +- .../liquidity_hub/pool-manager/src/queries.rs | 174 +++++++----------- .../pool-manager/src/router/commands.rs | 39 ++-- .../liquidity_hub/pool-manager/src/state.rs | 2 +- .../pool-manager/src/swap/commands.rs | 5 +- .../pool-manager/src/swap/perform_swap.rs | 2 +- .../src/tests/integration_tests.rs | 10 +- 12 files changed, 155 insertions(+), 283 deletions(-) diff --git a/contracts/liquidity_hub/pool-manager/src/contract.rs b/contracts/liquidity_hub/pool-manager/src/contract.rs index d7a2beb75..4181ff255 100644 --- a/contracts/liquidity_hub/pool-manager/src/contract.rs +++ b/contracts/liquidity_hub/pool-manager/src/contract.rs @@ -1,7 +1,5 @@ use crate::error::ContractError; -use crate::helpers::{ - reverse_simulate_swap_operations, simulate_swap_operations, validate_asset_balance, -}; +use crate::helpers::validate_asset_balance; use crate::queries::{get_pair, get_swap_route, get_swap_route_creator, get_swap_routes}; use crate::router::commands::{add_swap_routes, remove_swap_routes}; use crate::state::{ @@ -246,7 +244,7 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result Ok(to_json_binary(&simulate_swap_operations( + } => Ok(to_json_binary(&queries::simulate_swap_operations( deps, offer_amount, operations, @@ -254,7 +252,7 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result Ok(to_json_binary(&reverse_simulate_swap_operations( + } => Ok(to_json_binary(&queries::reverse_simulate_swap_operations( deps, ask_amount, operations, )?)?), QueryMsg::SwapRoute { diff --git a/contracts/liquidity_hub/pool-manager/src/error.rs b/contracts/liquidity_hub/pool-manager/src/error.rs index 1e146fecf..0a6cb9cf1 100644 --- a/contracts/liquidity_hub/pool-manager/src/error.rs +++ b/contracts/liquidity_hub/pool-manager/src/error.rs @@ -32,11 +32,11 @@ pub enum ContractError { SemVer(String), #[error("Unauthorized")] - Unauthorized {}, + Unauthorized, // Add any other custom errors you like here. // Look at https://docs.rs/thiserror/1.0.21/thiserror/ for details. #[error("The provided assets are both the same")] - SameAsset {}, + SameAsset, #[error("Attempt to migrate to version {new_version}, but contract is on a higher version {current_version}")] MigrateInvalidVersion { @@ -76,52 +76,43 @@ pub enum ContractError { EmptyPoolForSingleSideLiquidityProvision, #[error("Pair does not exist")] - UnExistingPair {}, + UnExistingPair, #[error("Operation disabled, {0}")] OperationDisabled(String), #[error("Invalid zero amount")] - InvalidZeroAmount {}, + InvalidZeroAmount, #[error("Initial liquidity amount must be over {0}")] InvalidInitialLiquidityAmount(Uint128), #[error("Failed to compute the LP share with the given deposit")] - LiquidityShareComputation {}, + LiquidityShareComputationFailed, #[error("The amount of LP shares to withdraw is invalid")] InvalidLpShare, #[error("Spread limit exceeded")] - MaxSpreadAssertion {}, + MaxSpreadAssertion, #[error("Slippage tolerance exceeded")] - MaxSlippageAssertion {}, + MaxSlippageAssertion, #[error("The asset doesn't match the assets stored in contract")] - AssetMismatch {}, - - #[error("Too small offer amount")] - TooSmallOfferAmount {}, + AssetMismatch, #[error("Failed to converge when performing newtons method")] - ConvergeError {}, + ConvergeError, #[error("An conversion overflow occurred when attempting to swap an asset")] - SwapOverflowError {}, + SwapOverflowError, #[error("An overflow occurred when attempting to construct a decimal")] - DecimalOverflow {}, - - #[error("A balance greater than zero is required by the factory to verify the asset")] - InvalidVerificationBalance {}, - - #[error("Burn fee is not allowed when using factory tokens")] - TokenFactoryAssetBurnDisabled {}, + DecimalOverflow, #[error("The token factory feature is not enabled")] - TokenFactoryNotEnabled {}, + TokenFactoryNotEnabled, #[error("{0}")] OverflowError(#[from] OverflowError), @@ -148,7 +139,7 @@ pub enum ContractError { }, #[error("Must provide swap operations to execute")] - NoSwapOperationsProvided {}, + NoSwapOperationsProvided, #[error("Attempt to perform non-consecutive swap operation from previous output of {previous_output} to next input of {next_input}")] NonConsecutiveSwapOperations { @@ -157,10 +148,7 @@ pub enum ContractError { }, #[error("Invalid pair creation fee, expected {expected} got {amount}")] - InvalidPairCreationFee { - amount: cosmwasm_std::Uint128, - expected: cosmwasm_std::Uint128, - }, + InvalidPairCreationFee { amount: Uint128, expected: Uint128 }, #[error("Funds for {denom} were missing when performing swap")] MissingNativeSwapFunds { denom: String }, diff --git a/contracts/liquidity_hub/pool-manager/src/helpers.rs b/contracts/liquidity_hub/pool-manager/src/helpers.rs index 00fc01e18..f945c2508 100644 --- a/contracts/liquidity_hub/pool-manager/src/helpers.rs +++ b/contracts/liquidity_hub/pool-manager/src/helpers.rs @@ -2,26 +2,22 @@ use std::ops::Mul; use cosmwasm_schema::cw_serde; use cosmwasm_std::{ - coin, ensure, Addr, Coin, Decimal, Decimal256, Deps, DepsMut, Env, StdError, StdResult, - Storage, Uint128, Uint256, + ensure, Addr, Coin, Decimal, Decimal256, Deps, DepsMut, Env, StdError, StdResult, Storage, + Uint128, Uint256, }; use white_whale_std::fee::PoolFee; -use white_whale_std::pool_manager::{ - SimulateSwapOperationsResponse, SimulationResponse, SwapOperation, -}; +use white_whale_std::pool_manager::SimulationResponse; use white_whale_std::pool_network::asset::{Asset, AssetInfo, PairType}; use crate::error::ContractError; use crate::math::Decimal256Helper; -use crate::queries::query_simulation; - -pub const INSTANTIATE_REPLY_ID: u64 = 1; /// The amount of iterations to perform when calculating the Newton-Raphson approximation. const NEWTON_ITERATIONS: u64 = 32; -// the number of pools in the pair +// todo isn't this for the 3pool? shouldn't it be 3 +// the number of assets in the pair const N_COINS: Uint256 = Uint256::from_u128(2); fn calculate_stableswap_d( @@ -81,7 +77,7 @@ fn calculate_stableswap_d( // completed iterations // but we never approximated correctly - Err(ContractError::ConvergeError {}) + Err(ContractError::ConvergeError) } /// Determines the direction of `offer_pool` -> `ask_pool`. @@ -132,18 +128,14 @@ pub fn calculate_stableswap_y( if y >= previous_y { if y.checked_sub(previous_y)? <= Uint256::one() { - return y - .try_into() - .map_err(|_| ContractError::SwapOverflowError {}); + return y.try_into().map_err(|_| ContractError::SwapOverflowError); } } else if y < previous_y && previous_y.checked_sub(y)? <= Uint256::one() { - return y - .try_into() - .map_err(|_| ContractError::SwapOverflowError {}); + return y.try_into().map_err(|_| ContractError::SwapOverflowError); } } - Err(ContractError::ConvergeError {}) + Err(ContractError::ConvergeError) } pub fn compute_swap( @@ -187,19 +179,19 @@ pub fn compute_swap( Ok(SwapComputation { return_amount: return_amount .try_into() - .map_err(|_| ContractError::SwapOverflowError {})?, + .map_err(|_| ContractError::SwapOverflowError)?, spread_amount: spread_amount .try_into() - .map_err(|_| ContractError::SwapOverflowError {})?, + .map_err(|_| ContractError::SwapOverflowError)?, swap_fee_amount: swap_fee_amount .try_into() - .map_err(|_| ContractError::SwapOverflowError {})?, + .map_err(|_| ContractError::SwapOverflowError)?, protocol_fee_amount: protocol_fee_amount .try_into() - .map_err(|_| ContractError::SwapOverflowError {})?, + .map_err(|_| ContractError::SwapOverflowError)?, burn_fee_amount: burn_fee_amount .try_into() - .map_err(|_| ContractError::SwapOverflowError {})?, + .map_err(|_| ContractError::SwapOverflowError)?, }) } @@ -216,22 +208,22 @@ pub fn compute_swap( Ok(SwapComputation { return_amount: return_amount .try_into() - .map_err(|_| ContractError::SwapOverflowError {})?, + .map_err(|_| ContractError::SwapOverflowError)?, spread_amount: spread_amount .try_into() - .map_err(|_| ContractError::SwapOverflowError {})?, + .map_err(|_| ContractError::SwapOverflowError)?, swap_fee_amount: swap_fee_amount .try_into() - .map_err(|_| ContractError::SwapOverflowError {})?, + .map_err(|_| ContractError::SwapOverflowError)?, protocol_fee_amount: protocol_fee_amount .try_into() - .map_err(|_| ContractError::SwapOverflowError {})?, + .map_err(|_| ContractError::SwapOverflowError)?, burn_fee_amount: burn_fee_amount .try_into() - .map_err(|_| ContractError::SwapOverflowError {})?, + .map_err(|_| ContractError::SwapOverflowError)?, osmosis_fee_amount: osmosis_fee_amount .try_into() - .map_err(|_| ContractError::SwapOverflowError {})?, + .map_err(|_| ContractError::SwapOverflowError)?, }) } } @@ -274,19 +266,19 @@ pub fn compute_swap( Ok(SwapComputation { return_amount: return_amount .try_into() - .map_err(|_| ContractError::SwapOverflowError {})?, + .map_err(|_| ContractError::SwapOverflowError)?, spread_amount: spread_amount .try_into() - .map_err(|_| ContractError::SwapOverflowError {})?, + .map_err(|_| ContractError::SwapOverflowError)?, swap_fee_amount: swap_fee_amount .try_into() - .map_err(|_| ContractError::SwapOverflowError {})?, + .map_err(|_| ContractError::SwapOverflowError)?, protocol_fee_amount: protocol_fee_amount .try_into() - .map_err(|_| ContractError::SwapOverflowError {})?, + .map_err(|_| ContractError::SwapOverflowError)?, burn_fee_amount: burn_fee_amount .try_into() - .map_err(|_| ContractError::SwapOverflowError {})?, + .map_err(|_| ContractError::SwapOverflowError)?, }) } @@ -303,22 +295,22 @@ pub fn compute_swap( Ok(SwapComputation { return_amount: return_amount .try_into() - .map_err(|_| ContractError::SwapOverflowError {})?, + .map_err(|_| ContractError::SwapOverflowError)?, spread_amount: spread_amount .try_into() - .map_err(|_| ContractError::SwapOverflowError {})?, + .map_err(|_| ContractError::SwapOverflowError)?, swap_fee_amount: swap_fee_amount .try_into() - .map_err(|_| ContractError::SwapOverflowError {})?, + .map_err(|_| ContractError::SwapOverflowError)?, protocol_fee_amount: protocol_fee_amount .try_into() - .map_err(|_| ContractError::SwapOverflowError {})?, + .map_err(|_| ContractError::SwapOverflowError)?, burn_fee_amount: burn_fee_amount .try_into() - .map_err(|_| ContractError::SwapOverflowError {})?, + .map_err(|_| ContractError::SwapOverflowError)?, osmosis_fee_amount: osmosis_fee_amount .try_into() - .map_err(|_| ContractError::SwapOverflowError {})?, + .map_err(|_| ContractError::SwapOverflowError)?, }) } } @@ -458,7 +450,7 @@ pub fn assert_slippage_tolerance( // slippage when adding liquidity. Due to the math behind the stableswap, the amp factor // needs to be in as well, much like when swaps are done if pool_ratio * one_minus_slippage_tolerance > deposit_ratio { - return Err(ContractError::MaxSlippageAssertion {}); + return Err(ContractError::MaxSlippageAssertion); } } PairType::ConstantProduct => { @@ -468,7 +460,7 @@ pub fn assert_slippage_tolerance( * one_minus_slippage_tolerance > Decimal256::from_ratio(pools[1], pools[0]) { - return Err(ContractError::MaxSlippageAssertion {}); + return Err(ContractError::MaxSlippageAssertion); } } } @@ -528,74 +520,12 @@ pub fn assert_admin(deps: Deps, env: &Env, sender: &Addr) -> Result<(), Contract .query_wasm_contract_info(env.contract.address.clone())?; if let Some(admin) = contract_info.admin { if sender != deps.api.addr_validate(admin.as_str())? { - return Err(ContractError::Unauthorized {}); + return Err(ContractError::Unauthorized); } } Ok(()) } -/// This function iterates over the swap operations, simulates each swap -/// to get the final amount after all the swaps. -pub fn simulate_swap_operations( - deps: Deps, - offer_amount: Uint128, - operations: Vec, -) -> Result { - let operations_len = operations.len(); - if operations_len == 0 { - return Err(ContractError::NoSwapOperationsProvided {}); - } - - let mut amount = offer_amount; - - for operation in operations.into_iter() { - match operation { - SwapOperation::WhaleSwap { - token_in_denom, - token_out_denom: _, - pool_identifier, - } => { - let res = - query_simulation(deps, coin(amount.u128(), token_in_denom), pool_identifier)?; - amount = res.return_amount; - } - } - } - - Ok(SimulateSwapOperationsResponse { amount }) -} - -/// This function iterates over the swap operations in the reverse order, -/// simulates each swap to get the final amount after all the swaps. -pub fn reverse_simulate_swap_operations( - deps: Deps, - ask_amount: Uint128, - operations: Vec, -) -> Result { - let operations_len = operations.len(); - if operations_len == 0 { - return Err(ContractError::NoSwapOperationsProvided {}); - } - - let mut amount = ask_amount; - - for operation in operations.into_iter().rev() { - match operation { - SwapOperation::WhaleSwap { - token_in_denom: _, - token_out_denom, - pool_identifier, - } => { - let res = - query_simulation(deps, coin(amount.u128(), token_out_denom), pool_identifier)?; - amount = res.return_amount; - } - } - } - - Ok(SimulateSwapOperationsResponse { amount }) -} - /// Validates the amounts after a single side liquidity provision swap are correct. pub fn validate_asset_balance( deps: &DepsMut, diff --git a/contracts/liquidity_hub/pool-manager/src/liquidity/commands.rs b/contracts/liquidity_hub/pool-manager/src/liquidity/commands.rs index 0a1bd3075..d7b4392aa 100644 --- a/contracts/liquidity_hub/pool-manager/src/liquidity/commands.rs +++ b/contracts/liquidity_hub/pool-manager/src/liquidity/commands.rs @@ -65,7 +65,7 @@ pub fn provide_liquidity( deposits.iter().all(|asset| pool_assets .iter() .any(|pool_asset| pool_asset.denom == asset.denom)), - ContractError::AssetMismatch {} + ContractError::AssetMismatch ); let receiver = @@ -95,7 +95,7 @@ pub fn provide_liquidity( let ask_denom = pool_assets .iter() .find(|pool_asset| pool_asset.denom != deposit.denom) - .ok_or(ContractError::AssetMismatch {})? + .ok_or(ContractError::AssetMismatch)? .denom .clone(); @@ -123,7 +123,7 @@ pub fn provide_liquidity( // subtracting the fees. ensure!( !expected_ask_asset_balance_in_contract.amount.is_zero(), - StdError::generic_err("Spread limit exceeded") + ContractError::MaxSpreadAssertion ); SINGLE_SIDE_LIQUIDITY_PROVISION_BUFFER.save( @@ -170,7 +170,7 @@ pub fn provide_liquidity( let pool_asset_index = pool_assets .iter() .position(|pool_asset| &pool_asset.denom == asset_denom) - .ok_or(ContractError::AssetMismatch {})?; + .ok_or(ContractError::AssetMismatch)?; // Increment the pool asset amount by the amount sent pool_assets[pool_asset_index].amount = pool_assets[pool_asset_index] @@ -181,7 +181,7 @@ pub fn provide_liquidity( // After totting up the pool assets we need to check if any of them are zero. // The very first deposit cannot be done with a single asset if pool_assets.iter().any(|deposit| deposit.amount.is_zero()) { - return Err(ContractError::InvalidZeroAmount {}); + return Err(ContractError::InvalidZeroAmount); } let mut messages: Vec = vec![]; @@ -199,7 +199,9 @@ pub fn provide_liquidity( let share = Uint128::new( (U256::from(pool_assets[0].amount.u128()) .checked_mul(U256::from(pool_assets[1].amount.u128())) - .ok_or::(ContractError::LiquidityShareComputation {}))? + .ok_or::( + ContractError::LiquidityShareComputationFailed, + ))? .integer_sqrt() .as_u128(), ) diff --git a/contracts/liquidity_hub/pool-manager/src/manager/commands.rs b/contracts/liquidity_hub/pool-manager/src/manager/commands.rs index 0b048abbc..e3c1ec7a6 100644 --- a/contracts/liquidity_hub/pool-manager/src/manager/commands.rs +++ b/contracts/liquidity_hub/pool-manager/src/manager/commands.rs @@ -117,7 +117,7 @@ pub fn create_pair( .iter() .any(|asset| asset_denoms.iter().filter(|&a| a == asset).count() > 1) { - return Err(ContractError::SameAsset {}); + return Err(ContractError::SameAsset); } // Verify pool fees @@ -179,7 +179,7 @@ pub fn create_pair( not(feature = "injective") ))] { - return Err(ContractError::TokenFactoryNotEnabled {}); + return Err(ContractError::TokenFactoryNotEnabled); } messages.push(white_whale_std::tokenfactory::create_denom::create_denom( diff --git a/contracts/liquidity_hub/pool-manager/src/math.rs b/contracts/liquidity_hub/pool-manager/src/math.rs index 3c01f4acb..2f512bc76 100644 --- a/contracts/liquidity_hub/pool-manager/src/math.rs +++ b/contracts/liquidity_hub/pool-manager/src/math.rs @@ -23,7 +23,7 @@ impl Decimal256Helper for Decimal256 { precision: u8, ) -> Result { Decimal256::from_atomics(value, u32::from(precision)) - .map_err(|_| ContractError::DecimalOverflow {}) + .map_err(|_| ContractError::DecimalOverflow) } fn checked_multiply_ratio( diff --git a/contracts/liquidity_hub/pool-manager/src/queries.rs b/contracts/liquidity_hub/pool-manager/src/queries.rs index c831e138f..fa73b4343 100644 --- a/contracts/liquidity_hub/pool-manager/src/queries.rs +++ b/contracts/liquidity_hub/pool-manager/src/queries.rs @@ -1,10 +1,11 @@ use std::cmp::Ordering; -use cosmwasm_std::{Coin, Decimal256, Deps, Env, Fraction, Order, StdResult, Uint128}; +use cosmwasm_std::{coin, Coin, Decimal256, Deps, Env, Fraction, Order, StdResult, Uint128}; use white_whale_std::pool_manager::{ - AssetDecimalsResponse, Config, PairInfoResponse, ReverseSimulationResponse, SimulationResponse, - SwapRoute, SwapRouteCreatorResponse, SwapRouteResponse, SwapRoutesResponse, + AssetDecimalsResponse, Config, PairInfoResponse, ReverseSimulationResponse, + SimulateSwapOperationsResponse, SimulationResponse, SwapOperation, SwapRoute, + SwapRouteCreatorResponse, SwapRouteResponse, SwapRoutesResponse, }; use white_whale_std::pool_network::asset::PairType; @@ -32,7 +33,7 @@ pub fn query_asset_decimals( .asset_denoms .iter() .position(|d| d.clone() == denom) - .ok_or(ContractError::AssetMismatch {})?; + .ok_or(ContractError::AssetMismatch)?; Ok(AssetDecimalsResponse { pair_identifier, @@ -70,7 +71,7 @@ pub fn query_simulation( offer_decimal = decimals[1]; ask_decimal = decimals[0]; } else { - return Err(ContractError::AssetMismatch {}); + return Err(ContractError::AssetMismatch); } let pool_fees = pair_info.pool_fees; @@ -315,105 +316,64 @@ pub fn get_pair(deps: Deps, pair_identifier: String) -> Result, -// ) -> Result { -// let operations_len = operations.len(); -// if operations_len == 0 { -// return Err(ContractError::NoSwapOperationsProvided {}); -// } - -// let mut offer_amount = offer_amount; -// for operation in operations.into_iter() { -// match operation { -// SwapOperation::WhaleSwap { -// token_in_info, -// token_out_info, -// pool_identifier, -// } => { -// let res: SimulationResponse = query_simulation( -// deps, -// env.clone(), -// Asset { -// info: token_in_info, -// amount: offer_amount, -// }, -// Asset { -// info: token_out_info, -// amount: Uint128::zero(), -// }, -// pool_identifier, -// )?; - -// offer_amount = res.return_amount; -// } -// } -// } - -// Ok(SimulateSwapOperationsResponse { -// amount: offer_amount, -// }) -// } - -// pub fn reverse_simulate_swap_operations( -// deps: Deps, -// env: Env, -// ask_amount: Uint128, -// operations: Vec, -// ) -> Result { -// let operations_len = operations.len(); -// if operations_len == 0 { -// return Err(ContractError::NoSwapOperationsProvided {}); -// } - -// let mut ask_amount = ask_amount; -// for operation in operations.into_iter().rev() { -// ask_amount = match operation { -// SwapOperation::WhaleSwap { -// token_in_info: offer_asset_info, -// token_out_info: ask_asset_info, -// pool_identifier, -// } => reverse_simulate_return_amount( -// deps, -// env.clone(), -// ask_amount, -// offer_asset_info, -// ask_asset_info, -// pool_identifier, -// )?, -// } -// } - -// Ok(SimulateSwapOperationsResponse { amount: ask_amount }) -// } - -// pub fn reverse_simulate_return_amount( -// deps: Deps, -// env: Env, -// _ask_amount: Uint128, -// offer_asset_info: AssetInfo, -// ask_asset_info: AssetInfo, -// pool_identifier: String, -// ) -> Result { -// let _pair_info = get_pair_by_identifier(&deps, pool_identifier.clone())?; - -// let res: ReverseSimulationResponse = query_reverse_simulation( -// deps, -// env, -// Asset { -// info: ask_asset_info, -// amount: Uint128::zero(), -// }, -// Asset { -// info: offer_asset_info, -// amount: Uint128::zero(), -// }, -// pool_identifier, -// )?; - -// Ok(res.offer_amount) -// } +/// This function iterates over the swap operations, simulates each swap +/// to get the final amount after all the swaps. +pub fn simulate_swap_operations( + deps: Deps, + offer_amount: Uint128, + operations: Vec, +) -> Result { + let operations_len = operations.len(); + if operations_len == 0 { + return Err(ContractError::NoSwapOperationsProvided); + } + + let mut amount = offer_amount; + + for operation in operations.into_iter() { + match operation { + SwapOperation::WhaleSwap { + token_in_denom, + token_out_denom: _, + pool_identifier, + } => { + let res = + query_simulation(deps, coin(amount.u128(), token_in_denom), pool_identifier)?; + amount = res.return_amount; + } + } + } + + Ok(SimulateSwapOperationsResponse { amount }) +} + +/// This function iterates over the swap operations in the reverse order, +/// simulates each swap to get the final amount after all the swaps. +pub fn reverse_simulate_swap_operations( + deps: Deps, + ask_amount: Uint128, + operations: Vec, +) -> Result { + let operations_len = operations.len(); + if operations_len == 0 { + return Err(ContractError::NoSwapOperationsProvided); + } + + let mut amount = ask_amount; + + for operation in operations.into_iter().rev() { + match operation { + SwapOperation::WhaleSwap { + token_in_denom: _, + token_out_denom, + pool_identifier, + } => { + let res = + query_simulation(deps, coin(amount.u128(), token_out_denom), pool_identifier)?; + amount = res.return_amount; + } + } + } + + Ok(SimulateSwapOperationsResponse { amount }) +} diff --git a/contracts/liquidity_hub/pool-manager/src/router/commands.rs b/contracts/liquidity_hub/pool-manager/src/router/commands.rs index 284d75b96..be14d3b4e 100644 --- a/contracts/liquidity_hub/pool-manager/src/router/commands.rs +++ b/contracts/liquidity_hub/pool-manager/src/router/commands.rs @@ -1,12 +1,12 @@ use cosmwasm_std::{ - attr, coin, to_json_binary, Addr, BankMsg, Coin, CosmosMsg, Decimal, DepsMut, MessageInfo, - Response, Uint128, WasmMsg, + attr, coin, wasm_execute, Addr, BankMsg, Coin, CosmosMsg, Decimal, DepsMut, MessageInfo, + Response, Uint128, }; use white_whale_std::pool_manager::{SwapOperation, SwapRoute}; use white_whale_std::whale_lair; +use crate::queries::simulate_swap_operations; use crate::{ - helpers::simulate_swap_operations, state::{SwapOperations, CONFIG, SWAP_ROUTES}, swap::perform_swap::perform_swap, ContractError, @@ -17,7 +17,7 @@ fn assert_operations(operations: Vec) -> Result<(), ContractError // check that the output of each swap is the input of the next swap let mut previous_output_info = operations .first() - .ok_or(ContractError::NoSwapOperationsProvided {})? + .ok_or(ContractError::NoSwapOperationsProvided)? .get_input_asset_info() .clone(); @@ -53,12 +53,12 @@ pub fn execute_swap_operations( // and retrieve the output token info let target_asset_denom = operations .last() - .ok_or(ContractError::NoSwapOperationsProvided {})? + .ok_or(ContractError::NoSwapOperationsProvided)? .get_target_asset_info(); let offer_asset_denom = operations .first() - .ok_or(ContractError::NoSwapOperationsProvided {})? + .ok_or(ContractError::NoSwapOperationsProvided)? .get_input_asset_info(); let offer_asset = Coin { @@ -117,21 +117,16 @@ pub fn execute_swap_operations( })); } if !swap_result.protocol_fee_asset.amount.is_zero() { - fee_messages.push(CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: config.bonding_manager_addr.to_string(), - msg: to_json_binary(&whale_lair::ExecuteMsg::FillRewards { - assets: vec![swap_result.protocol_fee_asset.clone()], - })?, - funds: vec![swap_result.protocol_fee_asset.clone()], - })); - } - - // todo remove, the swap_fee_asset stays in the pool - if !swap_result.swap_fee_asset.amount.is_zero() { - fee_messages.push(CosmosMsg::Bank(BankMsg::Send { - to_address: config.bonding_manager_addr.to_string(), - amount: vec![swap_result.swap_fee_asset], - })); + fee_messages.push( + wasm_execute( + config.bonding_manager_addr.to_string(), + &whale_lair::ExecuteMsg::FillRewards { + assets: vec![swap_result.protocol_fee_asset.clone()], + }, + vec![swap_result.protocol_fee_asset.clone()], + )? + .into(), + ); } } } @@ -224,7 +219,7 @@ pub fn remove_swap_routes( // only contract owner or route creator can remove the swap route let creator = swap_route_key.load(deps.storage)?.creator; if !cw_ownable::is_owner(deps.storage, &sender)? && sender != creator { - return Err(ContractError::Unauthorized {}); + return Err(ContractError::Unauthorized); } swap_route_key.remove(deps.storage); attributes.push(attr("swap_route", swap_route.clone().to_string())); diff --git a/contracts/liquidity_hub/pool-manager/src/state.rs b/contracts/liquidity_hub/pool-manager/src/state.rs index 29f6e2b3c..458b257aa 100644 --- a/contracts/liquidity_hub/pool-manager/src/state.rs +++ b/contracts/liquidity_hub/pool-manager/src/state.rs @@ -78,7 +78,7 @@ pub fn get_pair_by_identifier( ) -> Result { PAIRS .may_load(deps.storage, pair_identifier)? - .ok_or(ContractError::UnExistingPair {}) + .ok_or(ContractError::UnExistingPair) } /// Swap routes are used to establish defined routes for a given fee diff --git a/contracts/liquidity_hub/pool-manager/src/swap/commands.rs b/contracts/liquidity_hub/pool-manager/src/swap/commands.rs index 12460065c..d00afa10f 100644 --- a/contracts/liquidity_hub/pool-manager/src/swap/commands.rs +++ b/contracts/liquidity_hub/pool-manager/src/swap/commands.rs @@ -42,7 +42,7 @@ pub fn swap( .assets .iter() .any(|pool_asset| pool_asset.denom == *asset)), - ContractError::AssetMismatch {} + ContractError::AssetMismatch ); // perform the swap @@ -59,7 +59,6 @@ pub fn swap( let receiver = validate_addr_or_default(&deps.as_ref(), receiver, info.sender); - // first we add the swap result if !swap_result.return_asset.amount.is_zero() { messages.push(CosmosMsg::Bank(BankMsg::Send { to_address: receiver.clone().into_string(), @@ -67,12 +66,12 @@ pub fn swap( })); } - // then we add the fees if !swap_result.burn_fee_asset.amount.is_zero() { messages.push(CosmosMsg::Bank(BankMsg::Burn { amount: vec![swap_result.burn_fee_asset.clone()], })); } + if !swap_result.protocol_fee_asset.amount.is_zero() { messages.push( wasm_execute( diff --git a/contracts/liquidity_hub/pool-manager/src/swap/perform_swap.rs b/contracts/liquidity_hub/pool-manager/src/swap/perform_swap.rs index 7b098c8de..8c2ddfe34 100644 --- a/contracts/liquidity_hub/pool-manager/src/swap/perform_swap.rs +++ b/contracts/liquidity_hub/pool-manager/src/swap/perform_swap.rs @@ -67,7 +67,7 @@ pub fn perform_swap( offer_decimal = decimals[1]; ask_decimal = decimals[0]; } else { - return Err(ContractError::AssetMismatch {}); + return Err(ContractError::AssetMismatch); } let offer_amount = offer_asset.amount; diff --git a/contracts/liquidity_hub/pool-manager/src/tests/integration_tests.rs b/contracts/liquidity_hub/pool-manager/src/tests/integration_tests.rs index 6de17eddd..48b4e6923 100644 --- a/contracts/liquidity_hub/pool-manager/src/tests/integration_tests.rs +++ b/contracts/liquidity_hub/pool-manager/src/tests/integration_tests.rs @@ -501,7 +501,7 @@ mod router { suite.bonding_manager_addr.to_string(), "uusd".to_string(), |amt| { - assert_eq!(amt.unwrap().amount.u128(), 2000 + 4 * 2); + assert_eq!(amt.unwrap().amount.u128(), 2000 + 4); }, ); suite.query_balance( @@ -515,7 +515,7 @@ mod router { suite.bonding_manager_addr.to_string(), "uluna".to_string(), |amt| { - assert_eq!(amt.unwrap().amount.u128(), 4 * 2); + assert_eq!(amt.unwrap().amount.u128(), 4); }, ); } @@ -659,7 +659,7 @@ mod router { |result| { assert_eq!( result.unwrap_err().downcast_ref::(), - Some(&ContractError::NoSwapOperationsProvided {}) + Some(&ContractError::NoSwapOperationsProvided) ) }, ); @@ -2995,7 +2995,7 @@ mod provide_liquidity { let err = result.unwrap_err().downcast::().unwrap(); match err { - ContractError::AssetMismatch { .. } => {} + ContractError::AssetMismatch => {} _ => panic!("Wrong error type, should return ContractError::AssetMismatch"), } }, @@ -3045,7 +3045,7 @@ mod provide_liquidity { let err = result.unwrap_err().downcast::().unwrap(); match err { - ContractError::AssetMismatch {} => {} + ContractError::AssetMismatch => {} _ => panic!("Wrong error type, should return ContractError::AssetMismatch"), } }, From cabb5254681913b28908460ea1570d3da49a2cd2 Mon Sep 17 00:00:00 2001 From: Kerber0x Date: Thu, 2 May 2024 15:30:05 +0100 Subject: [PATCH 3/7] refactor(pool-manager): rename pair to pool --- .../pool-manager/schema/pool-manager.json | 271 ++--- .../pool-manager/schema/raw/execute.json | 131 +-- .../pool-manager/schema/raw/query.json | 20 +- .../raw/response_to_asset_decimals.json | 8 +- .../schema/raw/response_to_pool.json | 176 ++++ .../pool-manager/src/contract.rs | 101 +- .../liquidity_hub/pool-manager/src/error.rs | 14 +- .../liquidity_hub/pool-manager/src/helpers.rs | 26 +- .../pool-manager/src/liquidity/commands.rs | 53 +- .../pool-manager/src/manager/commands.rs | 68 +- .../liquidity_hub/pool-manager/src/queries.rs | 61 +- .../pool-manager/src/router/commands.rs | 29 +- .../liquidity_hub/pool-manager/src/state.rs | 42 +- .../pool-manager/src/swap/commands.rs | 15 +- .../pool-manager/src/swap/perform_swap.rs | 47 +- .../pool-manager/src/tests/gas/mod.rs | 1 - .../src/tests/integration_tests.rs | 278 +++--- .../pool-manager/src/tests/mock_querier.rs | 324 ------ .../pool-manager/src/tests/mod.rs | 4 - .../pool-manager/src/tests/suite.rs | 97 +- .../pool-manager/src/tests/temp_mock_api.rs | 87 -- .../pool-manager/src/tests/unit_tests/mod.rs | 3 - .../src/tests/unit_tests/pairs.rs | 620 ------------ .../src/tests/unit_tests/provide_liquidity.rs | 941 ------------------ .../pool-manager/src/tests/unit_tests/swap.rs | 395 -------- .../src/tests/unit_tests/withdrawals.rs | 654 ------------ packages/white-whale-std/src/pool_manager.rs | 83 +- 27 files changed, 855 insertions(+), 3694 deletions(-) create mode 100644 contracts/liquidity_hub/pool-manager/schema/raw/response_to_pool.json delete mode 100644 contracts/liquidity_hub/pool-manager/src/tests/gas/mod.rs delete mode 100644 contracts/liquidity_hub/pool-manager/src/tests/mock_querier.rs delete mode 100644 contracts/liquidity_hub/pool-manager/src/tests/temp_mock_api.rs delete mode 100644 contracts/liquidity_hub/pool-manager/src/tests/unit_tests/mod.rs delete mode 100644 contracts/liquidity_hub/pool-manager/src/tests/unit_tests/pairs.rs delete mode 100644 contracts/liquidity_hub/pool-manager/src/tests/unit_tests/provide_liquidity.rs delete mode 100644 contracts/liquidity_hub/pool-manager/src/tests/unit_tests/swap.rs delete mode 100644 contracts/liquidity_hub/pool-manager/src/tests/unit_tests/withdrawals.rs diff --git a/contracts/liquidity_hub/pool-manager/schema/pool-manager.json b/contracts/liquidity_hub/pool-manager/schema/pool-manager.json index 382096178..8d15e2023 100644 --- a/contracts/liquidity_hub/pool-manager/schema/pool-manager.json +++ b/contracts/liquidity_hub/pool-manager/schema/pool-manager.json @@ -50,21 +50,23 @@ "title": "ExecuteMsg", "oneOf": [ { + "description": "Creates a new pool.", "type": "object", "required": [ - "create_pair" + "create_pool" ], "properties": { - "create_pair": { + "create_pool": { "type": "object", "required": [ "asset_decimals", "asset_denoms", - "pair_type", - "pool_fees" + "pool_fees", + "pool_type" ], "properties": { "asset_decimals": { + "description": "The decimals for the given asset denoms, provided in the same order as `asset_denoms`.", "type": "array", "items": { "type": "integer", @@ -73,22 +75,34 @@ } }, "asset_denoms": { + "description": "The asset denoms for the pool.", "type": "array", "items": { "type": "string" } }, - "pair_identifier": { + "pool_fees": { + "description": "The fees for the pool.", + "allOf": [ + { + "$ref": "#/definitions/PoolFee" + } + ] + }, + "pool_identifier": { + "description": "The identifier for the pool.", "type": [ "string", "null" ] }, - "pair_type": { - "$ref": "#/definitions/PairType" - }, - "pool_fees": { - "$ref": "#/definitions/PoolFee" + "pool_type": { + "description": "The type of pool to create.", + "allOf": [ + { + "$ref": "#/definitions/PoolType" + } + ] } }, "additionalProperties": false @@ -106,7 +120,7 @@ "provide_liquidity": { "type": "object", "required": [ - "pair_identifier" + "pool_identifier" ], "properties": { "lock_position_identifier": { @@ -117,6 +131,7 @@ ] }, "max_spread": { + "description": "The maximum allowable spread between the bid and ask prices for the pool. When provided, if the spread exceeds this value, the liquidity provision will not be executed.", "anyOf": [ { "$ref": "#/definitions/Decimal" @@ -126,16 +141,19 @@ } ] }, - "pair_identifier": { + "pool_identifier": { + "description": "The identifier for the pool to provide liquidity for.", "type": "string" }, "receiver": { + "description": "The receiver of the LP", "type": [ "string", "null" ] }, "slippage_tolerance": { + "description": "A percentage value representing the acceptable slippage for the operation. When provided, if the slippage exceeds this value, the liquidity provision will not be executed.", "anyOf": [ { "$ref": "#/definitions/Decimal" @@ -171,14 +189,15 @@ "type": "object", "required": [ "ask_asset_denom", - "offer_asset", - "pair_identifier" + "pool_identifier" ], "properties": { "ask_asset_denom": { + "description": "The return asset of the swap.", "type": "string" }, "belief_price": { + "description": "The belief price of the swap.", "anyOf": [ { "$ref": "#/definitions/Decimal" @@ -189,6 +208,7 @@ ] }, "max_spread": { + "description": "The maximum spread to incur when performing the swap. If the spread exceeds this value, the swap will not be executed.", "anyOf": [ { "$ref": "#/definitions/Decimal" @@ -198,13 +218,12 @@ } ] }, - "offer_asset": { - "$ref": "#/definitions/Coin" - }, - "pair_identifier": { + "pool_identifier": { + "description": "The identifier for the pool to swap in.", "type": "string" }, - "to": { + "receiver": { + "description": "The recipient of the output tokens. If not provided, the tokens will be sent to the sender of the message.", "type": [ "string", "null" @@ -226,10 +245,10 @@ "withdraw_liquidity": { "type": "object", "required": [ - "pair_identifier" + "pool_identifier" ], "properties": { - "pair_identifier": { + "pool_identifier": { "type": "string" } }, @@ -280,7 +299,7 @@ "$ref": "#/definitions/SwapOperation" } }, - "to": { + "receiver": { "description": "The (optional) recipient of the output tokens.\n\nIf left unspecified, tokens will be sent to the sender of the message.", "type": [ "string", @@ -553,40 +572,6 @@ }, "additionalProperties": false }, - "PairType": { - "oneOf": [ - { - "type": "string", - "enum": [ - "constant_product" - ] - }, - { - "type": "object", - "required": [ - "stable_swap" - ], - "properties": { - "stable_swap": { - "type": "object", - "required": [ - "amp" - ], - "properties": { - "amp": { - "description": "The amount of amplification to perform on the constant product part of the swap formula.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - } - ] - }, "PoolFee": { "description": "Represents the fee structure for transactions within a pool.\n\n# Fields - `protocol_fee`: The fee percentage charged by the protocol on each transaction to support operational and developmental needs. - `swap_fee`: The fee percentage allocated to liquidity providers as a reward for supplying liquidity to the pool, incentivizing participation and ensuring pool health. - `burn_fee`: A fee percentage that is burned on each transaction, helping manage the token economy by reducing supply over time, potentially increasing token value. - `osmosis_fee` (optional): Specific to the Osmosis feature, this fee is charged on each transaction when the Osmosis feature is enabled, supporting specific ecosystem requirements. - `extra_fees`: A vector of custom fees allowing for extensible and adaptable fee structures to meet diverse and evolving needs. Validation ensures that the total of all fees does not exceed 100%, maintaining fairness and avoiding overcharging.\n\n# Features - `osmosis`: Enables the `osmosis_fee` field, integrating specific fee requirements for the Osmosis protocol within the pool's fee structure.", "type": "object", @@ -631,6 +616,40 @@ }, "additionalProperties": false }, + "PoolType": { + "oneOf": [ + { + "type": "string", + "enum": [ + "constant_product" + ] + }, + { + "type": "object", + "required": [ + "stable_swap" + ], + "properties": { + "stable_swap": { + "type": "object", + "required": [ + "amp" + ], + "properties": { + "amp": { + "description": "The amount of amplification to perform on the constant product part of the swap formula.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] + }, "SwapOperation": { "oneOf": [ { @@ -734,13 +753,13 @@ "type": "object", "required": [ "denom", - "pair_identifier" + "pool_identifier" ], "properties": { "denom": { "type": "string" }, - "pair_identifier": { + "pool_identifier": { "type": "string" } }, @@ -760,13 +779,13 @@ "type": "object", "required": [ "offer_asset", - "pair_identifier" + "pool_identifier" ], "properties": { "offer_asset": { "$ref": "#/definitions/Coin" }, - "pair_identifier": { + "pool_identifier": { "type": "string" } }, @@ -787,7 +806,7 @@ "required": [ "ask_asset", "offer_asset", - "pair_identifier" + "pool_identifier" ], "properties": { "ask_asset": { @@ -796,7 +815,7 @@ "offer_asset": { "$ref": "#/definitions/Coin" }, - "pair_identifier": { + "pool_identifier": { "type": "string" } }, @@ -906,16 +925,16 @@ { "type": "object", "required": [ - "pair" + "pool" ], "properties": { - "pair": { + "pool": { "type": "object", "required": [ - "pair_identifier" + "pool_identifier" ], "properties": { - "pair_identifier": { + "pool_identifier": { "type": "string" } }, @@ -1037,7 +1056,7 @@ "required": [ "decimals", "denom", - "pair_identifier" + "pool_identifier" ], "properties": { "decimals": { @@ -1047,11 +1066,11 @@ "minimum": 0.0 }, "denom": { - "description": "The queried denom in the given pair_identifier.", + "description": "The queried denom in the given pool_identifier.", "type": "string" }, - "pair_identifier": { - "description": "The pair identifier to do the query for.", + "pool_identifier": { + "description": "The pool identifier to do the query for.", "type": "string" } }, @@ -1246,17 +1265,17 @@ } } }, - "pair": { + "pool": { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "PairInfoResponse", + "title": "PoolInfoResponse", "type": "object", "required": [ - "pair_info", + "pool_info", "total_share" ], "properties": { - "pair_info": { - "$ref": "#/definitions/PairInfo" + "pool_info": { + "$ref": "#/definitions/PoolInfo" }, "total_share": { "$ref": "#/definitions/Coin" @@ -1295,15 +1314,59 @@ }, "additionalProperties": false }, - "PairInfo": { + "PoolFee": { + "description": "Represents the fee structure for transactions within a pool.\n\n# Fields - `protocol_fee`: The fee percentage charged by the protocol on each transaction to support operational and developmental needs. - `swap_fee`: The fee percentage allocated to liquidity providers as a reward for supplying liquidity to the pool, incentivizing participation and ensuring pool health. - `burn_fee`: A fee percentage that is burned on each transaction, helping manage the token economy by reducing supply over time, potentially increasing token value. - `osmosis_fee` (optional): Specific to the Osmosis feature, this fee is charged on each transaction when the Osmosis feature is enabled, supporting specific ecosystem requirements. - `extra_fees`: A vector of custom fees allowing for extensible and adaptable fee structures to meet diverse and evolving needs. Validation ensures that the total of all fees does not exceed 100%, maintaining fairness and avoiding overcharging.\n\n# Features - `osmosis`: Enables the `osmosis_fee` field, integrating specific fee requirements for the Osmosis protocol within the pool's fee structure.", + "type": "object", + "required": [ + "burn_fee", + "extra_fees", + "protocol_fee", + "swap_fee" + ], + "properties": { + "burn_fee": { + "description": "Fee percentage that is burned on each transaction. Burning a portion of the transaction fee helps in reducing the overall token supply.", + "allOf": [ + { + "$ref": "#/definitions/Fee" + } + ] + }, + "extra_fees": { + "description": "A list of custom, additional fees that can be defined for specific use cases or additional functionalities. This vector enables the flexibility to introduce new fees without altering the core fee structure. Total of all fees, including custom ones, is validated to not exceed 100%, ensuring a balanced and fair fee distribution.", + "type": "array", + "items": { + "$ref": "#/definitions/Fee" + } + }, + "protocol_fee": { + "description": "Fee percentage charged on each transaction for the protocol's benefit.", + "allOf": [ + { + "$ref": "#/definitions/Fee" + } + ] + }, + "swap_fee": { + "description": "Fee percentage allocated to liquidity providers on each swap.", + "allOf": [ + { + "$ref": "#/definitions/Fee" + } + ] + } + }, + "additionalProperties": false + }, + "PoolInfo": { "type": "object", "required": [ "asset_decimals", "asset_denoms", "assets", "lp_denom", - "pair_type", - "pool_fees" + "pool_fees", + "pool_type" ], "properties": { "asset_decimals": { @@ -1329,16 +1392,16 @@ "lp_denom": { "type": "string" }, - "pair_type": { - "$ref": "#/definitions/PairType" - }, "pool_fees": { "$ref": "#/definitions/PoolFee" + }, + "pool_type": { + "$ref": "#/definitions/PoolType" } }, "additionalProperties": false }, - "PairType": { + "PoolType": { "oneOf": [ { "type": "string", @@ -1372,50 +1435,6 @@ } ] }, - "PoolFee": { - "description": "Represents the fee structure for transactions within a pool.\n\n# Fields - `protocol_fee`: The fee percentage charged by the protocol on each transaction to support operational and developmental needs. - `swap_fee`: The fee percentage allocated to liquidity providers as a reward for supplying liquidity to the pool, incentivizing participation and ensuring pool health. - `burn_fee`: A fee percentage that is burned on each transaction, helping manage the token economy by reducing supply over time, potentially increasing token value. - `osmosis_fee` (optional): Specific to the Osmosis feature, this fee is charged on each transaction when the Osmosis feature is enabled, supporting specific ecosystem requirements. - `extra_fees`: A vector of custom fees allowing for extensible and adaptable fee structures to meet diverse and evolving needs. Validation ensures that the total of all fees does not exceed 100%, maintaining fairness and avoiding overcharging.\n\n# Features - `osmosis`: Enables the `osmosis_fee` field, integrating specific fee requirements for the Osmosis protocol within the pool's fee structure.", - "type": "object", - "required": [ - "burn_fee", - "extra_fees", - "protocol_fee", - "swap_fee" - ], - "properties": { - "burn_fee": { - "description": "Fee percentage that is burned on each transaction. Burning a portion of the transaction fee helps in reducing the overall token supply.", - "allOf": [ - { - "$ref": "#/definitions/Fee" - } - ] - }, - "extra_fees": { - "description": "A list of custom, additional fees that can be defined for specific use cases or additional functionalities. This vector enables the flexibility to introduce new fees without altering the core fee structure. Total of all fees, including custom ones, is validated to not exceed 100%, ensuring a balanced and fair fee distribution.", - "type": "array", - "items": { - "$ref": "#/definitions/Fee" - } - }, - "protocol_fee": { - "description": "Fee percentage charged on each transaction for the protocol's benefit.", - "allOf": [ - { - "$ref": "#/definitions/Fee" - } - ] - }, - "swap_fee": { - "description": "Fee percentage allocated to liquidity providers on each swap.", - "allOf": [ - { - "$ref": "#/definitions/Fee" - } - ] - } - }, - "additionalProperties": false - }, "Uint128": { "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", "type": "string" diff --git a/contracts/liquidity_hub/pool-manager/schema/raw/execute.json b/contracts/liquidity_hub/pool-manager/schema/raw/execute.json index e595c48ee..15e611b06 100644 --- a/contracts/liquidity_hub/pool-manager/schema/raw/execute.json +++ b/contracts/liquidity_hub/pool-manager/schema/raw/execute.json @@ -3,21 +3,23 @@ "title": "ExecuteMsg", "oneOf": [ { + "description": "Creates a new pool.", "type": "object", "required": [ - "create_pair" + "create_pool" ], "properties": { - "create_pair": { + "create_pool": { "type": "object", "required": [ "asset_decimals", "asset_denoms", - "pair_type", - "pool_fees" + "pool_fees", + "pool_type" ], "properties": { "asset_decimals": { + "description": "The decimals for the given asset denoms, provided in the same order as `asset_denoms`.", "type": "array", "items": { "type": "integer", @@ -26,22 +28,34 @@ } }, "asset_denoms": { + "description": "The asset denoms for the pool.", "type": "array", "items": { "type": "string" } }, - "pair_identifier": { + "pool_fees": { + "description": "The fees for the pool.", + "allOf": [ + { + "$ref": "#/definitions/PoolFee" + } + ] + }, + "pool_identifier": { + "description": "The identifier for the pool.", "type": [ "string", "null" ] }, - "pair_type": { - "$ref": "#/definitions/PairType" - }, - "pool_fees": { - "$ref": "#/definitions/PoolFee" + "pool_type": { + "description": "The type of pool to create.", + "allOf": [ + { + "$ref": "#/definitions/PoolType" + } + ] } }, "additionalProperties": false @@ -59,7 +73,7 @@ "provide_liquidity": { "type": "object", "required": [ - "pair_identifier" + "pool_identifier" ], "properties": { "lock_position_identifier": { @@ -70,6 +84,7 @@ ] }, "max_spread": { + "description": "The maximum allowable spread between the bid and ask prices for the pool. When provided, if the spread exceeds this value, the liquidity provision will not be executed.", "anyOf": [ { "$ref": "#/definitions/Decimal" @@ -79,16 +94,19 @@ } ] }, - "pair_identifier": { + "pool_identifier": { + "description": "The identifier for the pool to provide liquidity for.", "type": "string" }, "receiver": { + "description": "The receiver of the LP", "type": [ "string", "null" ] }, "slippage_tolerance": { + "description": "A percentage value representing the acceptable slippage for the operation. When provided, if the slippage exceeds this value, the liquidity provision will not be executed.", "anyOf": [ { "$ref": "#/definitions/Decimal" @@ -124,14 +142,15 @@ "type": "object", "required": [ "ask_asset_denom", - "offer_asset", - "pair_identifier" + "pool_identifier" ], "properties": { "ask_asset_denom": { + "description": "The return asset of the swap.", "type": "string" }, "belief_price": { + "description": "The belief price of the swap.", "anyOf": [ { "$ref": "#/definitions/Decimal" @@ -142,6 +161,7 @@ ] }, "max_spread": { + "description": "The maximum spread to incur when performing the swap. If the spread exceeds this value, the swap will not be executed.", "anyOf": [ { "$ref": "#/definitions/Decimal" @@ -151,13 +171,12 @@ } ] }, - "offer_asset": { - "$ref": "#/definitions/Coin" - }, - "pair_identifier": { + "pool_identifier": { + "description": "The identifier for the pool to swap in.", "type": "string" }, - "to": { + "receiver": { + "description": "The recipient of the output tokens. If not provided, the tokens will be sent to the sender of the message.", "type": [ "string", "null" @@ -179,10 +198,10 @@ "withdraw_liquidity": { "type": "object", "required": [ - "pair_identifier" + "pool_identifier" ], "properties": { - "pair_identifier": { + "pool_identifier": { "type": "string" } }, @@ -233,7 +252,7 @@ "$ref": "#/definitions/SwapOperation" } }, - "to": { + "receiver": { "description": "The (optional) recipient of the output tokens.\n\nIf left unspecified, tokens will be sent to the sender of the message.", "type": [ "string", @@ -506,40 +525,6 @@ }, "additionalProperties": false }, - "PairType": { - "oneOf": [ - { - "type": "string", - "enum": [ - "constant_product" - ] - }, - { - "type": "object", - "required": [ - "stable_swap" - ], - "properties": { - "stable_swap": { - "type": "object", - "required": [ - "amp" - ], - "properties": { - "amp": { - "description": "The amount of amplification to perform on the constant product part of the swap formula.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - } - ] - }, "PoolFee": { "description": "Represents the fee structure for transactions within a pool.\n\n# Fields - `protocol_fee`: The fee percentage charged by the protocol on each transaction to support operational and developmental needs. - `swap_fee`: The fee percentage allocated to liquidity providers as a reward for supplying liquidity to the pool, incentivizing participation and ensuring pool health. - `burn_fee`: A fee percentage that is burned on each transaction, helping manage the token economy by reducing supply over time, potentially increasing token value. - `osmosis_fee` (optional): Specific to the Osmosis feature, this fee is charged on each transaction when the Osmosis feature is enabled, supporting specific ecosystem requirements. - `extra_fees`: A vector of custom fees allowing for extensible and adaptable fee structures to meet diverse and evolving needs. Validation ensures that the total of all fees does not exceed 100%, maintaining fairness and avoiding overcharging.\n\n# Features - `osmosis`: Enables the `osmosis_fee` field, integrating specific fee requirements for the Osmosis protocol within the pool's fee structure.", "type": "object", @@ -584,6 +569,40 @@ }, "additionalProperties": false }, + "PoolType": { + "oneOf": [ + { + "type": "string", + "enum": [ + "constant_product" + ] + }, + { + "type": "object", + "required": [ + "stable_swap" + ], + "properties": { + "stable_swap": { + "type": "object", + "required": [ + "amp" + ], + "properties": { + "amp": { + "description": "The amount of amplification to perform on the constant product part of the swap formula.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] + }, "SwapOperation": { "oneOf": [ { diff --git a/contracts/liquidity_hub/pool-manager/schema/raw/query.json b/contracts/liquidity_hub/pool-manager/schema/raw/query.json index a74ad26dc..f8f2f798c 100644 --- a/contracts/liquidity_hub/pool-manager/schema/raw/query.json +++ b/contracts/liquidity_hub/pool-manager/schema/raw/query.json @@ -27,13 +27,13 @@ "type": "object", "required": [ "denom", - "pair_identifier" + "pool_identifier" ], "properties": { "denom": { "type": "string" }, - "pair_identifier": { + "pool_identifier": { "type": "string" } }, @@ -53,13 +53,13 @@ "type": "object", "required": [ "offer_asset", - "pair_identifier" + "pool_identifier" ], "properties": { "offer_asset": { "$ref": "#/definitions/Coin" }, - "pair_identifier": { + "pool_identifier": { "type": "string" } }, @@ -80,7 +80,7 @@ "required": [ "ask_asset", "offer_asset", - "pair_identifier" + "pool_identifier" ], "properties": { "ask_asset": { @@ -89,7 +89,7 @@ "offer_asset": { "$ref": "#/definitions/Coin" }, - "pair_identifier": { + "pool_identifier": { "type": "string" } }, @@ -199,16 +199,16 @@ { "type": "object", "required": [ - "pair" + "pool" ], "properties": { - "pair": { + "pool": { "type": "object", "required": [ - "pair_identifier" + "pool_identifier" ], "properties": { - "pair_identifier": { + "pool_identifier": { "type": "string" } }, diff --git a/contracts/liquidity_hub/pool-manager/schema/raw/response_to_asset_decimals.json b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_asset_decimals.json index a64999bd1..4cb4ceab1 100644 --- a/contracts/liquidity_hub/pool-manager/schema/raw/response_to_asset_decimals.json +++ b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_asset_decimals.json @@ -6,7 +6,7 @@ "required": [ "decimals", "denom", - "pair_identifier" + "pool_identifier" ], "properties": { "decimals": { @@ -16,11 +16,11 @@ "minimum": 0.0 }, "denom": { - "description": "The queried denom in the given pair_identifier.", + "description": "The queried denom in the given pool_identifier.", "type": "string" }, - "pair_identifier": { - "description": "The pair identifier to do the query for.", + "pool_identifier": { + "description": "The pool identifier to do the query for.", "type": "string" } }, diff --git a/contracts/liquidity_hub/pool-manager/schema/raw/response_to_pool.json b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_pool.json new file mode 100644 index 000000000..9a3ce9fcb --- /dev/null +++ b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_pool.json @@ -0,0 +1,176 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "PoolInfoResponse", + "type": "object", + "required": [ + "pool_info", + "total_share" + ], + "properties": { + "pool_info": { + "$ref": "#/definitions/PoolInfo" + }, + "total_share": { + "$ref": "#/definitions/Coin" + } + }, + "additionalProperties": false, + "definitions": { + "Coin": { + "type": "object", + "required": [ + "amount", + "denom" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" + } + } + }, + "Decimal": { + "description": "A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0\n\nThe greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18)", + "type": "string" + }, + "Fee": { + "type": "object", + "required": [ + "share" + ], + "properties": { + "share": { + "$ref": "#/definitions/Decimal" + } + }, + "additionalProperties": false + }, + "PoolFee": { + "description": "Represents the fee structure for transactions within a pool.\n\n# Fields - `protocol_fee`: The fee percentage charged by the protocol on each transaction to support operational and developmental needs. - `swap_fee`: The fee percentage allocated to liquidity providers as a reward for supplying liquidity to the pool, incentivizing participation and ensuring pool health. - `burn_fee`: A fee percentage that is burned on each transaction, helping manage the token economy by reducing supply over time, potentially increasing token value. - `osmosis_fee` (optional): Specific to the Osmosis feature, this fee is charged on each transaction when the Osmosis feature is enabled, supporting specific ecosystem requirements. - `extra_fees`: A vector of custom fees allowing for extensible and adaptable fee structures to meet diverse and evolving needs. Validation ensures that the total of all fees does not exceed 100%, maintaining fairness and avoiding overcharging.\n\n# Features - `osmosis`: Enables the `osmosis_fee` field, integrating specific fee requirements for the Osmosis protocol within the pool's fee structure.", + "type": "object", + "required": [ + "burn_fee", + "extra_fees", + "protocol_fee", + "swap_fee" + ], + "properties": { + "burn_fee": { + "description": "Fee percentage that is burned on each transaction. Burning a portion of the transaction fee helps in reducing the overall token supply.", + "allOf": [ + { + "$ref": "#/definitions/Fee" + } + ] + }, + "extra_fees": { + "description": "A list of custom, additional fees that can be defined for specific use cases or additional functionalities. This vector enables the flexibility to introduce new fees without altering the core fee structure. Total of all fees, including custom ones, is validated to not exceed 100%, ensuring a balanced and fair fee distribution.", + "type": "array", + "items": { + "$ref": "#/definitions/Fee" + } + }, + "protocol_fee": { + "description": "Fee percentage charged on each transaction for the protocol's benefit.", + "allOf": [ + { + "$ref": "#/definitions/Fee" + } + ] + }, + "swap_fee": { + "description": "Fee percentage allocated to liquidity providers on each swap.", + "allOf": [ + { + "$ref": "#/definitions/Fee" + } + ] + } + }, + "additionalProperties": false + }, + "PoolInfo": { + "type": "object", + "required": [ + "asset_decimals", + "asset_denoms", + "assets", + "lp_denom", + "pool_fees", + "pool_type" + ], + "properties": { + "asset_decimals": { + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + }, + "asset_denoms": { + "type": "array", + "items": { + "type": "string" + } + }, + "assets": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "lp_denom": { + "type": "string" + }, + "pool_fees": { + "$ref": "#/definitions/PoolFee" + }, + "pool_type": { + "$ref": "#/definitions/PoolType" + } + }, + "additionalProperties": false + }, + "PoolType": { + "oneOf": [ + { + "type": "string", + "enum": [ + "constant_product" + ] + }, + { + "type": "object", + "required": [ + "stable_swap" + ], + "properties": { + "stable_swap": { + "type": "object", + "required": [ + "amp" + ], + "properties": { + "amp": { + "description": "The amount of amplification to perform on the constant product part of the swap formula.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + } + } +} diff --git a/contracts/liquidity_hub/pool-manager/src/contract.rs b/contracts/liquidity_hub/pool-manager/src/contract.rs index 4181ff255..fc3ae0bb2 100644 --- a/contracts/liquidity_hub/pool-manager/src/contract.rs +++ b/contracts/liquidity_hub/pool-manager/src/contract.rs @@ -1,15 +1,13 @@ use crate::error::ContractError; use crate::helpers::validate_asset_balance; -use crate::queries::{get_pair, get_swap_route, get_swap_route_creator, get_swap_routes}; -use crate::router::commands::{add_swap_routes, remove_swap_routes}; use crate::state::{ - Config, SingleSideLiquidityProvisionBuffer, CONFIG, PAIR_COUNTER, + Config, SingleSideLiquidityProvisionBuffer, CONFIG, POOL_COUNTER, SINGLE_SIDE_LIQUIDITY_PROVISION_BUFFER, }; use crate::{liquidity, manager, queries, router, swap}; #[cfg(not(feature = "library"))] use cosmwasm_std::{ - entry_point, to_json_binary, Addr, Api, Binary, Deps, DepsMut, Env, MessageInfo, Response, + entry_point, to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, }; use cosmwasm_std::{wasm_execute, Reply, StdError}; use cw2::set_contract_version; @@ -44,7 +42,7 @@ pub fn instantiate( }; CONFIG.save(deps.storage, &config)?; // initialize vault counter - PAIR_COUNTER.save(deps.storage, &0u64)?; + POOL_COUNTER.save(deps.storage, &0u64)?; cw_ownable::initialize_owner(deps.storage, deps.api, Some(info.sender.as_str()))?; Ok(Response::default()) @@ -74,7 +72,7 @@ pub fn reply(deps: DepsMut, env: Env, msg: Reply) -> Result Result { match msg { - ExecuteMsg::CreatePair { + ExecuteMsg::CreatePool { asset_denoms, asset_decimals, pool_fees, - pair_type, - pair_identifier, - } => manager::commands::create_pair( + pool_type, + pool_identifier, + } => manager::commands::create_pool( deps, env, info, asset_denoms, asset_decimals, pool_fees, - pair_type, - pair_identifier, + pool_type, + pool_identifier, ), ExecuteMsg::ProvideLiquidity { max_spread, slippage_tolerance, receiver, - pair_identifier, + pool_identifier, unlocking_duration, lock_position_identifier, } => liquidity::commands::provide_liquidity( @@ -123,7 +121,7 @@ pub fn execute( slippage_tolerance, max_spread, receiver, - pair_identifier, + pool_identifier, unlocking_duration, lock_position_identifier, ), @@ -132,20 +130,19 @@ pub fn execute( belief_price, max_spread, receiver, - pair_identifier, + pool_identifier, } => swap::commands::swap( deps, - env, info.clone(), info.sender, ask_asset_denom, belief_price, max_spread, receiver, - pair_identifier, + pool_identifier, ), - ExecuteMsg::WithdrawLiquidity { pair_identifier } => { - liquidity::commands::withdraw_liquidity(deps, env, info, pair_identifier) + ExecuteMsg::WithdrawLiquidity { pool_identifier } => { + liquidity::commands::withdraw_liquidity(deps, env, info, pool_identifier) } ExecuteMsg::UpdateOwnership(action) => { Ok( @@ -161,24 +158,21 @@ pub fn execute( ExecuteMsg::ExecuteSwapOperations { operations, minimum_receive, - to, + receiver, max_spread, - } => { - let api = deps.api; - router::commands::execute_swap_operations( - deps, - info, - operations, - minimum_receive, - optional_addr_validate(api, to)?, - max_spread, - ) - } + } => router::commands::execute_swap_operations( + deps, + info, + operations, + minimum_receive, + receiver, + max_spread, + ), ExecuteMsg::AddSwapRoutes { swap_routes } => { - add_swap_routes(deps, info.sender, swap_routes) + router::commands::add_swap_routes(deps, info.sender, swap_routes) } ExecuteMsg::RemoveSwapRoutes { swap_routes } => { - remove_swap_routes(deps, info.sender, swap_routes) + router::commands::remove_swap_routes(deps, info.sender, swap_routes) } ExecuteMsg::UpdateConfig { whale_lair_addr, @@ -194,52 +188,36 @@ pub fn execute( } } -//todo remove. solution: just embed the content of the function where it's used -// Came from router can probably go -#[allow(dead_code)] -fn optional_addr_validate( - api: &dyn Api, - addr: Option, -) -> Result, ContractError> { - let addr = if let Some(addr) = addr { - Some(api.addr_validate(&addr)?) - } else { - None - }; - - Ok(addr) -} - #[cfg_attr(not(feature = "library"), entry_point)] pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result { match msg { QueryMsg::Config {} => Ok(to_json_binary(&queries::query_config(deps)?)?), QueryMsg::AssetDecimals { - pair_identifier, + pool_identifier, denom, } => Ok(to_json_binary(&queries::query_asset_decimals( deps, - pair_identifier, + pool_identifier, denom, )?)?), QueryMsg::Simulation { offer_asset, - pair_identifier, + pool_identifier, } => Ok(to_json_binary(&queries::query_simulation( deps, offer_asset, - pair_identifier, + pool_identifier, )?)?), QueryMsg::ReverseSimulation { ask_asset, offer_asset, - pair_identifier, + pool_identifier, } => Ok(to_json_binary(&queries::query_reverse_simulation( deps, env, ask_asset, offer_asset, - pair_identifier, + pool_identifier, )?)?), QueryMsg::SimulateSwapOperations { offer_amount, @@ -258,20 +236,20 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result Ok(to_json_binary(&get_swap_route( + } => Ok(to_json_binary(&queries::get_swap_route( deps, offer_asset_denom, ask_asset_denom, )?)?), - QueryMsg::SwapRoutes {} => Ok(to_json_binary(&get_swap_routes(deps)?)?), + QueryMsg::SwapRoutes {} => Ok(to_json_binary(&queries::get_swap_routes(deps)?)?), QueryMsg::Ownership {} => Ok(to_json_binary(&cw_ownable::get_ownership(deps.storage)?)?), - QueryMsg::Pair { pair_identifier } => { - Ok(to_json_binary(&get_pair(deps, pair_identifier)?)?) + QueryMsg::Pool { pool_identifier } => { + Ok(to_json_binary(&queries::get_pool(deps, pool_identifier)?)?) } QueryMsg::SwapRouteCreator { offer_asset_denom, ask_asset_denom, - } => Ok(to_json_binary(&get_swap_route_creator( + } => Ok(to_json_binary(&queries::get_swap_route_creator( deps, offer_asset_denom, ask_asset_denom, @@ -300,6 +278,3 @@ pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result Result { @@ -152,7 +152,7 @@ pub fn compute_swap( let offer_amount: Uint256 = offer_amount.into(); match swap_type { - PairType::ConstantProduct => { + PoolType::ConstantProduct => { // offer => ask // ask_amount = (ask_pool * offer_amount / (offer_pool + offer_amount)) - swap_fee - protocol_fee - burn_fee let return_amount: Uint256 = Uint256::one() @@ -227,7 +227,7 @@ pub fn compute_swap( }) } } - PairType::StableSwap { amp } => { + PoolType::StableSwap { amp } => { let offer_pool = Decimal256::decimal_with_precision(offer_pool, offer_precision)?; let ask_pool = Decimal256::decimal_with_precision(ask_pool, ask_precision)?; let offer_amount = Decimal256::decimal_with_precision(offer_amount, offer_precision)?; @@ -423,7 +423,7 @@ pub fn assert_slippage_tolerance( slippage_tolerance: &Option, deposits: &[Uint128; 2], pools: &[Coin; 2], - pair_type: PairType, + pool_type: PoolType, amount: Uint128, pool_token_supply: Uint128, ) -> Result<(), ContractError> { @@ -438,8 +438,8 @@ pub fn assert_slippage_tolerance( let pools: [Uint256; 2] = [pools[0].amount.into(), pools[1].amount.into()]; // Ensure each prices are not dropped as much as slippage tolerance rate - match pair_type { - PairType::StableSwap { .. } => { + match pool_type { + PoolType::StableSwap { .. } => { let pools_total = pools[0].checked_add(pools[1])?; let deposits_total = deposits[0].checked_add(deposits[1])?; @@ -453,7 +453,7 @@ pub fn assert_slippage_tolerance( return Err(ContractError::MaxSlippageAssertion); } } - PairType::ConstantProduct => { + PoolType::ConstantProduct => { if Decimal256::from_ratio(deposits[0], deposits[1]) * one_minus_slippage_tolerance > Decimal256::from_ratio(pools[0], pools[1]) || Decimal256::from_ratio(deposits[1], deposits[0]) @@ -492,12 +492,12 @@ pub fn instantiate_fees( storage: &mut dyn Storage, asset_info_0: AssetInfo, asset_info_1: AssetInfo, - pair_key: &Vec, - fee_storage_item: cw_storage_plus::Map<'static, &'static [u8], std::vec::Vec>, + pool_key: &Vec, + fee_storage_item: cw_storage_plus::Map<'static, &'static [u8], Vec>, ) -> StdResult<()> { fee_storage_item.save( storage, - pair_key, + pool_key, &vec![ Asset { info: asset_info_0, diff --git a/contracts/liquidity_hub/pool-manager/src/liquidity/commands.rs b/contracts/liquidity_hub/pool-manager/src/liquidity/commands.rs index d7b4392aa..ceebf4789 100644 --- a/contracts/liquidity_hub/pool-manager/src/liquidity/commands.rs +++ b/contracts/liquidity_hub/pool-manager/src/liquidity/commands.rs @@ -6,8 +6,7 @@ use cosmwasm_std::{Decimal, OverflowError, Uint128}; use white_whale_std::coin::aggregate_coins; use white_whale_std::common::validate_addr_or_default; -use white_whale_std::pool_manager::ExecuteMsg; -use white_whale_std::pool_network::asset::PairType; +use white_whale_std::pool_manager::{ExecuteMsg, PoolType}; use white_whale_std::pool_network::{ asset::{get_total_share, MINIMUM_LIQUIDITY_AMOUNT}, U256, @@ -15,13 +14,13 @@ use white_whale_std::pool_network::{ use crate::{ helpers::{self}, - state::get_pair_by_identifier, + state::get_pool_by_identifier, }; use crate::{ - state::{CONFIG, PAIRS}, + state::{CONFIG, POOLS}, ContractError, }; -// After writing create_pair I see this can get quite verbose so attempting to +// After writing create_pool I see this can get quite verbose so attempting to // break it down into smaller modules which house some things like swap, liquidity etc use crate::contract::SINGLE_SIDE_LIQUIDITY_PROVISION_REPLY_ID; use crate::helpers::aggregate_outgoing_fees; @@ -41,7 +40,7 @@ pub fn provide_liquidity( slippage_tolerance: Option, max_spread: Option, receiver: Option, - pair_identifier: String, + pool_identifier: String, unlocking_duration: Option, lock_position_identifier: Option, ) -> Result { @@ -52,10 +51,10 @@ pub fn provide_liquidity( ContractError::OperationDisabled("provide_liquidity".to_string()) ); - // Get the pair by the pair_identifier - let mut pair = get_pair_by_identifier(&deps.as_ref(), &pair_identifier)?; + // Get the pool by the pool_identifier + let mut pool = get_pool_by_identifier(&deps.as_ref(), &pool_identifier)?; - let mut pool_assets = pair.assets.clone(); + let mut pool_assets = pool.assets.clone(); let deposits = aggregate_coins(info.funds.clone())?; ensure!(!deposits.is_empty(), ContractError::EmptyAssets); @@ -90,7 +89,7 @@ pub fn provide_liquidity( }; let swap_simulation_response = - query_simulation(deps.as_ref(), swap_half.clone(), pair_identifier.clone())?; + query_simulation(deps.as_ref(), swap_half.clone(), pool_identifier.clone())?; let ask_denom = pool_assets .iter() @@ -140,7 +139,7 @@ pub fn provide_liquidity( liquidity_provision_data: LiquidityProvisionData { max_spread, slippage_tolerance, - pair_identifier: pair_identifier.clone(), + pool_identifier: pool_identifier.clone(), unlocking_duration, lock_position_identifier, }, @@ -156,7 +155,7 @@ pub fn provide_liquidity( belief_price: None, max_spread, receiver: None, - pair_identifier, + pool_identifier, }, vec![swap_half], )?, @@ -186,13 +185,13 @@ pub fn provide_liquidity( let mut messages: Vec = vec![]; - let liquidity_token = pair.lp_denom.clone(); + let liquidity_token = pool.lp_denom.clone(); // Compute share and other logic based on the number of assets let total_share = get_total_share(&deps.as_ref(), liquidity_token.clone())?; - let share = match &pair.pair_type { - PairType::ConstantProduct => { + let share = match &pool.pool_type { + PoolType::ConstantProduct => { if total_share == Uint128::zero() { // Make sure at least MINIMUM_LIQUIDITY_AMOUNT is deposited to mitigate the risk of the first // depositor preventing small liquidity providers from joining the pool @@ -251,7 +250,7 @@ pub fn provide_liquidity( &slippage_tolerance, &deposits_as, &pools_as, - pair.pair_type.clone(), + pool.pool_type.clone(), amount, total_share, )?; @@ -259,7 +258,7 @@ pub fn provide_liquidity( amount } } - PairType::StableSwap { amp: _ } => { + PoolType::StableSwap { amp: _ } => { // TODO: Handle stableswap Uint128::one() @@ -301,9 +300,9 @@ pub fn provide_liquidity( )?); } - pair.assets = pool_assets.clone(); + pool.assets = pool_assets.clone(); - PAIRS.save(deps.storage, &pair_identifier, &pair)?; + POOLS.save(deps.storage, &pool_identifier, &pool)?; Ok(Response::new().add_messages(messages).add_attributes(vec![ ("action", "provide_liquidity"), @@ -328,7 +327,7 @@ pub fn withdraw_liquidity( deps: DepsMut, env: Env, info: MessageInfo, - pair_identifier: String, + pool_identifier: String, ) -> Result { let config = CONFIG.load(deps.storage)?; // check if the withdraw feature is enabled @@ -338,9 +337,9 @@ pub fn withdraw_liquidity( )); } - // Get the pair by the pair_identifier - let mut pair = get_pair_by_identifier(&deps.as_ref(), &pair_identifier)?; - let liquidity_token = pair.lp_denom.clone(); + // Get the pool by the pool_identifier + let mut pool = get_pool_by_identifier(&deps.as_ref(), &pool_identifier)?; + let liquidity_token = pool.lp_denom.clone(); // Verify that the LP token was sent let amount = cw_utils::must_pay(&info, &liquidity_token)?; @@ -354,7 +353,7 @@ pub fn withdraw_liquidity( ensure!(share_ratio <= Decimal::one(), ContractError::InvalidLpShare); // Use the ratio to calculate the amount of each pool asset to refund - let refund_assets: Vec = pair + let refund_assets: Vec = pool .assets .iter() .map(|pool_asset| { @@ -373,12 +372,12 @@ pub fn withdraw_liquidity( amount: refund_assets.clone(), })); - // Deduct balances on pair_info by the amount of each refund asset - for (i, pool_asset) in pair.assets.iter_mut().enumerate() { + // Deduct balances on pool_info by the amount of each refund asset + for (i, pool_asset) in pool.assets.iter_mut().enumerate() { pool_asset.amount = pool_asset.amount.checked_sub(refund_assets[i].amount)?; } - PAIRS.save(deps.storage, &pair_identifier, &pair)?; + POOLS.save(deps.storage, &pool_identifier, &pool)?; // Burn the LP tokens messages.push(white_whale_std::lp_common::burn_lp_asset_msg( diff --git a/contracts/liquidity_hub/pool-manager/src/manager/commands.rs b/contracts/liquidity_hub/pool-manager/src/manager/commands.rs index e3c1ec7a6..447dd4d86 100644 --- a/contracts/liquidity_hub/pool-manager/src/manager/commands.rs +++ b/contracts/liquidity_hub/pool-manager/src/manager/commands.rs @@ -1,34 +1,34 @@ use cosmwasm_std::{ attr, Attribute, Coin, CosmosMsg, DepsMut, Env, MessageInfo, Response, Uint128, }; -use white_whale_std::{fee::PoolFee, pool_network::asset::PairType, whale_lair::fill_rewards_msg}; +use white_whale_std::{fee::PoolFee, whale_lair::fill_rewards_msg}; -use crate::state::{get_pair_by_identifier, PAIR_COUNTER}; +use crate::state::{get_pool_by_identifier, POOL_COUNTER}; use crate::{ - state::{Config, CONFIG, PAIRS}, + state::{Config, CONFIG, POOLS}, ContractError, }; use white_whale_std::lp_common::LP_SYMBOL; -use white_whale_std::pool_manager::PairInfo; +use white_whale_std::pool_manager::{PoolInfo, PoolType}; pub const MAX_ASSETS_PER_POOL: usize = 4; -/// Creates a liquidity pool pair with 2, 3, or N assets. The function dynamically handles different numbers of assets, -/// allowing for the creation of pairs with varying configurations. The maximum number of assets per pool is defined by +/// Creates a pool with 2, 3, or N assets. The function dynamically handles different numbers of assets, +/// allowing for the creation of pools with varying configurations. The maximum number of assets per pool is defined by /// the constant `MAX_ASSETS_PER_POOL`. /// /// # Example /// /// ```rust /// # use cosmwasm_std::{DepsMut, Decimal, Env, MessageInfo, Response, CosmosMsg, WasmMsg, to_json_binary}; -/// # use white_whale_std::pool_network::{asset::{PairType}}; /// # use white_whale_std::fee::PoolFee; /// # use white_whale_std::fee::Fee; /// # use pool_manager::error::ContractError; /// # use pool_manager::manager::commands::MAX_ASSETS_PER_POOL; -/// # use pool_manager::manager::commands::create_pair; +/// # use pool_manager::manager::commands::create_pool; /// # use std::convert::TryInto; +/// # use white_whale_std::pool_manager::PoolType; /// # /// # fn example(deps: DepsMut, env: Env, info: MessageInfo) -> Result { /// let asset_infos = vec![ @@ -66,24 +66,24 @@ pub const MAX_ASSETS_PER_POOL: usize = 4; /// }, /// extra_fees: vec![], /// }; -/// let pair_type = PairType::ConstantProduct; +/// let pool_type = PoolType::ConstantProduct; /// let token_factory_lp = false; /// -/// let response = create_pair(deps, env, info, asset_infos, asset_decimals, pool_fees, pair_type, None)?; +/// let response = create_pool(deps, env, info, asset_infos, asset_decimals, pool_fees, pool_type, None)?; /// # Ok(response) /// # } /// ``` #[allow(unreachable_code)] #[allow(clippy::too_many_arguments)] -pub fn create_pair( +pub fn create_pool( deps: DepsMut, env: Env, info: MessageInfo, asset_denoms: Vec, asset_decimals: Vec, pool_fees: PoolFee, - pair_type: PairType, - pair_identifier: Option, + pool_type: PoolType, + pool_identifier: Option, ) -> Result { // Load config for pool creation fee let config: Config = CONFIG.load(deps.storage)?; @@ -93,20 +93,20 @@ pub fn create_pair( // verify fee payment let amount = cw_utils::must_pay(&info, &config.pool_creation_fee.denom)?; if amount != config.pool_creation_fee.amount { - return Err(ContractError::InvalidPairCreationFee { + return Err(ContractError::InvalidPoolCreationFee { amount, expected: config.pool_creation_fee.amount, }); } } - // Prepare the sending of pair creation fee + // Prepare the sending of pool creation fee let mut messages: Vec = vec![]; // send pool creation fee to whale lair let creation_fee = vec![config.pool_creation_fee]; - // send pair creation fee to whale lair i.e the new fee_collector + // send pool creation fee to whale lair i.e the new fee_collector messages.push(fill_rewards_msg( config.bonding_manager_addr.into_string(), creation_fee, @@ -123,14 +123,14 @@ pub fn create_pair( // Verify pool fees pool_fees.is_valid()?; - let pair_id = PAIR_COUNTER.load(deps.storage)?; + let pool_id = POOL_COUNTER.load(deps.storage)?; // if no identifier is provided, use the pool counter (id) as identifier - let identifier = pair_identifier.unwrap_or(pair_id.to_string()); + let identifier = pool_identifier.unwrap_or(pool_id.to_string()); // check if there is an existing pool with the given identifier - let pair = get_pair_by_identifier(&deps.as_ref(), &identifier); - if pair.is_ok() { - return Err(ContractError::PairExists { + let pool = get_pool_by_identifier(&deps.as_ref(), &identifier); + if pool.is_ok() { + return Err(ContractError::PoolExists { asset_infos: asset_denoms .iter() .map(|i| i.to_string()) @@ -140,8 +140,8 @@ pub fn create_pair( }); } - // prepare labels for creating the pair token with a meaningful name - let pair_label = asset_denoms.join("-"); + // prepare labels for creating the pool token with a meaningful name + let pool_label = asset_denoms.join("-"); let mut attributes = Vec::::new(); @@ -154,16 +154,16 @@ pub fn create_pair( }) .collect::>(); - let lp_symbol = format!("{pair_label}.pool.{identifier}.{LP_SYMBOL}"); + let lp_symbol = format!("{pool_label}.pool.{identifier}.{LP_SYMBOL}"); let lp_asset = format!("{}/{}/{}", "factory", env.contract.address, lp_symbol); #[allow(clippy::redundant_clone)] - PAIRS.save( + POOLS.save( deps.storage, &identifier, - &PairInfo { + &PoolInfo { asset_denoms, - pair_type: pair_type.clone(), + pool_type: pool_type.clone(), lp_denom: lp_asset.clone(), asset_decimals, pool_fees, @@ -187,17 +187,17 @@ pub fn create_pair( lp_symbol, )); - // increase pair counter - PAIR_COUNTER.update(deps.storage, |mut counter| -> Result<_, ContractError> { + // increase pool counter + POOL_COUNTER.update(deps.storage, |mut counter| -> Result<_, ContractError> { counter += 1; Ok(counter) })?; - attributes.push(attr("action", "create_pair")); - attributes.push(attr("pair", &pair_label)); - attributes.push(attr("pair_label", pair_label.as_str())); - attributes.push(attr("pair_type", pair_type.get_label())); - attributes.push(attr("pair_identifier", identifier.as_str())); + attributes.push(attr("action", "create_pool")); + attributes.push(attr("pool", &pool_label)); + attributes.push(attr("pool_label", pool_label.as_str())); + attributes.push(attr("pool_type", pool_type.get_label())); + attributes.push(attr("pool_identifier", identifier.as_str())); Ok(Response::new() .add_attributes(attributes) diff --git a/contracts/liquidity_hub/pool-manager/src/queries.rs b/contracts/liquidity_hub/pool-manager/src/queries.rs index fa73b4343..c4227798d 100644 --- a/contracts/liquidity_hub/pool-manager/src/queries.rs +++ b/contracts/liquidity_hub/pool-manager/src/queries.rs @@ -3,16 +3,15 @@ use std::cmp::Ordering; use cosmwasm_std::{coin, Coin, Decimal256, Deps, Env, Fraction, Order, StdResult, Uint128}; use white_whale_std::pool_manager::{ - AssetDecimalsResponse, Config, PairInfoResponse, ReverseSimulationResponse, + AssetDecimalsResponse, Config, PoolInfoResponse, PoolType, ReverseSimulationResponse, SimulateSwapOperationsResponse, SimulationResponse, SwapOperation, SwapRoute, SwapRouteCreatorResponse, SwapRouteResponse, SwapRoutesResponse, }; -use white_whale_std::pool_network::asset::PairType; -use crate::state::{CONFIG, PAIRS}; +use crate::state::{CONFIG, POOLS}; use crate::{ helpers::{self, calculate_stableswap_y, StableSwapDirection}, - state::get_pair_by_identifier, + state::get_pool_by_identifier, ContractError, }; use crate::{math::Decimal256Helper, state::SWAP_ROUTES}; @@ -25,20 +24,20 @@ pub fn query_config(deps: Deps) -> Result { /// Query the native asset decimals pub fn query_asset_decimals( deps: Deps, - pair_identifier: String, + pool_identifier: String, denom: String, ) -> Result { - let pair_info = get_pair_by_identifier(&deps, &pair_identifier)?; - let decimal_index = pair_info + let pool_info = get_pool_by_identifier(&deps, &pool_identifier)?; + let decimal_index = pool_info .asset_denoms .iter() .position(|d| d.clone() == denom) .ok_or(ContractError::AssetMismatch)?; Ok(AssetDecimalsResponse { - pair_identifier, + pool_identifier, denom, - decimals: pair_info.asset_decimals[decimal_index], + decimals: pool_info.asset_decimals[decimal_index], }) } @@ -46,18 +45,18 @@ pub fn query_asset_decimals( pub fn query_simulation( deps: Deps, offer_asset: Coin, - pair_identifier: String, + pool_identifier: String, ) -> Result { - let pair_info = get_pair_by_identifier(&deps, &pair_identifier)?; - let pools = pair_info.assets.clone(); + let pool_info = get_pool_by_identifier(&deps, &pool_identifier)?; + let pools = pool_info.assets.clone(); // determine what's the offer and ask pool based on the offer_asset let offer_pool: Coin; let ask_pool: Coin; let offer_decimal: u8; let ask_decimal: u8; - let decimals = pair_info.asset_decimals.clone(); - // We now have the pools and pair info; we can now calculate the swap + let decimals = pool_info.asset_decimals.clone(); + // We now have the pools and pool info; we can now calculate the swap // Verify the pool if offer_asset.denom == pools[0].denom { offer_pool = pools[0].clone(); @@ -74,14 +73,14 @@ pub fn query_simulation( return Err(ContractError::AssetMismatch); } - let pool_fees = pair_info.pool_fees; + let pool_fees = pool_info.pool_fees; let swap_computation = helpers::compute_swap( offer_pool.amount, ask_pool.amount, offer_asset.amount, pool_fees, - &pair_info.pair_type, + &pool_info.pool_type, offer_decimal, ask_decimal, )?; @@ -117,20 +116,20 @@ pub fn query_reverse_simulation( _env: Env, ask_asset: Coin, _offer_asset: Coin, - pair_identifier: String, + pool_identifier: String, ) -> Result { - let pair_info = get_pair_by_identifier(&deps, &pair_identifier)?; - let pools = pair_info.assets.clone(); + let pool_info = get_pool_by_identifier(&deps, &pool_identifier)?; + let pools = pool_info.assets.clone(); - let decimals = pair_info.asset_decimals.clone(); + let decimals = pool_info.asset_decimals.clone(); let offer_pool: Coin = pools[0].clone(); let offer_decimal = decimals[0]; let ask_pool: Coin = pools[1].clone(); let ask_decimal = decimals[1]; - let pool_fees = pair_info.pool_fees; + let pool_fees = pool_info.pool_fees; - match pair_info.pair_type { - PairType::ConstantProduct => { + match pool_info.pool_type { + PoolType::ConstantProduct => { let offer_amount_computation = helpers::compute_offer_amount( offer_pool.amount, ask_pool.amount, @@ -161,7 +160,7 @@ pub fn query_reverse_simulation( }) } } - PairType::StableSwap { amp } => { + PoolType::StableSwap { amp } => { let offer_pool = Decimal256::decimal_with_precision(offer_pool.amount, offer_decimal)?; let ask_pool = Decimal256::decimal_with_precision(ask_pool.amount, ask_decimal)?; @@ -241,7 +240,7 @@ pub fn query_reverse_simulation( // Router related queries, swap routes and SwapOperations // get_swap_routes which only takes deps: Deps as input -// the function will read from SWAP_ROUTES and return all swpa routes in a vec +// the function will read from SWAP_ROUTES and return all swap routes in a vec pub fn get_swap_routes(deps: Deps) -> Result { let swap_routes: Vec = SWAP_ROUTES .range(deps.storage, None, None, Order::Ascending) @@ -305,13 +304,13 @@ pub fn get_swap_route_creator( }) } -/// Gets the pair info for a given pair identifier. Returns a [PairInfoResponse]. -pub fn get_pair(deps: Deps, pair_identifier: String) -> Result { - let pair = PAIRS.load(deps.storage, &pair_identifier)?; - let total_share = deps.querier.query_supply(pair.lp_denom)?; +/// Gets the pool info for a given pool identifier. Returns a [PoolInfoResponse]. +pub fn get_pool(deps: Deps, pool_identifier: String) -> Result { + let pool = POOLS.load(deps.storage, &pool_identifier)?; + let total_share = deps.querier.query_supply(pool.lp_denom)?; - Ok(PairInfoResponse { - pair_info: PAIRS.load(deps.storage, &pair_identifier)?, + Ok(PoolInfoResponse { + pool_info: POOLS.load(deps.storage, &pool_identifier)?, total_share, }) } diff --git a/contracts/liquidity_hub/pool-manager/src/router/commands.rs b/contracts/liquidity_hub/pool-manager/src/router/commands.rs index be14d3b4e..5036b4db3 100644 --- a/contracts/liquidity_hub/pool-manager/src/router/commands.rs +++ b/contracts/liquidity_hub/pool-manager/src/router/commands.rs @@ -1,7 +1,8 @@ use cosmwasm_std::{ - attr, coin, wasm_execute, Addr, BankMsg, Coin, CosmosMsg, Decimal, DepsMut, MessageInfo, - Response, Uint128, + attr, coin, ensure, wasm_execute, Addr, BankMsg, Coin, CosmosMsg, Decimal, DepsMut, + MessageInfo, Response, Uint128, }; +use white_whale_std::common::validate_addr_or_default; use white_whale_std::pool_manager::{SwapOperation, SwapRoute}; use white_whale_std::whale_lair; @@ -40,14 +41,15 @@ pub fn execute_swap_operations( info: MessageInfo, operations: Vec, minimum_receive: Option, - to: Option, + receiver: Option, max_spread: Option, ) -> Result { let config = CONFIG.load(deps.storage)?; // check if the swap feature is enabled - if !config.feature_toggle.swaps_enabled { - return Err(ContractError::OperationDisabled("swap".to_string())); - } + ensure!( + config.feature_toggle.swaps_enabled, + ContractError::OperationDisabled("swap".to_string()) + ); // ensure that there was at least one operation // and retrieve the output token info @@ -69,7 +71,8 @@ pub fn execute_swap_operations( assert_operations(operations.clone())?; // we return the output to the sender if no alternative recipient was specified. - let to = to.unwrap_or(info.sender.clone()); + let receiver = + validate_addr_or_default(&deps.as_ref(), receiver, info.sender.clone()).to_string(); // perform each swap operation // we start off with the initial funds @@ -146,17 +149,17 @@ pub fn execute_swap_operations( // send output to recipient Ok(Response::new() .add_message(BankMsg::Send { - to_address: to.to_string(), + to_address: receiver.clone(), amount: vec![coin(receiver_balance.u128(), target_asset_denom.clone())], }) .add_messages(fee_messages) .add_attributes(vec![ - attr("action", "execute_swap_operations"), - attr("sender", info.sender.as_str()), - attr("receiver", to.as_str()), + attr("action", "execute_swap_operations".to_string()), + attr("sender", info.sender.to_string()), + attr("receiver", receiver), attr("offer_info", offer_asset.denom), - attr("offer_amount", offer_asset.amount), - attr("return_denom", &target_asset_denom), + attr("offer_amount", offer_asset.amount.to_string()), + attr("return_denom", target_asset_denom), attr("return_amount", receiver_balance.to_string()), ]) .add_attributes(swap_attributes)) diff --git a/contracts/liquidity_hub/pool-manager/src/state.rs b/contracts/liquidity_hub/pool-manager/src/state.rs index 458b257aa..7422f803d 100644 --- a/contracts/liquidity_hub/pool-manager/src/state.rs +++ b/contracts/liquidity_hub/pool-manager/src/state.rs @@ -3,7 +3,7 @@ use cosmwasm_std::{Coin, Decimal, Deps}; use cw_storage_plus::{Index, IndexList, IndexedMap, Item, Map, UniqueIndex}; pub use white_whale_std::pool_manager::Config; -use white_whale_std::pool_manager::{PairInfo, SwapOperation}; +use white_whale_std::pool_manager::{PoolInfo, SwapOperation}; use crate::ContractError; @@ -33,7 +33,7 @@ pub struct SingleSideLiquidityProvisionBuffer { /// single asset. #[cw_serde] pub struct LiquidityProvisionData { - /// The maximum allowable spread between the bid and ask prices for the pair. + /// The maximum allowable spread between the bid and ask prices for the pool. /// When provided, if the spread exceeds this value, the liquidity provision will not be /// executed. pub max_spread: Option, @@ -41,8 +41,8 @@ pub struct LiquidityProvisionData { /// When provided, if the slippage exceeds this value, the liquidity provision will not be /// executed. pub slippage_tolerance: Option, - /// The identifier for the pair to provide liquidity for. - pub pair_identifier: String, + /// The identifier for the pool to provide liquidity for. + pub pool_identifier: String, /// The amount of time in seconds to unlock tokens if taking part on the incentives. If not passed, /// the tokens will not be locked and the LP tokens will be returned to the user. pub unlocking_duration: Option, @@ -53,32 +53,32 @@ pub struct LiquidityProvisionData { pub const SINGLE_SIDE_LIQUIDITY_PROVISION_BUFFER: Item = Item::new("single_side_liquidity_provision_buffer"); -pub const PAIRS: IndexedMap<&str, PairInfo, PairIndexes> = IndexedMap::new( - "pairs", - PairIndexes { - lp_asset: UniqueIndex::new(|v| v.lp_denom.to_string(), "pairs__lp_asset"), +pub const POOLS: IndexedMap<&str, PoolInfo, PoolIndexes> = IndexedMap::new( + "pools", + PoolIndexes { + lp_asset: UniqueIndex::new(|v| v.lp_denom.to_string(), "pools__lp_asset"), }, ); -pub struct PairIndexes<'a> { - pub lp_asset: UniqueIndex<'a, String, PairInfo, String>, +pub struct PoolIndexes<'a> { + pub lp_asset: UniqueIndex<'a, String, PoolInfo, String>, } -impl<'a> IndexList for PairIndexes<'a> { - fn get_indexes(&'_ self) -> Box> + '_> { - let v: Vec<&dyn Index> = vec![&self.lp_asset]; +impl<'a> IndexList for PoolIndexes<'a> { + fn get_indexes(&'_ self) -> Box> + '_> { + let v: Vec<&dyn Index> = vec![&self.lp_asset]; Box::new(v.into_iter()) } } -/// Gets the pair given its identifier -pub fn get_pair_by_identifier( +/// Gets the pool given its identifier +pub fn get_pool_by_identifier( deps: &Deps, - pair_identifier: &str, -) -> Result { - PAIRS - .may_load(deps.storage, pair_identifier)? - .ok_or(ContractError::UnExistingPair) + pool_identifier: &str, +) -> Result { + POOLS + .may_load(deps.storage, pool_identifier)? + .ok_or(ContractError::UnExistingPool) } /// Swap routes are used to establish defined routes for a given fee @@ -94,4 +94,4 @@ pub struct SwapOperations { pub const SWAP_ROUTES: Map<(&str, &str), SwapOperations> = Map::new("swap_routes"); pub const CONFIG: Item = Item::new("config"); -pub const PAIR_COUNTER: Item = Item::new("vault_count"); +pub const POOL_COUNTER: Item = Item::new("pool_count"); diff --git a/contracts/liquidity_hub/pool-manager/src/swap/commands.rs b/contracts/liquidity_hub/pool-manager/src/swap/commands.rs index d00afa10f..0f16e1c60 100644 --- a/contracts/liquidity_hub/pool-manager/src/swap/commands.rs +++ b/contracts/liquidity_hub/pool-manager/src/swap/commands.rs @@ -1,11 +1,11 @@ use crate::{state::CONFIG, ContractError}; use cosmwasm_std::{ - ensure, wasm_execute, Addr, BankMsg, CosmosMsg, DepsMut, Env, MessageInfo, Response, + ensure, wasm_execute, Addr, BankMsg, CosmosMsg, DepsMut, MessageInfo, Response, }; pub const MAX_ASSETS_PER_POOL: usize = 4; -use crate::state::get_pair_by_identifier; +use crate::state::get_pool_by_identifier; use cosmwasm_std::Decimal; use white_whale_std::common::validate_addr_or_default; use white_whale_std::whale_lair; @@ -15,14 +15,13 @@ use super::perform_swap::perform_swap; #[allow(clippy::too_many_arguments)] pub fn swap( mut deps: DepsMut, - _env: Env, info: MessageInfo, sender: Addr, ask_asset_denom: String, belief_price: Option, max_spread: Option, receiver: Option, - pair_identifier: String, + pool_identifier: String, ) -> Result { let config = CONFIG.load(deps.storage)?; // check if the swap feature is enabled @@ -34,11 +33,11 @@ pub fn swap( let offer_asset = cw_utils::one_coin(&info)?; // verify that the assets sent match the ones from the pool - let pair = get_pair_by_identifier(&deps.as_ref(), &pair_identifier)?; + let pool = get_pool_by_identifier(&deps.as_ref(), &pool_identifier)?; ensure!( vec![ask_asset_denom, offer_asset.denom.clone()] .iter() - .all(|asset| pair + .all(|asset| pool .assets .iter() .any(|pool_asset| pool_asset.denom == *asset)), @@ -49,7 +48,7 @@ pub fn swap( let swap_result = perform_swap( deps.branch(), offer_asset.clone(), - pair_identifier, + pool_identifier, belief_price, max_spread, )?; @@ -113,7 +112,7 @@ pub fn swap( ), ( "swap_type", - swap_result.pair_info.pair_type.get_label().to_string(), + swap_result.pool_info.pool_type.get_label().to_string(), ), ])) } diff --git a/contracts/liquidity_hub/pool-manager/src/swap/perform_swap.rs b/contracts/liquidity_hub/pool-manager/src/swap/perform_swap.rs index 8c2ddfe34..eb1216d13 100644 --- a/contracts/liquidity_hub/pool-manager/src/swap/perform_swap.rs +++ b/contracts/liquidity_hub/pool-manager/src/swap/perform_swap.rs @@ -1,11 +1,11 @@ use cosmwasm_std::{Coin, Decimal, DepsMut, Uint128}; -use white_whale_std::pool_manager::PairInfo; +use white_whale_std::pool_manager::PoolInfo; use white_whale_std::pool_network::swap::assert_max_spread; use crate::{ helpers, - state::{get_pair_by_identifier, PAIRS}, + state::{get_pool_by_identifier, POOLS}, ContractError, }; @@ -22,14 +22,14 @@ pub struct SwapResult { /// The osmosis fee of `return_asset` associated with this swap transaction. #[cfg(feature = "osmosis")] pub osmosis_fee_asset: Coin, - /// The pair that was traded. - pub pair_info: PairInfo, + /// The pool that was traded. + pub pool_info: PoolInfo, /// The amount of spread that occurred during the swap from the original exchange rate. pub spread_amount: Uint128, } /// Attempts to perform a swap from `offer_asset` to the relevant opposing -/// asset in the pair identified by `pair_identifier`. +/// asset in the pool identified by `pool_identifier`. /// /// Assumes that `offer_asset` is a **native token**. /// @@ -39,19 +39,19 @@ pub struct SwapResult { pub fn perform_swap( deps: DepsMut, offer_asset: Coin, - pair_identifier: String, + pool_identifier: String, belief_price: Option, max_spread: Option, ) -> Result { - let mut pair_info = get_pair_by_identifier(&deps.as_ref(), &pair_identifier)?; - let pools = &pair_info.assets; + let mut pool_info = get_pool_by_identifier(&deps.as_ref(), &pool_identifier)?; + let pools = &pool_info.assets; // compute the offer and ask pool let offer_pool: Coin; let ask_pool: Coin; let offer_decimal: u8; let ask_decimal: u8; - let decimals = &pair_info.asset_decimals; + let decimals = &pool_info.asset_decimals; // calculate the swap // first, set relevant variables @@ -71,14 +71,14 @@ pub fn perform_swap( } let offer_amount = offer_asset.amount; - let pool_fees = pair_info.pool_fees.clone(); + let pool_fees = pool_info.pool_fees.clone(); let swap_computation = helpers::compute_swap( offer_pool.amount, ask_pool.amount, offer_amount, pool_fees, - &pair_info.pair_type, + &pool_info.pool_type, offer_decimal, ask_decimal, )?; @@ -98,23 +98,22 @@ pub fn perform_swap( swap_computation.spread_amount, )?; - // State changes to the pairs balances + // State changes to the pools balances // Deduct the return amount from the pool and add the offer amount to the pool if offer_asset.denom == pools[0].denom { - pair_info.assets[0].amount += offer_amount; - pair_info.assets[1].amount -= swap_computation.return_amount; - pair_info.assets[1].amount -= swap_computation.protocol_fee_amount; - pair_info.assets[1].amount -= swap_computation.burn_fee_amount; + pool_info.assets[0].amount += offer_amount; + pool_info.assets[1].amount -= swap_computation.return_amount; + pool_info.assets[1].amount -= swap_computation.protocol_fee_amount; + pool_info.assets[1].amount -= swap_computation.burn_fee_amount; } else { - pair_info.assets[1].amount += offer_amount; - pair_info.assets[0].amount -= swap_computation.return_amount; - pair_info.assets[0].amount -= swap_computation.protocol_fee_amount; - pair_info.assets[0].amount -= swap_computation.burn_fee_amount; + pool_info.assets[1].amount += offer_amount; + pool_info.assets[0].amount -= swap_computation.return_amount; + pool_info.assets[0].amount -= swap_computation.protocol_fee_amount; + pool_info.assets[0].amount -= swap_computation.burn_fee_amount; } - PAIRS.save(deps.storage, &pair_identifier, &pair_info)?; + POOLS.save(deps.storage, &pool_identifier, &pool_info)?; - // TODO: Might be handy to make the below fees into a helper method let burn_fee_asset = Coin { denom: ask_pool.denom.clone(), amount: swap_computation.burn_fee_amount, @@ -137,7 +136,7 @@ pub fn perform_swap( swap_fee_asset, burn_fee_asset, protocol_fee_asset, - pair_info, + pool_info, spread_amount: swap_computation.spread_amount, }) } @@ -155,7 +154,7 @@ pub fn perform_swap( burn_fee_asset, protocol_fee_asset, osmosis_fee_asset, - pair_info, + pool_info, spread_amount: swap_computation.spread_amount, }) } diff --git a/contracts/liquidity_hub/pool-manager/src/tests/gas/mod.rs b/contracts/liquidity_hub/pool-manager/src/tests/gas/mod.rs deleted file mode 100644 index 8b1378917..000000000 --- a/contracts/liquidity_hub/pool-manager/src/tests/gas/mod.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/contracts/liquidity_hub/pool-manager/src/tests/integration_tests.rs b/contracts/liquidity_hub/pool-manager/src/tests/integration_tests.rs index 48b4e6923..ec8b515ad 100644 --- a/contracts/liquidity_hub/pool-manager/src/tests/integration_tests.rs +++ b/contracts/liquidity_hub/pool-manager/src/tests/integration_tests.rs @@ -2,15 +2,13 @@ use cosmwasm_std::{coin, Addr, Coin, Decimal, Uint128}; use white_whale_std::fee::Fee; use white_whale_std::fee::PoolFee; +use white_whale_std::pool_manager::PoolType; use white_whale_std::pool_network::asset::MINIMUM_LIQUIDITY_AMOUNT; use crate::ContractError; use super::suite::TestingSuite; -// Using our suite lets test create pair -// and add liquidity to it - #[test] fn instantiate_normal() { let mut suite = TestingSuite::default_with_balances(vec![]); @@ -33,7 +31,6 @@ fn deposit_and_withdraw_sanity_check() { // Asset denoms with uwhale and uluna let asset_denoms = vec!["uwhale".to_string(), "uluna".to_string()]; - // Default Pool fees white_whale_std::pool_network::pair::PoolFee #[cfg(not(feature = "osmosis"))] let pool_fees = PoolFee { protocol_fee: Fee { @@ -65,13 +62,13 @@ fn deposit_and_withdraw_sanity_check() { extra_fees: vec![], }; - // Create a pair - suite.instantiate_default().create_pair( + // Create a pool + suite.instantiate_default().create_pool( creator.clone(), asset_denoms, vec![6u8, 6u8], pool_fees, - white_whale_std::pool_network::asset::PairType::ConstantProduct, + PoolType::ConstantProduct, Some("whale-uluna".to_string()), vec![coin(1000, "uusd")], |result| { @@ -124,7 +121,7 @@ fn deposit_and_withdraw_sanity_check() { // contract should have 1_000 LP shares (MINIMUM_LIQUIDITY_AMOUNT) .query_all_balances(contract_addr.to_string(), |result| { let balances = result.unwrap(); - // check that balances has 999_000 factory/migaloo1wug8sewp6cedgkmrmvhl3lf3tulagm9hnvy8p0rppz9yjw0g4wtqvk723g/uwhale-uluna.vault.whale-uluna.uLP + // check that balances has 999_000 factory/migaloo1wug8sewp6cedgkmrmvhl3lf3tulagm9hnvy8p0rppz9yjw0g4wtqvk723g/uwhale-uluna.pool.whale-uluna.uLP assert!(balances.iter().any(|coin| { coin.denom == lp_denom.clone() && coin.amount == MINIMUM_LIQUIDITY_AMOUNT })); @@ -172,12 +169,12 @@ fn deposit_and_withdraw_sanity_check() { }); } -mod pair_creation_failures { +mod pool_creation_failures { use super::*; - // Insufficient fee to create pair; 90 instead of 100 + // Insufficient fee to create pool; 90 instead of 100 #[test] - fn insufficient_pair_creation_fee() { + fn insufficient_pool_creation_fee() { let mut suite = TestingSuite::default_with_balances(vec![ coin(1_000_000_001u128, "uwhale".to_string()), coin(1_000_000_000u128, "uluna".to_string()), @@ -190,7 +187,6 @@ mod pair_creation_failures { let asset_infos = vec!["uwhale".to_string()]; - // Default Pool fees white_whale_std::pool_network::pair::PoolFee #[cfg(not(feature = "osmosis"))] let pool_fees = PoolFee { protocol_fee: Fee { @@ -221,20 +217,20 @@ mod pair_creation_failures { }, extra_fees: vec![], }; - // Create a pair - suite.instantiate_default().create_pair( + // Create a poo + suite.instantiate_default().create_pool( creator.clone(), asset_infos, vec![6u8, 6u8], pool_fees, - white_whale_std::pool_network::asset::PairType::ConstantProduct, + PoolType::ConstantProduct, None, vec![coin(90, "uusd")], |result| { let err = result.unwrap_err().downcast::().unwrap(); match err { - ContractError::InvalidPairCreationFee { .. } => {} + ContractError::InvalidPoolCreationFee { .. } => {} _ => panic!("Wrong error type, should return ContractError::Unauthorized"), } }, @@ -242,7 +238,7 @@ mod pair_creation_failures { } #[test] - fn cant_recreate_existing_pair() { + fn cant_recreate_existing_poo() { let mut suite = TestingSuite::default_with_balances(vec![ coin(1_000_000_001u128, "uwhale".to_string()), coin(1_000_000_000u128, "uluna".to_string()), @@ -255,7 +251,6 @@ mod pair_creation_failures { let asset_infos = vec!["uwhale".to_string()]; - // Default Pool fees white_whale_std::pool_network::pair::PoolFee #[cfg(not(feature = "osmosis"))] let pool_fees = PoolFee { protocol_fee: Fee { @@ -287,34 +282,34 @@ mod pair_creation_failures { extra_fees: vec![], }; - // Create a pair + // Create a poo suite .instantiate_default() - .create_pair( + .create_pool( creator.clone(), asset_infos.clone(), vec![6u8, 6u8], pool_fees.clone(), - white_whale_std::pool_network::asset::PairType::ConstantProduct, - Some("mycoolpair".to_string()), + PoolType::ConstantProduct, + Some("mycoolpoo".to_string()), vec![coin(1000, "uusd")], |result| { result.unwrap(); }, ) - .create_pair( + .create_pool( creator.clone(), asset_infos, vec![6u8, 6u8], pool_fees, - white_whale_std::pool_network::asset::PairType::ConstantProduct, - Some("mycoolpair".to_string()), + PoolType::ConstantProduct, + Some("mycoolpoo".to_string()), vec![coin(1000, "uusd")], |result| { let err = result.unwrap_err().downcast::().unwrap(); match err { - ContractError::PairExists { .. } => {} - _ => panic!("Wrong error type, should return ContractError::PairExists"), + ContractError::PoolExists { .. } => {} + _ => panic!("Wrong error type, should return ContractError::PoolExists"), } }, ); @@ -340,8 +335,8 @@ mod router { let _unauthorized = suite.senders[2].clone(); // Asset infos with uwhale and uluna - let first_pair = vec!["uwhale".to_string(), "uluna".to_string()]; - let second_pair = vec!["uluna".to_string(), "uusd".to_string()]; + let first_pool = vec!["uwhale".to_string(), "uluna".to_string()]; + let second_pool = vec!["uluna".to_string(), "uusd".to_string()]; #[cfg(not(feature = "osmosis"))] let pool_fees = PoolFee { @@ -373,27 +368,27 @@ mod router { extra_fees: vec![], }; - // Create a pair + // Create a pool suite .instantiate_default() - .create_pair( + .create_pool( creator.clone(), - first_pair, + first_pool, vec![6u8, 6u8], pool_fees.clone(), - white_whale_std::pool_network::asset::PairType::ConstantProduct, + PoolType::ConstantProduct, Some("whale-uluna".to_string()), vec![coin(1000, "uusd")], |result| { result.unwrap(); }, ) - .create_pair( + .create_pool( creator.clone(), - second_pair, + second_pool, vec![6u8, 6u8], pool_fees, - white_whale_std::pool_network::asset::PairType::ConstantProduct, + PoolType::ConstantProduct, Some("uluna-uusd".to_string()), vec![coin(1000, "uusd")], |result| { @@ -452,7 +447,7 @@ mod router { ); // Prepare the swap operations, we want to go from WHALE -> UUSD - // We will use the uluna-uusd pair as the intermediary pool + // We will use the uluna-uusd pool as the intermediary pool let swap_operations = vec![ white_whale_std::pool_manager::SwapOperation::WhaleSwap { @@ -468,7 +463,7 @@ mod router { ]; // before swap uusd balance = 1_000_000_000 - // - 2*1_000 pair creation fee + // - 2*1_000 pool creation fee // - 1_000_000 liquidity provision // = 998_998_000 let pre_swap_amount = 998_998_000; @@ -532,10 +527,9 @@ mod router { let _unauthorized = suite.senders[2].clone(); // Asset infos with uwhale and uluna - let first_pair = vec!["uwhale".to_string(), "uluna".to_string()]; - let second_pair = vec!["uluna".to_string(), "uusd".to_string()]; + let first_pool = vec!["uwhale".to_string(), "uluna".to_string()]; + let second_pool = vec!["uluna".to_string(), "uusd".to_string()]; - // Default Pool fees white_whale_std::pool_network::pair::PoolFee // Protocol fee is 0.01% and swap fee is 0.02% and burn fee is 0% #[cfg(not(feature = "osmosis"))] let pool_fees = PoolFee { @@ -568,27 +562,27 @@ mod router { extra_fees: vec![], }; - // Create a pair + // Create a pool suite .instantiate_default() - .create_pair( + .create_pool( creator.clone(), - first_pair, + first_pool, vec![6u8, 6u8], pool_fees.clone(), - white_whale_std::pool_network::asset::PairType::ConstantProduct, + PoolType::ConstantProduct, Some("whale-uluna".to_string()), vec![coin(1000, "uusd")], |result| { result.unwrap(); }, ) - .create_pair( + .create_pool( creator.clone(), - second_pair, + second_pool, vec![6u8, 6u8], pool_fees, - white_whale_std::pool_network::asset::PairType::ConstantProduct, + PoolType::ConstantProduct, Some("uluna-uusd".to_string()), vec![coin(1000, "uusd")], |result| { @@ -677,10 +671,9 @@ mod router { let _unauthorized = suite.senders[2].clone(); // Asset infos with uwhale and uluna - let first_pair = vec!["uwhale".to_string(), "uluna".to_string()]; - let second_pair = vec!["uluna".to_string(), "uusd".to_string()]; + let first_pool = vec!["uwhale".to_string(), "uluna".to_string()]; + let second_pool = vec!["uluna".to_string(), "uusd".to_string()]; - // Default Pool fees white_whale_std::pool_network::pair::PoolFee // Protocol fee is 0.01% and swap fee is 0.02% and burn fee is 0% #[cfg(not(feature = "osmosis"))] let pool_fees = PoolFee { @@ -713,27 +706,27 @@ mod router { extra_fees: vec![], }; - // Create a pair + // Create a pool suite .instantiate_default() - .create_pair( + .create_pool( creator.clone(), - first_pair, + first_pool, vec![6u8, 6u8], pool_fees.clone(), - white_whale_std::pool_network::asset::PairType::ConstantProduct, + PoolType::ConstantProduct, Some("whale-uluna".to_string()), vec![coin(1000, "uusd")], |result| { result.unwrap(); }, ) - .create_pair( + .create_pool( creator.clone(), - second_pair, + second_pool, vec![6u8, 6u8], pool_fees, - white_whale_std::pool_network::asset::PairType::ConstantProduct, + PoolType::ConstantProduct, Some("uluna-uusd".to_string()), vec![coin(1000, "uusd")], |result| { @@ -792,7 +785,7 @@ mod router { ); // Prepare the swap operations, we want to go from WHALE -> UUSD - // We will use the uluna-uusd pair as the intermediary pool + // We will use the uluna-uusd pool as the intermediary pool let swap_operations = vec![ white_whale_std::pool_manager::SwapOperation::WhaleSwap { @@ -838,10 +831,9 @@ mod router { let unauthorized = suite.senders[2].clone(); // Asset infos with uwhale and uluna - let first_pair = vec!["uwhale".to_string(), "uluna".to_string()]; - let second_pair = vec!["uluna".to_string(), "uusd".to_string()]; + let first_pool = vec!["uwhale".to_string(), "uluna".to_string()]; + let second_pool = vec!["uluna".to_string(), "uusd".to_string()]; - // Default Pool fees white_whale_std::pool_network::pair::PoolFee // Protocol fee is 0.01% and swap fee is 0.02% and burn fee is 0% #[cfg(not(feature = "osmosis"))] let pool_fees = PoolFee { @@ -874,27 +866,27 @@ mod router { extra_fees: vec![], }; - // Create a pair + // Create a pool suite .instantiate_default() - .create_pair( + .create_pool( creator.clone(), - first_pair, + first_pool, vec![6u8, 6u8], pool_fees.clone(), - white_whale_std::pool_network::asset::PairType::ConstantProduct, + PoolType::ConstantProduct, Some("whale-uluna".to_string()), vec![coin(1000, "uusd")], |result| { result.unwrap(); }, ) - .create_pair( + .create_pool( creator.clone(), - second_pair, + second_pool, vec![6u8, 6u8], pool_fees, - white_whale_std::pool_network::asset::PairType::ConstantProduct, + PoolType::ConstantProduct, Some("uluna-uusd".to_string()), vec![coin(1000, "uusd")], |result| { @@ -954,7 +946,7 @@ mod router { ); // Prepare the swap operations, we want to go from WHALE -> UUSD - // We will use the uluna-uusd pair as the intermediary pool + // We will use the uluna-uusd pool as the intermediary pool let swap_operations = vec![ white_whale_std::pool_manager::SwapOperation::WhaleSwap { @@ -1070,8 +1062,8 @@ mod router { let _unauthorized = suite.senders[2].clone(); // Asset infos with uwhale and uluna - let first_pair = vec!["uwhale".to_string(), "uluna".to_string()]; - let second_pair = vec!["uluna".to_string(), "uusd".to_string()]; + let first_pool = vec!["uwhale".to_string(), "uluna".to_string()]; + let second_pool = vec!["uluna".to_string(), "uusd".to_string()]; #[cfg(not(feature = "osmosis"))] let pool_fees = PoolFee { @@ -1103,27 +1095,27 @@ mod router { extra_fees: vec![], }; - // Create a pair + // Create a pool suite .instantiate_default() - .create_pair( + .create_pool( creator.clone(), - first_pair, + first_pool, vec![6u8, 6u8], pool_fees.clone(), - white_whale_std::pool_network::asset::PairType::ConstantProduct, + PoolType::ConstantProduct, Some("whale-uluna".to_string()), vec![coin(1000, "uusd")], |result| { result.unwrap(); }, ) - .create_pair( + .create_pool( creator.clone(), - second_pair, + second_pool, vec![6u8, 6u8], pool_fees, - white_whale_std::pool_network::asset::PairType::ConstantProduct, + PoolType::ConstantProduct, Some("uluna-uusd".to_string()), vec![coin(1000, "uusd")], |result| { @@ -1182,7 +1174,7 @@ mod router { ); // Prepare the swap operations, we want to go from WHALE -> UUSD - // We will use the uluna-uusd pair as the intermediary pool + // We will use the uluna-uusd pool as the intermediary pool let swap_operations = vec![ white_whale_std::pool_manager::SwapOperation::WhaleSwap { @@ -1198,7 +1190,7 @@ mod router { ]; // before swap uusd balance = 1_000_000_000 - // - 2*1_000 pair creation fee + // - 2*1_000 pool creation fee // - 1_000_000 liquidity provision // = 998_998_000 let pre_swap_amount = 998_998_000; @@ -1237,8 +1229,8 @@ mod router { let _other = suite.senders[1].clone(); let _unauthorized = suite.senders[2].clone(); - let first_pair = vec!["uwhale".to_string(), "uluna".to_string()]; - let second_pair = vec!["uluna".to_string(), "uusd".to_string()]; + let first_pool = vec!["uwhale".to_string(), "uluna".to_string()]; + let second_pool = vec!["uluna".to_string(), "uusd".to_string()]; #[cfg(not(feature = "osmosis"))] let pool_fees = PoolFee { @@ -1270,27 +1262,27 @@ mod router { extra_fees: vec![], }; - // Create a pair + // Create a pool suite .instantiate_default() - .create_pair( + .create_pool( creator.clone(), - first_pair, + first_pool, vec![6u8, 6u8], pool_fees.clone(), - white_whale_std::pool_network::asset::PairType::ConstantProduct, + PoolType::ConstantProduct, Some("whale-uluna".to_string()), vec![coin(1000, "uusd")], |result| { result.unwrap(); }, ) - .create_pair( + .create_pool( creator.clone(), - second_pair, + second_pool, vec![6u8, 6u8], pool_fees, - white_whale_std::pool_network::asset::PairType::ConstantProduct, + PoolType::ConstantProduct, Some("uluna-uusd".to_string()), vec![coin(1000, "uusd")], |result| { @@ -1403,8 +1395,8 @@ mod router { let other = suite.senders[1].clone(); let unauthorized = suite.senders[2].clone(); - let first_pair = vec!["uwhale".to_string(), "uluna".to_string()]; - let second_pair = vec!["uluna".to_string(), "uusd".to_string()]; + let first_pool = vec!["uwhale".to_string(), "uluna".to_string()]; + let second_pool = vec!["uluna".to_string(), "uusd".to_string()]; #[cfg(not(feature = "osmosis"))] let pool_fees = PoolFee { @@ -1436,27 +1428,27 @@ mod router { extra_fees: vec![], }; - // Create a pair + // Create a pool suite .instantiate_default() - .create_pair( + .create_pool( creator.clone(), - first_pair, + first_pool, vec![6u8, 6u8], pool_fees.clone(), - white_whale_std::pool_network::asset::PairType::ConstantProduct, + PoolType::ConstantProduct, Some("whale-uluna".to_string()), vec![coin(1000, "uusd")], |result| { result.unwrap(); }, ) - .create_pair( + .create_pool( creator.clone(), - second_pair, + second_pool, vec![6u8, 6u8], pool_fees, - white_whale_std::pool_network::asset::PairType::ConstantProduct, + PoolType::ConstantProduct, Some("uluna-uusd".to_string()), vec![coin(1000, "uusd")], |result| { @@ -1601,8 +1593,8 @@ mod router { let _unauthorized = suite.senders[2].clone(); // Asset infos with uwhale and uluna - let first_pair = vec!["uwhale".to_string(), "uluna".to_string()]; - let second_pair = vec!["uluna".to_string(), "uusd".to_string()]; + let first_pool = vec!["uwhale".to_string(), "uluna".to_string()]; + let second_pool = vec!["uluna".to_string(), "uusd".to_string()]; #[cfg(not(feature = "osmosis"))] let pool_fees = PoolFee { @@ -1634,27 +1626,27 @@ mod router { extra_fees: vec![], }; - // Create a pair + // Create a pool suite .instantiate_default() - .create_pair( + .create_pool( creator.clone(), - first_pair, + first_pool, vec![6u8, 6u8], pool_fees.clone(), - white_whale_std::pool_network::asset::PairType::ConstantProduct, + PoolType::ConstantProduct, Some("whale-uluna".to_string()), vec![coin(1_000, "uusd")], |result| { result.unwrap(); }, ) - .create_pair( + .create_pool( creator.clone(), - second_pair, + second_pool, vec![6u8, 6u8], pool_fees, - white_whale_std::pool_network::asset::PairType::ConstantProduct, + PoolType::ConstantProduct, Some("uluna-uusd".to_string()), vec![coin(1_000, "uusd")], |result| { @@ -1713,7 +1705,7 @@ mod router { ); // Prepare the swap operations, we want to go from WHALE -> UUSD - // We will use the uluna-uusd pair as the intermediary pool + // We will use the uluna-uusd pool as the intermediary pool let swap_operations = vec![ white_whale_std::pool_manager::SwapOperation::WhaleSwap { @@ -1805,6 +1797,7 @@ mod swapping { use std::cell::RefCell; use cosmwasm_std::assert_approx_eq; + use white_whale_std::pool_manager::PoolType; use super::*; @@ -1822,7 +1815,6 @@ mod swapping { let asset_infos = vec!["uwhale".to_string(), "uluna".to_string()]; - // Default Pool fees white_whale_std::pool_network::pair::PoolFee // Protocol fee is 0.01% and swap fee is 0.02% and burn fee is 0% #[cfg(not(feature = "osmosis"))] let pool_fees = PoolFee { @@ -1855,13 +1847,13 @@ mod swapping { extra_fees: vec![], }; - // Create a pair - suite.instantiate_default().create_pair( + // Create a pool + suite.instantiate_default().create_pool( creator.clone(), asset_infos, vec![6u8, 6u8], pool_fees, - white_whale_std::pool_network::asset::PairType::ConstantProduct, + PoolType::ConstantProduct, Some("whale-uluna".to_string()), vec![coin(1000, "uusd")], |result| { @@ -1869,9 +1861,9 @@ mod swapping { }, ); - // Query pair info to ensure the query is working fine - suite.query_pair_info("whale-uluna".to_string(), |result| { - assert_eq!(result.unwrap().pair_info.asset_decimals, vec![6u8, 6u8]); + // Query pool info to ensure the query is working fine + suite.query_pool_info("whale-uluna".to_string(), |result| { + assert_eq!(result.unwrap().pool_info.asset_decimals, vec![6u8, 6u8]); }); // Lets try to add liquidity @@ -1905,12 +1897,12 @@ mod swapping { })); }, ) - .query_pair_info("whale-uluna".to_string(), |result| { + .query_pool_info("whale-uluna".to_string(), |result| { let response = result.unwrap(); assert_eq!( response.total_share, Coin { - denom: response.pair_info.lp_denom, + denom: response.pool_info.lp_denom, amount: Uint128::from(1_000_000u128) } ); @@ -2043,7 +2035,6 @@ mod swapping { let asset_infos = vec!["uwhale".to_string(), "uluna".to_string()]; - // Default Pool fees white_whale_std::pool_network::pair::PoolFee // Protocol fee is 0.01% and swap fee is 0.02% and burn fee is 0% #[cfg(not(feature = "osmosis"))] let pool_fees = PoolFee { @@ -2076,13 +2067,13 @@ mod swapping { extra_fees: vec![], }; - // Create a pair - suite.instantiate_default().create_pair( + // Create a pool + suite.instantiate_default().create_pool( creator.clone(), asset_infos, vec![6u8, 6u8], pool_fees, - white_whale_std::pool_network::asset::PairType::StableSwap { amp: 100 }, + PoolType::StableSwap { amp: 100 }, Some("whale-uluna".to_string()), vec![coin(1000, "uusd")], |result| { @@ -2237,7 +2228,6 @@ mod swapping { let asset_infos = vec!["uwhale".to_string(), "uluna".to_string()]; - // Default Pool fees white_whale_std::pool_network::pair::PoolFee // Protocol fee is 0.001% and swap fee is 0.002% and burn fee is 0% #[cfg(not(feature = "osmosis"))] let pool_fees = PoolFee { @@ -2270,13 +2260,13 @@ mod swapping { extra_fees: vec![], }; - // Create a pair - suite.instantiate_default().create_pair( + // Create a pool + suite.instantiate_default().create_pool( creator.clone(), asset_infos, vec![6u8, 6u8], pool_fees, - white_whale_std::pool_network::asset::PairType::ConstantProduct, + PoolType::ConstantProduct, Some("whale-uluna".to_string()), vec![coin(1000, "uusd")], |result| { @@ -2510,6 +2500,7 @@ mod locking_lp { use white_whale_std::fee::{Fee, PoolFee}; use white_whale_std::incentive_manager::Position; + use white_whale_std::pool_manager::PoolType; use white_whale_std::pool_network::asset::MINIMUM_LIQUIDITY_AMOUNT; use crate::tests::suite::TestingSuite; @@ -2528,7 +2519,6 @@ mod locking_lp { // Asset denoms with uwhale and uluna let asset_denoms = vec!["uwhale".to_string(), "uluna".to_string()]; - // Default Pool fees white_whale_std::pool_network::pair::PoolFee #[cfg(not(feature = "osmosis"))] let pool_fees = PoolFee { protocol_fee: Fee { @@ -2560,13 +2550,13 @@ mod locking_lp { extra_fees: vec![], }; - // Create a pair - suite.instantiate_default().create_pair( + // Create a pool + suite.instantiate_default().create_pool( creator.clone(), asset_denoms, vec![6u8, 6u8], pool_fees, - white_whale_std::pool_network::asset::PairType::ConstantProduct, + PoolType::ConstantProduct, Some("whale-uluna".to_string()), vec![coin(1000, "uusd")], |result| { @@ -2719,7 +2709,6 @@ mod locking_lp { // Asset denoms with uwhale and uluna let asset_denoms = vec!["uwhale".to_string(), "uluna".to_string()]; - // Default Pool fees white_whale_std::pool_network::pair::PoolFee #[cfg(not(feature = "osmosis"))] let pool_fees = PoolFee { protocol_fee: Fee { @@ -2751,13 +2740,13 @@ mod locking_lp { extra_fees: vec![], }; - // Create a pair - suite.instantiate_default().create_pair( + // Create a pool + suite.instantiate_default().create_pool( creator.clone(), asset_denoms, vec![6u8, 6u8], pool_fees, - white_whale_std::pool_network::asset::PairType::ConstantProduct, + PoolType::ConstantProduct, Some("whale-uluna".to_string()), vec![coin(1000, "uusd")], |result| { @@ -2894,6 +2883,7 @@ mod provide_liquidity { use cosmwasm_std::{coin, Coin, Decimal, StdError, Uint128}; use white_whale_std::fee::{Fee, PoolFee}; + use white_whale_std::pool_manager::PoolType; use white_whale_std::pool_network::asset::MINIMUM_LIQUIDITY_AMOUNT; use crate::tests::suite::TestingSuite; @@ -2914,7 +2904,6 @@ mod provide_liquidity { // Asset denoms with uwhale and uluna let asset_denoms = vec!["uwhale".to_string(), "uluna".to_string()]; - // Default Pool fees white_whale_std::pool_network::pair::PoolFee #[cfg(not(feature = "osmosis"))] let pool_fees = PoolFee { protocol_fee: Fee { @@ -2946,13 +2935,13 @@ mod provide_liquidity { extra_fees: vec![], }; - // Create a pair - suite.instantiate_default().create_pair( + // Create a pool + suite.instantiate_default().create_pool( creator.clone(), asset_denoms, vec![6u8, 6u8], pool_fees, - white_whale_std::pool_network::asset::PairType::ConstantProduct, + PoolType::ConstantProduct, Some("whale-uluna".to_string()), vec![coin(1000, "uusd")], |result| { @@ -3156,17 +3145,17 @@ mod provide_liquidity { // 1_000 to the contract, and 1_000_000 to the second, single-side LP assert_eq!(res.unwrap().amount, Uint128::from(2_000_000u128)); }) - .query_pair_info("whale-uluna".to_string(), |res| { + .query_pool_info("whale-uluna".to_string(), |res| { let response = res.unwrap(); let whale = response - .pair_info + .pool_info .assets .iter() .find(|coin| coin.denom == "uwhale".to_string()) .unwrap(); let luna = response - .pair_info + .pool_info .assets .iter() .find(|coin| coin.denom == "uluna".to_string()) @@ -3364,7 +3353,6 @@ mod provide_liquidity { // Asset denoms with uwhale and uluna let asset_denoms = vec!["uwhale".to_string(), "uluna".to_string()]; - // Default Pool fees white_whale_std::pool_network::pair::PoolFee #[cfg(not(feature = "osmosis"))] let pool_fees = PoolFee { protocol_fee: Fee { @@ -3396,13 +3384,13 @@ mod provide_liquidity { extra_fees: vec![], }; - // Create a pair - suite.instantiate_default().create_pair( + // Create a pool + suite.instantiate_default().create_pool( creator.clone(), asset_denoms, vec![6u8, 6u8], pool_fees, - white_whale_std::pool_network::asset::PairType::ConstantProduct, + PoolType::ConstantProduct, Some("whale-uluna".to_string()), vec![coin(1000, "uusd")], |result| { diff --git a/contracts/liquidity_hub/pool-manager/src/tests/mock_querier.rs b/contracts/liquidity_hub/pool-manager/src/tests/mock_querier.rs deleted file mode 100644 index 2db5b9408..000000000 --- a/contracts/liquidity_hub/pool-manager/src/tests/mock_querier.rs +++ /dev/null @@ -1,324 +0,0 @@ -use std::collections::HashMap; -use std::iter::FromIterator; -use std::marker::PhantomData; -use std::panic; - -use cosmwasm_std::testing::{MockApi, MockQuerier, MockStorage, MOCK_CONTRACT_ADDR}; -use cosmwasm_std::{ - from_binary, from_slice, to_binary, Addr, CodeInfoResponse, Coin, ContractInfoResponse, - ContractResult, Empty, HexBinary, OwnedDeps, Querier, QuerierResult, QueryRequest, SystemError, - SystemResult, Uint128, WasmQuery, -}; -use cw20::{BalanceResponse as Cw20BalanceResponse, Cw20QueryMsg, TokenInfoResponse}; -use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32}; -use white_whale_std::pool_network::asset::{Asset, AssetInfo, PairInfo, PairType, TrioInfo}; -use white_whale_std::pool_network::factory::{ - NativeTokenDecimalsResponse, QueryMsg as FactoryQueryMsg, -}; -use white_whale_std::pool_network::pair::{ - self, PoolResponse as PairPoolResponse, QueryMsg as PairQueryMsg, -}; -use white_whale_std::pool_network::pair::{ReverseSimulationResponse, SimulationResponse}; -use white_whale_std::pool_network::temp_mock_api::MockSimpleApi; -use white_whale_std::pool_network::trio; -use white_whale_std::pool_network::trio::{ - PoolResponse as TrioPoolResponse, QueryMsg as TrioQueryMsg, -}; -/// mock_dependencies is a drop-in replacement for cosmwasm_std::testing::mock_dependencies -/// this uses our CustomQuerier. -pub fn mock_dependencies( - contract_balance: &[Coin], -) -> OwnedDeps { - let custom_querier: WasmMockQuerier = - WasmMockQuerier::new(MockQuerier::new(&[(MOCK_CONTRACT_ADDR, contract_balance)])); - - OwnedDeps { - storage: MockStorage::default(), - api: MockSimpleApi::default(), - querier: custom_querier, - custom_query_type: PhantomData, - } -} - -pub struct WasmMockQuerier { - base: MockQuerier, - token_querier: TokenQuerier, - pool_factory_querier: PoolFactoryQuerier, -} - -#[derive(Clone, Default)] -pub struct TokenQuerier { - // this lets us iterate over all pairs that match the first string - balances: HashMap>, -} - -impl TokenQuerier { - pub fn new(balances: &[(&String, &[(&String, &Uint128)])]) -> Self { - TokenQuerier { - balances: balances_to_map(balances), - } - } -} - -pub fn balances_to_map( - balances: &[(&String, &[(&String, &Uint128)])], -) -> HashMap> { - let mut balances_map: HashMap> = HashMap::new(); - for (contract_addr, balances) in balances.iter() { - let mut contract_balances_map: HashMap = HashMap::new(); - for (addr, balance) in balances.iter() { - contract_balances_map.insert(addr.to_string(), **balance); - } - - balances_map.insert(contract_addr.to_string(), contract_balances_map); - } - balances_map -} - -#[derive(Clone, Default)] -pub struct PoolFactoryQuerier { - pairs: HashMap, - native_token_decimals: HashMap, -} - -impl PoolFactoryQuerier { - pub fn new(pairs: &[(&String, &PairInfo)], native_token_decimals: &[(String, u8)]) -> Self { - PoolFactoryQuerier { - pairs: pairs_to_map(pairs), - native_token_decimals: native_token_decimals_to_map(native_token_decimals), - } - } -} - -pub fn pairs_to_map(pairs: &[(&String, &PairInfo)]) -> HashMap { - let mut pairs_map: HashMap = HashMap::new(); - // Key is the pool_identifer - for (key, pair) in pairs.iter() { - pairs_map.insert(key.to_string(), (**pair).clone()); - } - pairs_map -} - -pub fn native_token_decimals_to_map(native_token_decimals: &[(String, u8)]) -> HashMap { - let mut native_token_decimals_map: HashMap = HashMap::new(); - - for (denom, decimals) in native_token_decimals.iter() { - native_token_decimals_map.insert(denom.to_string(), *decimals); - } - native_token_decimals_map -} - -impl Querier for WasmMockQuerier { - fn raw_query(&self, bin_request: &[u8]) -> QuerierResult { - // MockQuerier doesn't support Custom, so we ignore it completely here - let request: QueryRequest = match from_slice(bin_request) { - Ok(v) => v, - Err(e) => { - return SystemResult::Err(SystemError::InvalidRequest { - error: format!("Parsing query request: {e}"), - request: bin_request.into(), - }); - } - }; - self.handle_query(&request) - } -} - -impl WasmMockQuerier { - pub fn handle_query(&self, request: &QueryRequest) -> QuerierResult { - match &request { - QueryRequest::Wasm(WasmQuery::Smart { contract_addr, msg }) => match from_binary(msg) { - Ok(white_whale_std::pool_manager::QueryMsg::Pair { pair_identifier }) => { - match self.pool_factory_querier.pairs.get(&pair_identifier) { - Some(v) => SystemResult::Ok(ContractResult::Ok(to_binary(v).unwrap())), - None => SystemResult::Err(SystemError::InvalidRequest { - error: "No pair info exists".to_string(), - request: msg.as_slice().into(), - }), - } - } - _ => match from_binary(msg) { - Ok(white_whale_std::pool_manager::QueryMsg::Simulation { - offer_asset, - ask_asset, - pair_identifier, - }) => SystemResult::Ok(ContractResult::from(to_binary(&SimulationResponse { - return_amount: offer_asset.amount, - swap_fee_amount: Uint128::zero(), - spread_amount: Uint128::zero(), - protocol_fee_amount: Uint128::zero(), - burn_fee_amount: Uint128::zero(), - }))), - Ok(white_whale_std::pool_manager::QueryMsg::ReverseSimulation { - ask_asset, - offer_asset, - pair_identifier, - }) => SystemResult::Ok(ContractResult::from(to_binary( - &ReverseSimulationResponse { - offer_amount: ask_asset.amount, - swap_fee_amount: Uint128::zero(), - spread_amount: Uint128::zero(), - protocol_fee_amount: Uint128::zero(), - burn_fee_amount: Uint128::zero(), - }, - ))), - }, - }, - QueryRequest::Wasm(WasmQuery::ContractInfo { .. }) => { - let mut contract_info_response = ContractInfoResponse::default(); - contract_info_response.code_id = 0u64; - contract_info_response.creator = "creator".to_string(); - contract_info_response.admin = Some("creator".to_string()); - - SystemResult::Ok(ContractResult::Ok( - to_binary(&contract_info_response).unwrap(), - )) - } - QueryRequest::Wasm(WasmQuery::CodeInfo { code_id }) => { - let mut default = CodeInfoResponse::default(); - - match code_id { - 11 => { - default.code_id = 67; - default.creator = Addr::unchecked("creator").to_string(); - default.checksum = HexBinary::from_hex(&sha256::digest(format!( - "code_checksum_{}", - code_id - ))) - .unwrap(); - SystemResult::Ok(to_binary(&default).into()) - } - _ => { - return SystemResult::Err(SystemError::Unknown {}); - } - } - } - _ => self.base.handle_query(request), - } - } -} - -impl WasmMockQuerier { - pub fn new(base: MockQuerier) -> Self { - WasmMockQuerier { - base, - token_querier: TokenQuerier::default(), - pool_factory_querier: PoolFactoryQuerier::default(), - } - } - - // configure the mint whitelist mock querier - pub fn with_token_balances(&mut self, balances: &[(&String, &[(&String, &Uint128)])]) { - self.token_querier = TokenQuerier::new(balances); - } - - // configure the pair - pub fn with_pool_factory( - &mut self, - pairs: &[(&String, &PairInfo)], - native_token_decimals: &[(String, u8)], - ) { - self.pool_factory_querier = PoolFactoryQuerier::new(pairs, native_token_decimals); - } - - pub fn with_balance(&mut self, balances: &[(&String, Vec)]) { - for (addr, balance) in balances { - self.base.update_balance(addr.to_string(), balance.clone()); - } - } -} - -#[cfg(test)] -mod mock_exception { - use cosmwasm_std::Binary; - - use super::*; - - #[test] - fn raw_query_err() { - let deps = mock_dependencies(&[]); - assert_eq!( - deps.querier.raw_query(&[]), - SystemResult::Err(SystemError::InvalidRequest { - error: "Parsing query request: Error parsing into type cosmwasm_std::query::QueryRequest: EOF while parsing a JSON value.".to_string(), - request: Binary(vec![]), - }) - ); - } - - #[test] - fn none_factory_pair_will_err() { - let deps = mock_dependencies(&[]); - - let msg = to_binary(&white_whale_std::pool_manager::QueryMsg::Pair { - pair_identifier: "pair0000".to_string(), - }) - .unwrap(); - assert_eq!( - deps.querier - .handle_query(&QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: "contract0000".to_string(), - msg: msg.clone(), - })), - SystemResult::Err(SystemError::InvalidRequest { - error: "No pair info exists".to_string(), - request: msg, - }) - ) - } - - #[test] - fn none_tokens_info_will_err() { - let deps = mock_dependencies(&[]); - - let msg = to_binary(&Cw20QueryMsg::TokenInfo {}).unwrap(); - - assert_eq!( - deps.querier - .handle_query(&QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: "token0000".to_string(), - msg: msg.clone(), - })), - SystemResult::Err(SystemError::InvalidRequest { - error: "No balance info exists for the contract token0000".to_string(), - request: msg, - }) - ) - } - - #[test] - fn none_tokens_balance_will_err() { - let deps = mock_dependencies(&[]); - - let msg = to_binary(&Cw20QueryMsg::Balance { - address: "address0000".to_string(), - }) - .unwrap(); - - assert_eq!( - deps.querier - .handle_query(&QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: "token0000".to_string(), - msg: msg.clone(), - })), - SystemResult::Err(SystemError::InvalidRequest { - error: "No balance info exists for the contract token0000".to_string(), - request: msg, - }) - ) - } - - #[test] - #[should_panic] - fn none_tokens_minter_will_panic() { - let deps = mock_dependencies(&[]); - - let msg = to_binary(&Cw20QueryMsg::Minter {}).unwrap(); - - deps.querier - .handle_query(&QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: "token0000".to_string(), - msg, - })); - } -} diff --git a/contracts/liquidity_hub/pool-manager/src/tests/mod.rs b/contracts/liquidity_hub/pool-manager/src/tests/mod.rs index ba1e59453..8a80c1006 100644 --- a/contracts/liquidity_hub/pool-manager/src/tests/mod.rs +++ b/contracts/liquidity_hub/pool-manager/src/tests/mod.rs @@ -1,6 +1,2 @@ pub mod integration_tests; pub mod suite; - -// TODO: Uncomment once unit_tests are working or removed -// pub mod mock_querier; -// pub mod unit_tests; diff --git a/contracts/liquidity_hub/pool-manager/src/tests/suite.rs b/contracts/liquidity_hub/pool-manager/src/tests/suite.rs index c952224e9..09f56c42e 100644 --- a/contracts/liquidity_hub/pool-manager/src/tests/suite.rs +++ b/contracts/liquidity_hub/pool-manager/src/tests/suite.rs @@ -1,11 +1,11 @@ use cosmwasm_std::testing::MockStorage; use std::cell::RefCell; -use white_whale_std::pool_manager::InstantiateMsg; use white_whale_std::pool_manager::{ - Config, FeatureToggle, PairInfoResponse, ReverseSimulateSwapOperationsResponse, + Config, FeatureToggle, PoolInfoResponse, ReverseSimulateSwapOperationsResponse, ReverseSimulationResponse, SimulateSwapOperationsResponse, SimulationResponse, SwapOperation, SwapRouteCreatorResponse, SwapRouteResponse, SwapRoutesResponse, }; +use white_whale_std::pool_manager::{InstantiateMsg, PoolType}; use cosmwasm_std::{coin, Addr, Coin, Decimal, Empty, StdResult, Timestamp, Uint128, Uint64}; use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32}; @@ -18,7 +18,7 @@ use white_whale_std::epoch_manager::epoch_manager::{Epoch, EpochConfig}; use white_whale_std::fee::PoolFee; use white_whale_std::incentive_manager::PositionsResponse; use white_whale_std::lp_common::LP_SYMBOL; -use white_whale_std::pool_network::asset::{AssetInfo, PairType}; +use white_whale_std::pool_network::asset::AssetInfo; use white_whale_testing::multi_test::stargate_mock::StargateMock; fn contract_pool_manager() -> Box> { @@ -105,11 +105,10 @@ impl TestingSuite { self } - pub(crate) fn get_lp_denom(&self, pair_id: String) -> String { - // TODO: this should have + pub(crate) fn get_lp_denom(&self, pool_identifier: String) -> String { format!( "factory/{}/u{}.pool.{}.{}", - self.pool_manager_addr, pair_id, pair_id, LP_SYMBOL + self.pool_manager_addr, pool_identifier, pool_identifier, LP_SYMBOL ) } } @@ -317,7 +316,7 @@ impl TestingSuite { pub(crate) fn provide_liquidity( &mut self, sender: Addr, - pair_identifier: String, + pool_identifier: String, unlocking_duration: Option, lock_position_identifier: Option, max_spread: Option, @@ -326,7 +325,7 @@ impl TestingSuite { result: impl Fn(Result), ) -> &mut Self { let msg = white_whale_std::pool_manager::ExecuteMsg::ProvideLiquidity { - pair_identifier, + pool_identifier, slippage_tolerance: None, max_spread, receiver, @@ -351,7 +350,7 @@ impl TestingSuite { belief_price: Option, max_spread: Option, receiver: Option, - pair_identifier: String, + pool_identifier: String, funds: Vec, result: impl Fn(Result), ) -> &mut Self { @@ -360,7 +359,7 @@ impl TestingSuite { belief_price, max_spread, receiver, - pair_identifier, + pool_identifier, }; result( @@ -378,7 +377,7 @@ impl TestingSuite { sender: Addr, operations: Vec, minimum_receive: Option, - to: Option, + receiver: Option, max_spread: Option, funds: Vec, result: impl Fn(Result), @@ -386,7 +385,7 @@ impl TestingSuite { let msg = white_whale_std::pool_manager::ExecuteMsg::ExecuteSwapOperations { operations, minimum_receive, - to, + receiver, max_spread, }; @@ -400,30 +399,30 @@ impl TestingSuite { #[track_caller] #[allow(clippy::too_many_arguments)] - pub(crate) fn create_pair( + pub(crate) fn create_pool( &mut self, sender: Addr, asset_denoms: Vec, asset_decimals: Vec, pool_fees: PoolFee, - pair_type: PairType, - pair_identifier: Option, - pair_creation_fee_funds: Vec, + pool_type: PoolType, + pool_identifier: Option, + pool_creation_fee_funds: Vec, result: impl Fn(Result), ) -> &mut Self { - let msg = white_whale_std::pool_manager::ExecuteMsg::CreatePair { + let msg = white_whale_std::pool_manager::ExecuteMsg::CreatePool { asset_denoms, asset_decimals, pool_fees, - pair_type, - pair_identifier, + pool_type, + pool_identifier, }; result(self.app.execute_contract( sender, self.pool_manager_addr.clone(), &msg, - &pair_creation_fee_funds, + &pool_creation_fee_funds, )); self @@ -433,11 +432,11 @@ impl TestingSuite { pub(crate) fn withdraw_liquidity( &mut self, sender: Addr, - pair_identifier: String, + pool_identifier: String, funds: Vec, result: impl Fn(Result), ) -> &mut Self { - let msg = white_whale_std::pool_manager::ExecuteMsg::WithdrawLiquidity { pair_identifier }; + let msg = white_whale_std::pool_manager::ExecuteMsg::WithdrawLiquidity { pool_identifier }; result( self.app @@ -553,48 +552,48 @@ impl TestingSuite { self } - pub(crate) fn query_pair_info( + pub(crate) fn query_pool_info( &self, - pair_identifier: String, - result: impl Fn(StdResult), + pool_identifier: String, + result: impl Fn(StdResult), ) -> &Self { - let pair_info_response: StdResult = self.app.wrap().query_wasm_smart( + let pool_info_response: StdResult = self.app.wrap().query_wasm_smart( &self.pool_manager_addr, - &white_whale_std::pool_manager::QueryMsg::Pair { pair_identifier }, + &white_whale_std::pool_manager::QueryMsg::Pool { pool_identifier }, ); - result(pair_info_response); + result(pool_info_response); self } pub(crate) fn query_simulation( &mut self, - pair_identifier: String, + pool_identifier: String, offer_asset: Coin, result: impl Fn(StdResult), ) -> &mut Self { - let pair_info_response: StdResult = self.app.wrap().query_wasm_smart( + let pool_info_response: StdResult = self.app.wrap().query_wasm_smart( &self.pool_manager_addr, &white_whale_std::pool_manager::QueryMsg::Simulation { offer_asset, - pair_identifier, + pool_identifier, }, ); - result(pair_info_response); + result(pool_info_response); self } pub(crate) fn query_reverse_simulation( &mut self, - pair_identifier: String, + pool_identifier: String, offer_asset: String, ask_asset: Coin, result: impl Fn(StdResult), ) -> &mut Self { - let pair_info_response: StdResult = + let pool_info_response: StdResult = self.app.wrap().query_wasm_smart( &self.pool_manager_addr, &white_whale_std::pool_manager::QueryMsg::ReverseSimulation { @@ -603,11 +602,11 @@ impl TestingSuite { denom: offer_asset, }, ask_asset, - pair_identifier, + pool_identifier, }, ); - result(pair_info_response); + result(pool_info_response); self } @@ -618,7 +617,7 @@ impl TestingSuite { operations: Vec, result: impl Fn(StdResult), ) -> &mut Self { - let pair_info_response: StdResult = + let pool_info_response: StdResult = self.app.wrap().query_wasm_smart( &self.pool_manager_addr, &white_whale_std::pool_manager::QueryMsg::SimulateSwapOperations { @@ -627,7 +626,7 @@ impl TestingSuite { }, ); - result(pair_info_response); + result(pool_info_response); self } @@ -638,7 +637,7 @@ impl TestingSuite { operations: Vec, result: impl Fn(StdResult), ) -> &mut Self { - let pair_info_response: StdResult = + let pool_info_response: StdResult = self.app.wrap().query_wasm_smart( &self.pool_manager_addr, &white_whale_std::pool_manager::QueryMsg::ReverseSimulateSwapOperations { @@ -647,7 +646,7 @@ impl TestingSuite { }, ); - result(pair_info_response); + result(pool_info_response); self } @@ -659,13 +658,13 @@ impl TestingSuite { result: impl Fn(StdResult), ) -> &mut Self { // Get the LP token from Config - let lp_token_response: PairInfoResponse = self + let lp_token_response: PoolInfoResponse = self .app .wrap() .query_wasm_smart( &self.pool_manager_addr, - &white_whale_std::pool_manager::QueryMsg::Pair { - pair_identifier: identifier, + &white_whale_std::pool_manager::QueryMsg::Pool { + pool_identifier: identifier, }, ) .unwrap(); @@ -675,7 +674,7 @@ impl TestingSuite { let balance: Uint128 = self .app .wrap() - .query_balance(sender, lp_token_response.pair_info.lp_denom) + .query_balance(sender, lp_token_response.pool_info.lp_denom) .unwrap() .amount; @@ -694,7 +693,7 @@ impl TestingSuite { .unwrap() } - /// Retrieves a swap route for a given pair of assets. + /// Retrieves a swap route for a given pool of assets. pub(crate) fn query_swap_route( &mut self, offer_asset_denom: String, @@ -714,7 +713,7 @@ impl TestingSuite { self } - /// Retrieves the swap routes for a given pair of assets. + /// Retrieves the swap routes for a given poolr of assets. pub(crate) fn query_swap_routes( &mut self, result: impl Fn(StdResult), @@ -729,7 +728,7 @@ impl TestingSuite { self } - /// Retrieves the swap route creator for a given pair of assets. + /// Retrieves the swap route creator for a given pool of assets. pub(crate) fn query_swap_route_creator( &mut self, offer_asset_denom: String, @@ -778,9 +777,9 @@ impl TestingSuite { ) -> &mut Self { let lp_denom = RefCell::new("".to_string()); - self.query_pair_info(identifier.clone(), |res| { + self.query_pool_info(identifier.clone(), |res| { let response = res.unwrap(); - *lp_denom.borrow_mut() = response.pair_info.lp_denom.clone(); + *lp_denom.borrow_mut() = response.pool_info.lp_denom.clone(); }); let supply_response = self.app.wrap().query_supply(lp_denom.into_inner()); diff --git a/contracts/liquidity_hub/pool-manager/src/tests/temp_mock_api.rs b/contracts/liquidity_hub/pool-manager/src/tests/temp_mock_api.rs deleted file mode 100644 index fb5a7b1ea..000000000 --- a/contracts/liquidity_hub/pool-manager/src/tests/temp_mock_api.rs +++ /dev/null @@ -1,87 +0,0 @@ -use cosmwasm_std::{ - Addr, Api, CanonicalAddr, RecoverPubkeyError, StdError, StdResult, VerificationError, -}; -// Reworked mock api to work with instantiate2 in mock_querier, can eventually be removed -#[derive(Copy, Clone, Default)] -pub struct MockSimpleApi {} - -impl Api for MockSimpleApi { - fn addr_validate(&self, input: &str) -> StdResult { - let canonical = self.addr_canonicalize(input)?; - let normalized = self.addr_humanize(&canonical)?; - if input != normalized && normalized != "contract1" { - return Err(StdError::generic_err( - "Invalid input: address not normalized", - )); - } - - Ok(Addr::unchecked(input)) - } - - fn addr_canonicalize(&self, input: &str) -> StdResult { - // Very straigthfoward canonicalization, we simply serialize the address to bytes - Ok(input.chars().map(|c| c as u8).collect::>().into()) - } - - fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult { - let mut address: String = canonical.0 .0.iter().map(|&c| c as char).collect(); - if address - == "\u{82}³r\u{13}Ø\r¯ËÌB\u{85}Ó^-b¸\u{19}\u{89}Z\rBðf0ç\u{9d}µís+æ\u{16}".to_string() - { - address = "contract1".to_string(); - } - Ok(Addr::unchecked(address)) - } - - fn secp256k1_verify( - &self, - message_hash: &[u8], - signature: &[u8], - public_key: &[u8], - ) -> Result { - cosmwasm_std::testing::MockApi::default().secp256k1_verify( - message_hash, - signature, - public_key, - ) - } - - fn secp256k1_recover_pubkey( - &self, - message_hash: &[u8], - signature: &[u8], - recovery_param: u8, - ) -> Result, RecoverPubkeyError> { - cosmwasm_std::testing::MockApi::default().secp256k1_recover_pubkey( - message_hash, - signature, - recovery_param, - ) - } - - fn ed25519_verify( - &self, - message: &[u8], - signature: &[u8], - public_key: &[u8], - ) -> Result { - cosmwasm_std::testing::MockApi::default().ed25519_verify(message, signature, public_key) - } - - fn ed25519_batch_verify( - &self, - messages: &[&[u8]], - signatures: &[&[u8]], - public_keys: &[&[u8]], - ) -> Result { - cosmwasm_std::testing::MockApi::default().ed25519_batch_verify( - messages, - signatures, - public_keys, - ) - } - - fn debug(&self, message: &str) { - println!("{}", message); - } -} diff --git a/contracts/liquidity_hub/pool-manager/src/tests/unit_tests/mod.rs b/contracts/liquidity_hub/pool-manager/src/tests/unit_tests/mod.rs deleted file mode 100644 index c79f956f8..000000000 --- a/contracts/liquidity_hub/pool-manager/src/tests/unit_tests/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod pairs; -pub mod provide_liquidity; -pub mod swap; diff --git a/contracts/liquidity_hub/pool-manager/src/tests/unit_tests/pairs.rs b/contracts/liquidity_hub/pool-manager/src/tests/unit_tests/pairs.rs deleted file mode 100644 index 03ca151ab..000000000 --- a/contracts/liquidity_hub/pool-manager/src/tests/unit_tests/pairs.rs +++ /dev/null @@ -1,620 +0,0 @@ -use cosmwasm_std::testing::{ - mock_dependencies_with_balance, mock_env, mock_info, MockApi, MockStorage, MOCK_CONTRACT_ADDR, -}; -use cosmwasm_std::{ - attr, coin, from_binary, to_binary, Api, CanonicalAddr, Coin, CosmosMsg, Decimal, OwnedDeps, - Reply, ReplyOn, Response, SubMsg, SubMsgResponse, SubMsgResult, Uint128, WasmMsg, -}; - -use white_whale_std::fee::Fee; -use white_whale_std::pool_network; -use white_whale_std::pool_network::asset::{ - AssetInfo, AssetInfoRaw, PairInfo, PairInfoRaw, PairType, -}; -use white_whale_std::pool_network::factory::{ - ConfigResponse, ExecuteMsg, InstantiateMsg, MigrateMsg, NativeTokenDecimalsResponse, QueryMsg, -}; -use white_whale_std::pool_network::mock_querier::{ - mock_dependencies, mock_dependencies_trio, WasmMockQuerier, WasmMockTrioQuerier, -}; -use white_whale_std::pool_network::pair::{ - InstantiateMsg as PairInstantiateMsg, MigrateMsg as PairMigrateMsg, PoolFee, -}; -use white_whale_std::pool_network::trio::{ - InstantiateMsg as TrioInstantiateMsg, MigrateMsg as TrioMigrateMsg, PoolFee as TrioPoolFee, -}; - -use crate::contract::{execute, instantiate, query}; -use crate::error::ContractError; -use crate::state::{pair_key, PAIRS}; -use test_case::test_case; -use white_whale_std::pool_manager::InstantiateMsg as SingleSwapInstantiateMsg; -#[cfg(test)] -mod pair_creation_tests { - use super::*; - use crate::tests::mock_querier::mock_dependencies; - use cosmwasm_std::testing::{mock_env, mock_info}; - use cosmwasm_std::{coin, coins, Binary, Decimal, DepsMut, Uint128}; - use cw20::MinterResponse; - use white_whale_std::pool_network::asset::Asset; - - // use crate::msg::{AssetInfo, ExecuteMsg, Fee, PairType, PoolFee}; - use crate::state::add_allow_native_token; - use crate::token::InstantiateMsg as TokenInstantiateMsg; - use cosmwasm_std::attr; - use cosmwasm_std::SubMsg; - use cosmwasm_std::WasmMsg; - use test_case::test_case; - use white_whale_std::pool_manager::ExecuteMsg; - use white_whale_std::pool_network::pair; - - // Constants for testing - const MOCK_CONTRACT_ADDR: &str = "contract_addr"; - - #[test] - fn create_pair() { - let mut deps = mock_dependencies(&[coin(10u128, "uusd".to_string())]); - // Instantiate contract - let msg = SingleSwapInstantiateMsg { - fee_collector_addr: "fee_collector_addr".to_string(), - owner: "owner".to_string(), - pair_code_id: 10u64, - token_code_id: 11u64, - pool_creation_fee: Asset { - amount: Uint128::new(1000000u128), - info: AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - }, - }; - let env = mock_env(); - let info = mock_info("owner", &[]); - let res = instantiate(deps.as_mut(), env, info, msg).unwrap(); - assert_eq!(0, res.messages.len()); - deps.querier - .with_pool_factory(&[], &[("uusd".to_string(), 6u8)]); - deps.querier.with_token_balances(&[( - &"asset0001".to_string(), - &[(&"addr0000".to_string(), &Uint128::new(1000000u128))], - )]); - let asset_infos = [ - AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - AssetInfo::Token { - contract_addr: "asset0001".to_string(), - }, - ]; - - let msg = ExecuteMsg::CreatePair { - asset_infos: asset_infos.to_vec(), - pool_fees: PoolFee { - protocol_fee: Fee { - share: Decimal::percent(1u64), - }, - swap_fee: Fee { - share: Decimal::percent(1u64), - }, - burn_fee: Fee { - share: Decimal::zero(), - }, - }, - pair_type: PairType::ConstantProduct, - token_factory_lp: false, - pair_identifier: Some("uusd-mAAPL".to_string()), - }; - - let env = mock_env(); - let info = mock_info( - "addr0000", - &[Coin { - denom: "uusd".to_string(), - amount: Uint128::new(1000000u128), - }], - ); - let res = execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap(); - assert_eq!( - res.attributes, - vec![ - attr("action", "create_pair"), - attr("pair", "uusd-mAAPL"), - attr("pair_label", "uusd-mAAPL"), - attr("pair_type", "ConstantProduct"), - ] - ); - let seed = format!( - "{}{}{}", - "uusd-mAAPL".to_string(), - info.sender.into_string(), - env.block.height - ); - let salt = Binary::from(seed.as_bytes()); - - assert_eq!( - res.messages, - vec![SubMsg { - id: 0, - gas_limit: None, - reply_on: ReplyOn::Never, - msg: WasmMsg::Instantiate2 { - msg: to_binary(&TokenInstantiateMsg { - name: "uusd-mAAPL-LP".to_string(), - symbol: "uLP".to_string(), - decimals: 6, - initial_balances: vec![], - mint: Some(MinterResponse { - minter: env.contract.address.to_string(), - cap: None, - }), - }) - .unwrap(), - code_id: 11u64, - funds: vec![], - label: "uusd-mAAPL-LP".to_string(), - admin: None, - salt - } - .into(), - },] - ); - } - - #[test] - fn create_stableswap_pair() { - let mut deps = mock_dependencies(&[coin(10u128, "uusd".to_string())]); - // deps.api = Box::new(MockApi::default()); - // Instantiate contract - let msg = SingleSwapInstantiateMsg { - fee_collector_addr: "fee_collector_addr".to_string(), - owner: "owner".to_string(), - pair_code_id: 10u64, - token_code_id: 11u64, - pool_creation_fee: Asset { - amount: Uint128::new(1000000u128), - info: AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - }, - }; - let env = mock_env(); - let info = mock_info("owner", &[]); - let res = instantiate(deps.as_mut(), env, info, msg).unwrap(); - assert_eq!(0, res.messages.len()); - - deps.querier - .with_pool_factory(&[], &[("uusd".to_string(), 6u8)]); - deps.querier.with_token_balances(&[( - &"asset0001".to_string(), - &[(&"addr0000".to_string(), &Uint128::new(1000000u128))], - )]); - - let asset_infos = [ - AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - AssetInfo::Token { - contract_addr: "asset0001".to_string(), - }, - ]; - - let msg = ExecuteMsg::CreatePair { - asset_infos: asset_infos.to_vec(), - pool_fees: PoolFee { - protocol_fee: Fee { - share: Decimal::percent(1u64), - }, - swap_fee: Fee { - share: Decimal::percent(1u64), - }, - burn_fee: Fee { - share: Decimal::zero(), - }, - }, - pair_type: PairType::StableSwap { amp: 100 }, - token_factory_lp: false, - pair_identifier: Some("uusd-mAAPL".to_string()), - }; - - let env = mock_env(); - let info = mock_info( - "addr0000", - &[Coin { - denom: "uusd".to_string(), - amount: Uint128::new(1000000u128), - }], - ); - let res = execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap(); - let seed = format!( - "{}{}{}", - "uusd-mAAPL".to_string(), - info.sender.into_string(), - env.block.height - ); - let salt = Binary::from(seed.as_bytes()); - assert_eq!( - res.attributes, - vec![ - attr("action", "create_pair"), - attr("pair", "uusd-mAAPL"), - attr("pair_label", "uusd-mAAPL"), - attr("pair_type", "StableSwap"), - ] - ); - - assert_eq!( - res.messages, - vec![SubMsg { - id: 0, - gas_limit: None, - reply_on: ReplyOn::Never, - msg: WasmMsg::Instantiate2 { - msg: to_binary(&TokenInstantiateMsg { - name: "uusd-mAAPL-LP".to_string(), - symbol: "uLP".to_string(), - decimals: 6, - initial_balances: vec![], - mint: Some(MinterResponse { - minter: env.contract.address.to_string(), - cap: None, - }), - }) - .unwrap(), - code_id: 11u64, - funds: vec![], - label: "uusd-mAAPL-LP".to_string(), - admin: None, - salt - } - .into(), - },] - ); - } - - #[test] - fn create_pair_native_token_and_ibc_token() { - let mut deps = mock_dependencies(&[ - coin(10u128, "uusd".to_string()), - coin( - 10u128, - "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2".to_string(), - ), - ]); - - // Instantiate contract - let msg = SingleSwapInstantiateMsg { - fee_collector_addr: "fee_collector_addr".to_string(), - owner: "owner".to_string(), - pair_code_id: 10u64, - token_code_id: 11u64, - pool_creation_fee: Asset { - amount: Uint128::new(1000000u128), - info: AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - }, - }; - let env = mock_env(); - let info = mock_info("owner", &[]); - let res = instantiate(deps.as_mut(), env, info, msg).unwrap(); - assert_eq!(0, res.messages.len()); - - deps.querier.with_pool_factory( - &[], - &[ - ("uusd".to_string(), 6u8), - ( - "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2" - .to_string(), - 6u8, - ), - ], - ); - deps.querier.with_token_balances(&[( - &"asset0001".to_string(), - &[(&"addr0000".to_string(), &Uint128::new(1000000u128))], - )]); - - // deps = init(deps); - // deps.querier.with_pool_factory( - // &[], - // &[ - // ("uusd".to_string(), 6u8), - // ( - // "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2".to_string(), - // 6u8, - // ), - // ], - // ); - - let asset_infos = [ - AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - AssetInfo::NativeToken { - denom: "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2" - .to_string(), - }, - ]; - - let msg = ExecuteMsg::CreatePair { - asset_infos: asset_infos.to_vec(), - pool_fees: PoolFee { - protocol_fee: Fee { - share: Decimal::percent(1u64), - }, - swap_fee: Fee { - share: Decimal::percent(1u64), - }, - burn_fee: Fee { - share: Decimal::zero(), - }, - }, - pair_type: PairType::ConstantProduct, - token_factory_lp: false, - pair_identifier: None, - }; - - let env = mock_env(); - let info = mock_info( - "addr0000", - &[Coin { - denom: "uusd".to_string(), - amount: Uint128::new(1000000u128), - }], - ); - let res = execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap(); - assert_eq!( - res.attributes, - vec![ - attr("action", "create_pair"), - attr("pair", "uusd-ibc/2739...5EB2"), - attr("pair_label", "uusd-ibc/2739...5EB2"), - attr("pair_type", "ConstantProduct"), - ] - ); - let seed = format!( - "{}{}{}", - "uusd-ibc/2739...5EB2".to_string(), - info.sender.into_string(), - env.block.height - ); - let salt = Binary::from(seed.as_bytes()); - assert_eq!( - res.messages, - vec![SubMsg { - id: 0, - gas_limit: None, - reply_on: ReplyOn::Never, - msg: WasmMsg::Instantiate2 { - msg: to_binary(&TokenInstantiateMsg { - name: "uusd-ibc/2739...5EB2-LP".to_string(), - symbol: "uLP".to_string(), - decimals: 6, - initial_balances: vec![], - mint: Some(MinterResponse { - minter: env.contract.address.to_string(), - cap: None, - }), - }) - .unwrap(), - code_id: 11u64, - funds: vec![], - label: "uusd-ibc/2739...5EB2-LP".to_string(), - admin: None, - salt - } - .into(), - },] - ); - } - - #[test] - fn create_ibc_tokens_pair() { - let mut deps = mock_dependencies(&[ - coin( - 10u128, - "ibc/4CD525F166D32B0132C095F353F4C6F033B0FF5C49141470D1EFDA1D63303D04".to_string(), - ), - coin( - 10u128, - "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2".to_string(), - ), - ]); - let pair_creation_fee = Asset { - amount: Uint128::new(1000000u128), - info: AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - }; - - // Instantiate contract - let msg = SingleSwapInstantiateMsg { - fee_collector_addr: "fee_collector_addr".to_string(), - owner: "owner".to_string(), - pair_code_id: 10u64, - token_code_id: 11u64, - pool_creation_fee: pair_creation_fee.clone(), - }; - let env = mock_env(); - let info = mock_info("owner", &[]); - let res = instantiate(deps.as_mut(), env, info, msg).unwrap(); - assert_eq!(0, res.messages.len()); - - // deps = init(deps); - deps.querier.with_pool_factory( - &[], - &[ - ( - "ibc/4CD525F166D32B0132C095F353F4C6F033B0FF5C49141470D1EFDA1D63303D04" - .to_string(), - 6u8, - ), - ( - "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2" - .to_string(), - 6u8, - ), - ], - ); - - let asset_infos = [ - AssetInfo::NativeToken { - denom: "ibc/4CD525F166D32B0132C095F353F4C6F033B0FF5C49141470D1EFDA1D63303D04" - .to_string(), - }, - AssetInfo::NativeToken { - denom: "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2" - .to_string(), - }, - ]; - - let msg = ExecuteMsg::CreatePair { - asset_infos: asset_infos.to_vec(), - pool_fees: PoolFee { - protocol_fee: Fee { - share: Decimal::percent(1u64), - }, - swap_fee: Fee { - share: Decimal::percent(1u64), - }, - burn_fee: Fee { - share: Decimal::zero(), - }, - }, - pair_type: PairType::ConstantProduct, - token_factory_lp: false, - pair_identifier: None, - }; - - let env = mock_env(); - let info = mock_info("addr0000", &[coin(1000000u128, "uusd".to_string())]); - let res = execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap(); - assert_eq!( - res.attributes, - vec![ - attr("action", "create_pair"), - attr("pair", "ibc/4CD5...3D04-ibc/2739...5EB2"), - attr("pair_label", "ibc/4CD5...3D04-ibc/2739...5EB2"), - attr("pair_type", "ConstantProduct"), - ] - ); - let seed = format!( - "{}{}{}", - "ibc/4CD5...3D04-ibc/2739...5EB2".to_string(), - info.sender.into_string(), - env.block.height - ); - let salt = Binary::from(seed.as_bytes()); - assert_eq!( - res.messages, - vec![SubMsg { - id: 0, - gas_limit: None, - reply_on: ReplyOn::Never, - msg: WasmMsg::Instantiate2 { - msg: to_binary(&TokenInstantiateMsg { - name: "ibc/4CD5...3D04-ibc/2739...5EB2-LP".to_string(), - symbol: "uLP".to_string(), - decimals: 6, - initial_balances: vec![], - mint: Some(MinterResponse { - minter: env.contract.address.to_string(), - cap: None, - }), - }) - .unwrap(), - code_id: 11u64, - funds: vec![], - label: "ibc/4CD5...3D04-ibc/2739...5EB2-LP".to_string(), - admin: None, - salt - } - .into(), - },] - ); - } - - #[test_case( - AssetInfo::NativeToken { denom: "uusd".to_string() }, - AssetInfo::NativeToken { denom: "uusd".to_string() }, - ContractError::SameAsset { } ; - "fail_to_create_same_pair" - )] - #[test_case( - AssetInfo::NativeToken { denom: "uusd".to_string() }, - AssetInfo::Token { contract_addr: "asset0001".to_string() }, - ContractError::ExistingPair { } ; - "fail_to_create_existing_pair" - )] - #[test_case( - AssetInfo::NativeToken { denom: "uusd".to_string() }, - AssetInfo::NativeToken { denom: "uxxx".to_string() }, - ContractError::Std(cosmwasm_std::StdError::generic_err("Querier system error: Cannot parse request: No decimal info exist in: {\"native_token_decimals\":{\"denom\":\"uxxx\"}}".to_string())) ; - "fail_to_create_pair_with_inactive_denoms" - )] - fn test_failures(asset1: AssetInfo, asset2: AssetInfo, expected_error: ContractError) { - let mut deps = mock_dependencies(&[coin(10000000u128, "uusd".to_string())]); - // deps = init(deps); - // Instantiate contract - let msg = SingleSwapInstantiateMsg { - fee_collector_addr: "fee_collector_addr".to_string(), - owner: "owner".to_string(), - pair_code_id: 10u64, - token_code_id: 11u64, - pool_creation_fee: Asset { - amount: Uint128::new(1000000u128), - info: AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - }, - }; - let env = mock_env(); - let info = mock_info("owner", &[]); - let res = instantiate(deps.as_mut(), env, info, msg).unwrap(); - assert_eq!(0, res.messages.len()); - - deps.querier - .with_pool_factory(&[], &[("uusd".to_string(), 6u8)]); - deps.querier.with_token_balances(&[( - &"asset0001".to_string(), - &[(&"addr0000".to_string(), &Uint128::new(1000000u128))], - )]); - let msg = white_whale_std::pool_manager::ExecuteMsg::CreatePair { - asset_infos: [asset1, asset2].to_vec(), - pool_fees: PoolFee { - protocol_fee: Fee { - share: Decimal::percent(1u64), - }, - swap_fee: Fee { - share: Decimal::percent(1u64), - }, - burn_fee: Fee { - share: Decimal::zero(), - }, - }, - pair_type: PairType::ConstantProduct, - token_factory_lp: false, - pair_identifier: None, - }; - - let env = mock_env(); - let info = mock_info( - "addr0000", - &[Coin { - denom: "uusd".to_string(), - amount: Uint128::new(1000000u128), - }], - ); - - if let ContractError::ExistingPair { .. } = expected_error { - // Create the pair so when we try again below we get ExistingPair provided the error checking is behaving properly - let res = execute(deps.as_mut(), env.clone(), info.clone(), msg.clone()); - } - - let res = execute(deps.as_mut(), env, info, msg); - match res { - Ok(_) => panic!("Should return expected error"), - Err(err) => assert_eq!(err, expected_error), - } - } -} diff --git a/contracts/liquidity_hub/pool-manager/src/tests/unit_tests/provide_liquidity.rs b/contracts/liquidity_hub/pool-manager/src/tests/unit_tests/provide_liquidity.rs deleted file mode 100644 index a740287d4..000000000 --- a/contracts/liquidity_hub/pool-manager/src/tests/unit_tests/provide_liquidity.rs +++ /dev/null @@ -1,941 +0,0 @@ -use cosmwasm_std::testing::{mock_env, mock_info, MOCK_CONTRACT_ADDR}; -use cosmwasm_std::{ - attr, to_binary, Coin, CosmosMsg, Decimal, Reply, Response, StdError, SubMsg, SubMsgResponse, - SubMsgResult, Uint128, WasmMsg, -}; -#[cfg(feature = "token_factory")] -use cosmwasm_std::{coin, BankMsg}; -use cw20::Cw20ExecuteMsg; -use white_whale_std::fee::Fee; -#[cfg(feature = "token_factory")] -use white_whale_std::lp_common::LP_SYMBOL; - -use crate::tests::mock_querier::mock_dependencies; -#[cfg(feature = "token_factory")] -use white_whale_std::pool_network; -use white_whale_std::pool_network::asset::{Asset, AssetInfo, PairType, MINIMUM_LIQUIDITY_AMOUNT}; -#[cfg(feature = "token_factory")] -use white_whale_std::pool_network::denom::MsgMint; -use white_whale_std::pool_network::pair::PoolFee; -// use white_whale_std::pool_network::pair::{ExecuteMsg, InstantiateMsg, PoolFee}; -use crate::contract::{execute, instantiate}; -use crate::error::ContractError; -use white_whale_std::pool_manager::ExecuteMsg; -use white_whale_std::pool_manager::InstantiateMsg as SingleSwapInstantiateMsg; -#[test] -fn provide_liquidity_cw20_lp() { - let mut deps = mock_dependencies(&[Coin { - denom: "uusd".to_string(), - amount: Uint128::from(2_000u128), - }]); - - // Note: In order to support and write tests sooner I override the MockAPI in mock_querier with a SimpleMockAPI - // The effect is I can continue testing with instantiate2 but now an addr like liquidity0000 becomes TEMP_CONTRACT_ADDR - // This likely breaks tests elsewhere - let TEMP_CONTRACT_ADDR: String = - "4j®Q¶õ\u{1c}¼\u{f}º\u{8d}N\u{7}Sȶö\u{7}©³8\u{7f}j¼Þp\u{9c}\u{1b}æù\u{a0}î".to_string(); - - deps.querier.with_token_balances(&[ - ( - &TEMP_CONTRACT_ADDR.clone(), - &[(&MOCK_CONTRACT_ADDR.to_string(), &Uint128::zero())], - ), - ( - &"asset0000".to_string(), - &[(&"addr0000".to_string(), &Uint128::from(100u128))], - ), - ]); - deps.querier - .with_pool_factory(&[], &[("uusd".to_string(), 6u8)]); - - // Instantiate contract - let msg = SingleSwapInstantiateMsg { - fee_collector_addr: "fee_collector_addr".to_string(), - owner: "owner".to_string(), - pair_code_id: 10u64, - token_code_id: 11u64, - pool_creation_fee: Asset { - amount: Uint128::new(1000000u128), - info: AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - }, - }; - let env = mock_env(); - let info = mock_info("owner", &[]); - let res = instantiate(deps.as_mut(), env, info, msg).unwrap(); - assert_eq!(0, res.messages.len()); - - // Create the Pair - let asset_infos = [ - AssetInfo::Token { - contract_addr: "asset0000".to_string(), - }, - AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - ]; - - let msg = ExecuteMsg::CreatePair { - asset_infos: asset_infos.to_vec(), - pool_fees: PoolFee { - protocol_fee: Fee { - share: Decimal::percent(1u64), - }, - swap_fee: Fee { - share: Decimal::percent(1u64), - }, - burn_fee: Fee { - share: Decimal::zero(), - }, - }, - pair_type: PairType::ConstantProduct, - token_factory_lp: false, - pair_identifier: None, - }; - - let env = mock_env(); - - let info = mock_info( - "addr0000", - &[Coin { - denom: "uusd".to_string(), - amount: Uint128::new(1000000u128), - }], - ); - - let res = execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap(); - - // unsuccessfully providing liquidity since share becomes zero, MINIMUM_LIQUIDITY_AMOUNT provided - let msg = ExecuteMsg::ProvideLiquidity { - assets: [ - Asset { - info: AssetInfo::Token { - contract_addr: "asset0000".to_string(), - }, - amount: MINIMUM_LIQUIDITY_AMOUNT, - }, - Asset { - info: AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - amount: MINIMUM_LIQUIDITY_AMOUNT, - }, - ] - .to_vec(), - slippage_tolerance: None, - receiver: None, - pair_identifier: "0".to_string(), - }; - - let env = mock_env(); - let info = mock_info( - "addr0000", - &[Coin { - denom: "uusd".to_string(), - amount: MINIMUM_LIQUIDITY_AMOUNT, - }], - ); - let res = execute(deps.as_mut(), env, info, msg).unwrap_err(); - match res { - ContractError::InvalidInitialLiquidityAmount { .. } => {} - _ => { - println!("{:?}", res); - panic!("should return ContractError::InvalidInitialLiquidityAmount") - } - } - - // successfully provide liquidity for the exist pool - let msg = ExecuteMsg::ProvideLiquidity { - assets: [ - Asset { - info: AssetInfo::Token { - contract_addr: "asset0000".to_string(), - }, - amount: Uint128::from(2_000u128), - }, - Asset { - info: AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - amount: Uint128::from(2_000u128), - }, - ] - .to_vec(), - slippage_tolerance: None, - receiver: None, - pair_identifier: "0".to_string(), - }; - - let env = mock_env(); - let info = mock_info( - "addr0000", - &[Coin { - denom: "uusd".to_string(), - amount: Uint128::from(2_000u128), - }], - ); - let res = execute(deps.as_mut(), env, info, msg).unwrap(); - - assert_eq!(res.messages.len(), 2usize); - - let transfer_from_msg = res.messages.get(0).expect("no message"); - let mint_initial_lp_msg = res.messages.get(1).expect("no message"); - let mint_msg = res.messages.get(2).expect("no message"); - assert_eq!( - transfer_from_msg, - &SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: "asset0000".to_string(), - msg: to_binary(&Cw20ExecuteMsg::TransferFrom { - owner: "addr0000".to_string(), - recipient: MOCK_CONTRACT_ADDR.to_string(), - amount: Uint128::from(2_000u128), - }) - .unwrap(), - funds: vec![], - })) - ); - assert_eq!( - mint_initial_lp_msg, - &SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: TEMP_CONTRACT_ADDR.clone(), - msg: to_binary(&Cw20ExecuteMsg::Mint { - recipient: "cosmos2contract".to_string(), - amount: MINIMUM_LIQUIDITY_AMOUNT, - }) - .unwrap(), - funds: vec![], - })) - ); - assert_eq!( - mint_msg, - &SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: TEMP_CONTRACT_ADDR.clone(), - msg: to_binary(&Cw20ExecuteMsg::Transfer { - recipient: "addr0000".to_string(), - amount: MINIMUM_LIQUIDITY_AMOUNT, - }) - .unwrap(), - funds: vec![], - })) - ); - - // provide more liquidity 1:2, which is not proportional to 1:1, - // then it must accept 1:1 and treat left amount as donation - deps.querier.with_balance(&[( - &MOCK_CONTRACT_ADDR.to_string(), - vec![Coin { - denom: "uusd".to_string(), - amount: Uint128::from( - 200u128 + 200u128, /* user deposit must be pre-applied */ - ), - }], - )]); - - deps.querier.with_token_balances(&[ - ( - &TEMP_CONTRACT_ADDR.to_string(), - &[(&MOCK_CONTRACT_ADDR.to_string(), &Uint128::from(100u128))], - ), - ( - &"asset0000".to_string(), - &[(&MOCK_CONTRACT_ADDR.to_string(), &Uint128::from(200u128))], - ), - ]); - - let msg = ExecuteMsg::ProvideLiquidity { - assets: [ - Asset { - info: AssetInfo::Token { - contract_addr: "asset0000".to_string(), - }, - amount: Uint128::from(100u128), - }, - Asset { - info: AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - amount: Uint128::from(200u128), - }, - ] - .to_vec(), - slippage_tolerance: None, - receiver: Some("staking0000".to_string()), // try changing receiver - pair_identifier: 1.to_string(), - }; - - let env = mock_env(); - let info = mock_info( - "addr0000", - &[Coin { - denom: "uusd".to_string(), - amount: Uint128::from(200u128), - }], - ); - - // only accept 100, then 50 share will be generated with 100 * (100 / 200) - let res: Response = execute(deps.as_mut(), env, info, msg).unwrap(); - assert_eq!(res.messages.len(), 3usize); - - let transfer_from_msg = res.messages.get(0).expect("no message"); - let mint_msg = res.messages.get(1).expect("no message"); - assert_eq!( - transfer_from_msg, - &SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: "asset0000".to_string(), - msg: to_binary(&Cw20ExecuteMsg::TransferFrom { - owner: "addr0000".to_string(), - recipient: MOCK_CONTRACT_ADDR.to_string(), - amount: Uint128::from(200u128), - }) - .unwrap(), - funds: vec![], - })) - ); - assert_eq!( - mint_msg, - &SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: TEMP_CONTRACT_ADDR.to_string(), - msg: to_binary(&Cw20ExecuteMsg::Mint { - recipient: "cosmos2contract".to_string(), // LP tokens sent to specified receiver - amount: Uint128::from(33u128), - }) - .unwrap(), - funds: vec![], - })) - ); - - // check wrong argument - let msg = ExecuteMsg::ProvideLiquidity { - assets: [ - Asset { - info: AssetInfo::Token { - contract_addr: "asset0000".to_string(), - }, - amount: Uint128::from(100u128), - }, - Asset { - info: AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - amount: Uint128::from(50u128), - }, - ] - .to_vec(), - slippage_tolerance: None, - receiver: None, - pair_identifier: 1.to_string(), - }; - - let env = mock_env(); - let info = mock_info( - "addr0000", - &[Coin { - denom: "uusd".to_string(), - amount: Uint128::from(100u128), - }], - ); - let res = execute(deps.as_mut(), env, info, msg).unwrap_err(); - match res { - ContractError::Std(StdError::GenericErr { msg, .. }) => assert_eq!( - msg, - "Native token balance mismatch between the argument and the transferred".to_string() - ), - _ => { - panic!("Must return generic error"); - } - } - - // initialize token balance to 1:1 - deps.querier.with_balance(&[( - &MOCK_CONTRACT_ADDR.to_string(), - vec![Coin { - denom: "uusd".to_string(), - amount: Uint128::from( - 100u128 + 100u128, /* user deposit must be pre-applied */ - ), - }], - )]); - - deps.querier.with_token_balances(&[ - ( - &"liquidity0000".to_string(), - &[(&MOCK_CONTRACT_ADDR.to_string(), &Uint128::from(100u128))], - ), - ( - &"asset0000".to_string(), - &[(&MOCK_CONTRACT_ADDR.to_string(), &Uint128::from(200u128))], - ), - ]); - - // failed because the price is under slippage_tolerance - let msg = ExecuteMsg::ProvideLiquidity { - assets: [ - Asset { - info: AssetInfo::Token { - contract_addr: "asset0000".to_string(), - }, - amount: Uint128::from(98u128), - }, - Asset { - info: AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - amount: Uint128::from(100u128), - }, - ] - .to_vec(), - slippage_tolerance: Some(Decimal::percent(1)), - receiver: None, - pair_identifier: 1.to_string(), - }; - - let env = mock_env(); - let info = mock_info( - "addr0001", - &[Coin { - denom: "uusd".to_string(), - amount: Uint128::from(100u128), - }], - ); - - deps.querier.with_token_balances(&[ - ( - &TEMP_CONTRACT_ADDR.to_string(), - &[(&MOCK_CONTRACT_ADDR.to_string(), &Uint128::from(100u128))], - ), - ( - &"asset0000".to_string(), - &[(&MOCK_CONTRACT_ADDR.to_string(), &Uint128::from(100u128))], - ), - ]); - let res = execute(deps.as_mut(), env, info, msg).unwrap_err(); - match res { - ContractError::MaxSlippageAssertion {} => {} - _ => panic!("DO NOT ENTER HERE"), - } - - // initialize token balance to 1:1 - deps.querier.with_balance(&[( - &MOCK_CONTRACT_ADDR.to_string(), - vec![Coin { - denom: "uusd".to_string(), - amount: Uint128::from(100u128 + 98u128 /* user deposit must be pre-applied */), - }], - )]); - - // failed because the price is under slippage_tolerance - let msg = ExecuteMsg::ProvideLiquidity { - assets: [ - Asset { - info: AssetInfo::Token { - contract_addr: "asset0000".to_string(), - }, - amount: Uint128::from(100u128), - }, - Asset { - info: AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - amount: Uint128::from(98u128), - }, - ] - .to_vec(), - slippage_tolerance: Some(Decimal::percent(1)), - receiver: None, - pair_identifier: 1.to_string(), - }; - - let env = mock_env(); - let info = mock_info( - "addr0001", - &[Coin { - denom: "uusd".to_string(), - amount: Uint128::from(98u128), - }], - ); - let res = execute(deps.as_mut(), env, info, msg).unwrap_err(); - match res { - ContractError::MaxSlippageAssertion {} => {} - _ => panic!("DO NOT ENTER HERE"), - } - - // initialize token balance to 1:1 - deps.querier.with_balance(&[( - &MOCK_CONTRACT_ADDR.to_string(), - vec![Coin { - denom: "uusd".to_string(), - amount: Uint128::from( - 100u128 + 100u128, /* user deposit must be pre-applied */ - ), - }], - )]); - - deps.querier.with_token_balances(&[ - ( - &TEMP_CONTRACT_ADDR.clone(), - &[(&MOCK_CONTRACT_ADDR.to_string(), &Uint128::from(100u128))], - ), - ( - &"asset0000".to_string(), - &[ - (&"addr0001".to_string(), &Uint128::from(100u128)), - (&MOCK_CONTRACT_ADDR.to_string(), &Uint128::from(100u128)), - ], - ), - ]); - - // successfully provides - let msg = ExecuteMsg::ProvideLiquidity { - assets: [ - Asset { - info: AssetInfo::Token { - contract_addr: "asset0000".to_string(), - }, - amount: Uint128::from(99u128), - }, - Asset { - info: AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - amount: Uint128::from(100u128), - }, - ] - .to_vec(), - slippage_tolerance: Some(Decimal::percent(2)), - receiver: None, - pair_identifier: 1.to_string(), - }; - - let env = mock_env(); - let info = mock_info( - "addr0001", - &[Coin { - denom: "uusd".to_string(), - amount: Uint128::from(100u128), - }], - ); - let _res = execute(deps.as_mut(), env, info, msg).unwrap(); - - // initialize token balance to 1:1 - deps.querier.with_balance(&[( - &MOCK_CONTRACT_ADDR.to_string(), - vec![Coin { - denom: "uusd".to_string(), - amount: Uint128::from(100u128 + 99u128 /* user deposit must be pre-applied */), - }], - )]); - - // successfully provides - let msg = ExecuteMsg::ProvideLiquidity { - assets: [ - Asset { - info: AssetInfo::Token { - contract_addr: "asset0000".to_string(), - }, - amount: Uint128::from(100u128), - }, - Asset { - info: AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - amount: Uint128::from(99u128), - }, - ] - .to_vec(), - slippage_tolerance: Some(Decimal::percent(2)), - receiver: None, - pair_identifier: 1.to_string(), - }; - - let env = mock_env(); - let info = mock_info( - "addr0001", - &[Coin { - denom: "uusd".to_string(), - amount: Uint128::from(99u128), - }], - ); - let _res = execute(deps.as_mut(), env, info, msg).unwrap(); -} - -#[test] -fn provide_liquidity_zero_amount() { - let mut deps = mock_dependencies(&[Coin { - denom: "uusd".to_string(), - amount: Uint128::from(2_000u128), - }]); - - // Note: In order to support and write tests sooner I override the MockAPI in mock_querier with a SimpleMockAPI - // The effect is I can continue testing with instantiate2 but now an addr like liquidity0000 becomes TEMP_CONTRACT_ADDR - // This likely breaks tests elsewhere - let TEMP_CONTRACT_ADDR: String = - "contract757573642d6d4141504c61646472303030303132333435".to_string(); - - deps.querier.with_token_balances(&[ - ( - &TEMP_CONTRACT_ADDR.clone(), - &[(&MOCK_CONTRACT_ADDR.to_string(), &Uint128::zero())], - ), - (&"asset0000".to_string(), &[]), - ]); - - deps.querier - .with_pool_factory(&[], &[("uusd".to_string(), 6u8)]); - - // Instantiate contract - let msg = SingleSwapInstantiateMsg { - fee_collector_addr: "fee_collector_addr".to_string(), - owner: "owner".to_string(), - pair_code_id: 10u64, - token_code_id: 11u64, - pool_creation_fee: Asset { - amount: Uint128::new(1000000u128), - info: AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - }, - }; - let env = mock_env(); - let info = mock_info("owner", &[]); - let res = instantiate(deps.as_mut(), env, info, msg).unwrap(); - assert_eq!(0, res.messages.len()); - - // Create the Pair - let asset_infos = [ - AssetInfo::Token { - contract_addr: "asset0000".to_string(), - }, - AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - ]; - - let msg = ExecuteMsg::CreatePair { - asset_infos: asset_infos.to_vec(), - pool_fees: PoolFee { - protocol_fee: Fee { - share: Decimal::percent(1u64), - }, - swap_fee: Fee { - share: Decimal::percent(1u64), - }, - burn_fee: Fee { - share: Decimal::zero(), - }, - }, - pair_type: PairType::ConstantProduct, - token_factory_lp: false, - pair_identifier: None, - }; - - let env = mock_env(); - - let info = mock_info( - "addr0000", - &[Coin { - denom: "uusd".to_string(), - amount: Uint128::new(1000000u128), - }], - ); - - let res = execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap(); - - // Instantiate contract - let msg = SingleSwapInstantiateMsg { - fee_collector_addr: "fee_collector_addr".to_string(), - owner: "owner".to_string(), - pair_code_id: 10u64, - token_code_id: 11u64, - pool_creation_fee: Asset { - amount: Uint128::new(1000000u128), - info: AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - }, - }; - let env = mock_env(); - let info = mock_info("owner", &[]); - let res = instantiate(deps.as_mut(), env, info, msg).unwrap(); - assert_eq!(0, res.messages.len()); - - // provide invalid (zero) liquidity - let msg = ExecuteMsg::ProvideLiquidity { - assets: [ - Asset { - info: AssetInfo::Token { - contract_addr: "asset0000".to_string(), - }, - amount: Uint128::zero(), - }, - Asset { - info: AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - amount: Uint128::from(100u128), - }, - ] - .to_vec(), - slippage_tolerance: None, - receiver: None, - pair_identifier: "0".to_string(), - }; - - let env = mock_env(); - let info = mock_info( - "addr0000", - &[Coin { - denom: "uusd".to_string(), - amount: Uint128::from(100u128), - }], - ); - let res = execute(deps.as_mut(), env, info, msg); - - match res { - Ok(_) => panic!("should return ContractError::InvalidZeroAmount"), - Err(ContractError::InvalidZeroAmount {}) => {} - _ => { - panic!("should return ContractError::InvalidZeroAmount") - } - } -} - -#[test] -fn provide_liquidity_invalid_minimum_lp_amount() { - let mut deps = mock_dependencies(&[Coin { - denom: "uusd".to_string(), - amount: Uint128::from(999u128), - }]); - - // Note: In order to support and write tests sooner I override the MockAPI in mock_querier with a SimpleMockAPI - // The effect is I can continue testing with instantiate2 but now an addr like liquidity0000 becomes TEMP_CONTRACT_ADDR - // This likely breaks tests elsewhere - let TEMP_CONTRACT_ADDR: String = - "contract6d4141504c2d7575736461646472303030303132333435".to_string(); - - deps.querier.with_token_balances(&[ - ( - &TEMP_CONTRACT_ADDR.to_string(), - &[(&MOCK_CONTRACT_ADDR.to_string(), &Uint128::zero())], - ), - (&"asset0001".to_string(), &[]), - ]); - deps.querier - .with_pool_factory(&[], &[("uusd".to_string(), 6u8)]); - - // Instantiate contract - let msg = SingleSwapInstantiateMsg { - fee_collector_addr: "fee_collector_addr".to_string(), - owner: "owner".to_string(), - pair_code_id: 10u64, - token_code_id: 11u64, - pool_creation_fee: Asset { - amount: Uint128::new(1000000u128), - info: AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - }, - }; - let env = mock_env(); - let info = mock_info("owner", &[]); - let res = instantiate(deps.as_mut(), env, info, msg).unwrap(); - assert_eq!(0, res.messages.len()); - - let asset_infos = [ - AssetInfo::Token { - contract_addr: "asset0001".to_string(), - }, - AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - ]; - - let msg = ExecuteMsg::CreatePair { - asset_infos: asset_infos.to_vec(), - pool_fees: PoolFee { - protocol_fee: Fee { - share: Decimal::percent(1u64), - }, - swap_fee: Fee { - share: Decimal::percent(1u64), - }, - burn_fee: Fee { - share: Decimal::zero(), - }, - }, - pair_type: PairType::ConstantProduct, - token_factory_lp: false, - pair_identifier: None, - }; - - let env = mock_env(); - let info = mock_info( - "addr0000", - &[Coin { - denom: "uusd".to_string(), - amount: Uint128::new(1000000u128), - }], - ); - let res = execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap(); - assert_eq!( - res.attributes, - vec![ - attr("action", "create_pair"), - attr("pair", "mAAPL-uusd"), - attr("pair_label", "mAAPL-uusd"), - attr("pair_type", "ConstantProduct"), - ] - ); - - // successfully provide liquidity for the exist pool - let msg = ExecuteMsg::ProvideLiquidity { - assets: [ - Asset { - info: AssetInfo::Token { - contract_addr: "asset0001".to_string(), - }, - amount: (MINIMUM_LIQUIDITY_AMOUNT - Uint128::one()), - }, - Asset { - info: AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - amount: Uint128::from(100u128), - }, - ] - .to_vec(), - slippage_tolerance: None, - receiver: None, - pair_identifier: 1.to_string(), - }; - - let env = mock_env(); - let info = mock_info( - "addr0000", - &[Coin { - denom: "uusd".to_string(), - amount: Uint128::from(100u128), - }], - ); - let res = execute(deps.as_mut(), env, info, msg); - - match res { - Ok(_) => panic!("should return ContractError::InvalidInitialLiquidityAmount"), - Err(ContractError::InvalidInitialLiquidityAmount { .. }) => {} - e => { - println!("{:?}", e.unwrap()); - panic!("should return ContractError::InvalidInitialLiquidityAmount"); - } - } -} - -#[cfg(feature = "token_factory")] -#[test] -fn provide_liquidity_tokenfactory_lp() { - let lp_denom = format!("{}/{MOCK_CONTRACT_ADDR}/{LP_SYMBOL}", "factory"); - - let mut deps = mock_dependencies(&[ - Coin { - denom: "uusd".to_string(), - amount: Uint128::from(2_000u128), - }, - Coin { - denom: "uwhale".to_string(), - amount: Uint128::from(2_000u128), - }, - Coin { - denom: lp_denom.clone(), - amount: Uint128::zero(), - }, - ]); - - deps.querier - .with_token_balances(&[(&"asset0000".to_string(), &[])]); - - // Instantiate contract - let msg = SingleSwapInstantiateMsg { - fee_collector_addr: "fee_collector_addr".to_string(), - owner: "owner".to_string(), - pair_code_id: 10u64, - token_code_id: 11u64, - pool_creation_fee: vec![Asset { - amount: Uint128::new(1000000u128), - info: AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - }], - }; - let env = mock_env(); - let info = mock_info("owner", &[]); - let res = instantiate(deps.as_mut(), env, info, msg).unwrap(); - assert_eq!(0, res.messages.len()); - // successfully provide liquidity for the exist pool - let msg = ExecuteMsg::ProvideLiquidity { - assets: [ - Asset { - info: AssetInfo::NativeToken { - denom: "uwhale".to_string(), - }, - amount: Uint128::from(2_000u128), - }, - Asset { - info: AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - amount: Uint128::from(2_000u128), - }, - ] - .to_vec(), - slippage_tolerance: None, - receiver: None, - }; - - let env = mock_env(); - let info = mock_info( - "addr0000", - &[ - Coin { - denom: "uusd".to_string(), - amount: Uint128::from(2_000u128), - }, - Coin { - denom: "uwhale".to_string(), - amount: Uint128::from(2_000u128), - }, - ], - ); - let res = execute(deps.as_mut(), env, info, msg).unwrap(); - - assert_eq!(res.messages.len(), 3usize); - - let mint_initial_lp_msg = res.messages.get(0).expect("no message").clone().msg; - let mint_msg = res.messages.get(1).expect("no message").clone().msg; - let bank_send_msg = res.messages.get(2).expect("no message").clone().msg; - - let mint_initial_lp_msg_expected = >::into(MsgMint { - sender: MOCK_CONTRACT_ADDR.to_string(), - amount: Some(pool_network::denom::Coin { - denom: lp_denom.clone(), - amount: MINIMUM_LIQUIDITY_AMOUNT.to_string(), - }), - }); - - let mint_msg_expected = >::into(MsgMint { - sender: MOCK_CONTRACT_ADDR.to_string(), - amount: Some(pool_network::denom::Coin { - denom: lp_denom.clone(), - amount: "1000".to_string(), - }), - }); - - let bank_send_msg_expected = CosmosMsg::Bank(BankMsg::Send { - to_address: "addr0000".to_string(), - amount: vec![coin(1000u128, lp_denom.clone())], - }); - - assert_eq!(mint_initial_lp_msg, mint_initial_lp_msg_expected); - - assert_eq!(mint_msg, mint_msg_expected); - - assert_eq!(bank_send_msg, bank_send_msg_expected); -} diff --git a/contracts/liquidity_hub/pool-manager/src/tests/unit_tests/swap.rs b/contracts/liquidity_hub/pool-manager/src/tests/unit_tests/swap.rs deleted file mode 100644 index 478516e53..000000000 --- a/contracts/liquidity_hub/pool-manager/src/tests/unit_tests/swap.rs +++ /dev/null @@ -1,395 +0,0 @@ -use cosmwasm_std::testing::{mock_env, mock_info, MOCK_CONTRACT_ADDR}; -use cosmwasm_std::{ - attr, to_binary, Coin, CosmosMsg, Decimal, Reply, ReplyOn, Response, StdError, SubMsg, - SubMsgResponse, SubMsgResult, Uint128, WasmMsg, -}; -#[cfg(feature = "token_factory")] -use cosmwasm_std::{coin, BankMsg}; -use cw20::Cw20ExecuteMsg; -use white_whale_std::fee::Fee; -#[cfg(feature = "token_factory")] -use white_whale_std::lp_common::LP_SYMBOL; - -use crate::tests::mock_querier::mock_dependencies; -#[cfg(feature = "token_factory")] -use white_whale_std::pool_network; -use white_whale_std::pool_network::asset::{Asset, AssetInfo, PairType, MINIMUM_LIQUIDITY_AMOUNT}; -#[cfg(feature = "token_factory")] -use white_whale_std::pool_network::denom::MsgMint; -use white_whale_std::pool_network::pair::PoolFee; -// use white_whale_std::pool_network::pair::{ExecuteMsg, InstantiateMsg, PoolFee}; -use crate::contract::{execute, instantiate}; -use crate::error::ContractError; -use white_whale_std::pool_manager::ExecuteMsg; -use white_whale_std::pool_manager::InstantiateMsg as SingleSwapInstantiateMsg; - -#[test] -fn try_native_to_token() { - let total_share = Uint128::from(30000000000u128); - let asset_pool_amount = Uint128::from(20000000000u128); - let collateral_pool_amount = Uint128::from(30000000000u128); - let exchange_rate: Decimal = Decimal::from_ratio(asset_pool_amount, collateral_pool_amount); - let offer_amount = Uint128::from(1500000000u128); - - let mut deps = mock_dependencies(&[Coin { - denom: "uusd".to_string(), - amount: collateral_pool_amount + offer_amount, - /* user deposit must be pre-applied */ - }]); - - // Note: In order to support and write tests sooner I override the MockAPI in mock_querier with a SimpleMockAPI - // The effect is I can continue testing with instantiate2 but now an addr like liquidity0000 becomes TEMP_CONTRACT_ADDR - // This likely breaks tests elsewhere - let TEMP_CONTRACT_ADDR: String = - "contract757573642d6d4141504c61646472303030303132333435".to_string(); - - deps.querier.with_token_balances(&[ - ( - &TEMP_CONTRACT_ADDR.clone(), - &[(&MOCK_CONTRACT_ADDR.to_string(), &total_share)], - ), - ( - &"asset0000".to_string(), - &[(&MOCK_CONTRACT_ADDR.to_string(), &asset_pool_amount)], - ), - ]); - deps.querier - .with_pool_factory(&[], &[("uusd".to_string(), 6u8)]); - - // Instantiate contract - let msg = SingleSwapInstantiateMsg { - fee_collector_addr: "fee_collector_addr".to_string(), - owner: "owner".to_string(), - pair_code_id: 10u64, - token_code_id: 11u64, - pool_creation_fee: Asset { - amount: Uint128::new(1000000u128), - info: AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - }, - }; - let env = mock_env(); - let info = mock_info("owner", &[]); - let res = instantiate(deps.as_mut(), env, info, msg).unwrap(); - assert_eq!(0, res.messages.len()); - - // Create the Pair - let asset_infos = [ - AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - AssetInfo::Token { - contract_addr: "asset0000".to_string(), - }, - ]; - - let msg = ExecuteMsg::CreatePair { - asset_infos: asset_infos.to_vec(), - pool_fees: PoolFee { - protocol_fee: Fee { - share: Decimal::from_ratio(1u128, 1000u128), - }, - swap_fee: Fee { - share: Decimal::from_ratio(3u128, 1000u128), - }, - burn_fee: Fee { - share: Decimal::from_ratio(1u128, 1000u128), - }, - }, - pair_type: PairType::ConstantProduct, - token_factory_lp: false, - pair_identifier: None, - }; - - let env = mock_env(); - - let info = mock_info( - "addr0000", - &[Coin { - denom: "uusd".to_string(), - amount: Uint128::new(1000000u128), - }], - ); - - let res = execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap(); - - // normal swap - let msg = ExecuteMsg::Swap { - offer_asset: Asset { - info: AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - amount: offer_amount, - }, - ask_asset: AssetInfo::Token { - contract_addr: "asset0000".to_string(), - }, - belief_price: None, - max_spread: Some(Decimal::percent(5)), - to: None, - pair_identifier: "0".to_string(), - }; - let env = mock_env(); - let info = mock_info( - "addr0000", - &[Coin { - denom: "uusd".to_string(), - amount: offer_amount, - }], - ); - let res = execute(deps.as_mut(), env, info, msg).unwrap(); - assert_eq!(res.messages.len(), 1); - - let msg_transfer = res.messages.get(0).expect("no message"); - - // current price is 1.5, so expected return without spread is 1000 - // ask_amount = ((ask_pool - accrued protocol fees) * offer_amount / (offer_pool - accrued protocol fees + offer_amount)) - // 952.380952 = (20000 - 0) * 1500 / (30000 - 0 + 1500) - swap_fee - protocol_fee - burn_fee - // TODO: Returned amount is 904545457 and spread is up to 5% -- 43290043. Investigate this - let expected_ret_amount = Uint128::from(952_380_952u128); - let expected_spread_amount = (offer_amount * exchange_rate) - .checked_sub(expected_ret_amount) - .unwrap(); - let expected_swap_fee_amount = expected_ret_amount.multiply_ratio(3u128, 1000u128); // 0.3% - let expected_protocol_fee_amount = expected_ret_amount.multiply_ratio(1u128, 1000u128); // 0.1% - let expected_burn_fee_amount = expected_ret_amount.multiply_ratio(1u128, 1000u128); // 0.1% - let expected_return_amount = expected_ret_amount - .checked_sub(expected_swap_fee_amount) - .unwrap() - .checked_sub(expected_protocol_fee_amount) - .unwrap() - .checked_sub(expected_burn_fee_amount) - .unwrap(); - - // since there is a burn_fee on the PoolFee, check burn message - // since we swapped to a cw20 token, the burn message should be a Cw20ExecuteMsg::Burn - let expected_burn_msg = SubMsg { - id: 0, - msg: CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: "asset0000".to_string(), - msg: to_binary(&Cw20ExecuteMsg::Burn { - amount: expected_burn_fee_amount, - }) - .unwrap(), - funds: vec![], - }), - gas_limit: None, - reply_on: ReplyOn::Never, - }; - println!("{:?}", exchange_rate); - println!("{:?}", offer_amount * exchange_rate); - assert_eq!(res.messages.last().unwrap().clone(), expected_burn_msg); - - // // as we swapped native to token, we accumulate the protocol fees in token - // let protocol_fees_for_token = query_fees( - // deps.as_ref(), - // Some("asset0000".to_string()), - // None, - // COLLECTED_PROTOCOL_FEES, - // Some(ALL_TIME_COLLECTED_PROTOCOL_FEES), - // ) - // .unwrap() - // .fees; - // assert_eq!( - // protocol_fees_for_token.first().unwrap().amount, - // expected_protocol_fee_amount - // ); - // let burned_fees_for_token = query_fees( - // deps.as_ref(), - // Some("asset0000".to_string()), - // None, - // ALL_TIME_BURNED_FEES, - // None, - // ) - // .unwrap() - // .fees; - // assert_eq!( - // burned_fees_for_token.first().unwrap().amount, - // expected_burn_fee_amount - // ); - // let protocol_fees_for_native = query_fees( - // deps.as_ref(), - // Some("uusd".to_string()), - // None, - // COLLECTED_PROTOCOL_FEES, - // Some(ALL_TIME_COLLECTED_PROTOCOL_FEES), - // ) - // .unwrap() - // .fees; - // assert_eq!( - // protocol_fees_for_native.first().unwrap().amount, - // Uint128::zero() - // ); - // let burned_fees_for_native = query_fees( - // deps.as_ref(), - // Some("uusd".to_string()), - // None, - // ALL_TIME_BURNED_FEES, - // None, - // ) - // .unwrap() - // .fees; - // assert_eq!( - // burned_fees_for_native.first().unwrap().amount, - // Uint128::zero() - // ); - - // // check simulation res, reset values pre-swap to check simulation - // deps.querier.with_balance(&[( - // &MOCK_CONTRACT_ADDR.to_string(), - // vec![Coin { - // denom: "uusd".to_string(), - // amount: collateral_pool_amount, - // /* user deposit must be pre-applied */ - // }], - // )]); - - // // reset protocol fees so the simulation returns same values as the actual swap - // COLLECTED_PROTOCOL_FEES - // .save( - // &mut deps.storage, - // &vec![ - // Asset { - // info: AssetInfo::NativeToken { - // denom: "uusd".to_string(), - // }, - // amount: Uint128::zero(), - // }, - // Asset { - // info: AssetInfo::Token { - // contract_addr: "asset0000".to_string(), - // }, - // amount: Uint128::zero(), - // }, - // ], - // ) - // .unwrap(); - - // let simulation_res: SimulationResponse = from_binary( - // &query( - // deps.as_ref(), - // mock_env(), - // QueryMsg::Simulation { - // offer_asset: Asset { - // info: AssetInfo::NativeToken { - // denom: "uusd".to_string(), - // }, - // amount: offer_amount, - // }, - // }, - // ) - // .unwrap(), - // ) - // .unwrap(); - - // assert_eq!(expected_return_amount, simulation_res.return_amount); - // assert_eq!(expected_swap_fee_amount, simulation_res.swap_fee_amount); - // assert_eq!(expected_burn_fee_amount, simulation_res.burn_fee_amount); - // assert_eq!(expected_spread_amount, simulation_res.spread_amount); - // assert_eq!( - // expected_protocol_fee_amount, - // simulation_res.protocol_fee_amount - // ); - - // // reset protocol fees so the simulation returns same values as the actual swap - // COLLECTED_PROTOCOL_FEES - // .save( - // &mut deps.storage, - // &vec![ - // Asset { - // info: AssetInfo::NativeToken { - // denom: "uusd".to_string(), - // }, - // amount: Uint128::zero(), - // }, - // Asset { - // info: AssetInfo::Token { - // contract_addr: "asset0000".to_string(), - // }, - // amount: Uint128::zero(), - // }, - // ], - // ) - // .unwrap(); - - // let reverse_simulation_res: ReverseSimulationResponse = from_binary( - // &query( - // deps.as_ref(), - // mock_env(), - // QueryMsg::ReverseSimulation { - // ask_asset: Asset { - // info: AssetInfo::Token { - // contract_addr: "asset0000".to_string(), - // }, - // amount: expected_return_amount, - // }, - // }, - // ) - // .unwrap(), - // ) - // .unwrap(); - - // assert!( - // (offer_amount.u128() as i128 - reverse_simulation_res.offer_amount.u128() as i128).abs() - // < 3i128 - // ); - // assert!( - // (expected_swap_fee_amount.u128() as i128 - // - reverse_simulation_res.swap_fee_amount.u128() as i128) - // .abs() - // < 3i128 - // ); - // assert!( - // (expected_spread_amount.u128() as i128 - // - reverse_simulation_res.spread_amount.u128() as i128) - // .abs() - // < 3i128 - // ); - // assert!( - // (expected_protocol_fee_amount.u128() as i128 - // - reverse_simulation_res.protocol_fee_amount.u128() as i128) - // .abs() - // < 3i128 - // ); - // assert!( - // (expected_burn_fee_amount.u128() as i128 - // - reverse_simulation_res.burn_fee_amount.u128() as i128) - // .abs() - // < 3i128 - // ); - - // assert_eq!( - // res.attributes, - // vec![ - // attr("action", "swap"), - // attr("sender", "addr0000"), - // attr("receiver", "addr0000"), - // attr("offer_asset", "uusd"), - // attr("ask_asset", "asset0000"), - // attr("offer_amount", offer_amount.to_string()), - // attr("return_amount", expected_return_amount.to_string()), - // attr("spread_amount", expected_spread_amount.to_string()), - // attr("swap_fee_amount", expected_swap_fee_amount.to_string()), - // attr( - // "protocol_fee_amount", - // expected_protocol_fee_amount.to_string(), - // ), - // attr("burn_fee_amount", expected_burn_fee_amount.to_string()), - // attr("swap_type", "ConstantProduct"), - // ] - // ); - - // assert_eq!( - // &SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute { - // contract_addr: "asset0000".to_string(), - // msg: to_binary(&Cw20ExecuteMsg::Transfer { - // recipient: "addr0000".to_string(), - // amount: expected_return_amount, - // }) - // .unwrap(), - // funds: vec![], - // })), - // msg_transfer, - // ); -} diff --git a/contracts/liquidity_hub/pool-manager/src/tests/unit_tests/withdrawals.rs b/contracts/liquidity_hub/pool-manager/src/tests/unit_tests/withdrawals.rs deleted file mode 100644 index 681b9e68d..000000000 --- a/contracts/liquidity_hub/pool-manager/src/tests/unit_tests/withdrawals.rs +++ /dev/null @@ -1,654 +0,0 @@ -use cosmwasm_std::testing::{mock_env, mock_info, MOCK_CONTRACT_ADDR}; -use cosmwasm_std::{ - attr, to_binary, BankMsg, Coin, CosmosMsg, Decimal, Reply, Response, SubMsg, SubMsgResponse, - SubMsgResult, Uint128, WasmMsg, -}; -use cw20::{Cw20ExecuteMsg, Cw20ReceiveMsg}; - -#[cfg(feature = "token_factory")] -use cosmwasm_std::coin; -use white_whale_std::fee::Fee; -#[cfg(feature = "token_factory")] -use white_whale_std::lp_common::LP_SYMBOL; -#[cfg(feature = "token_factory")] -use white_whale_std::pool_network; -use white_whale_std::pool_network::asset::{AssetInfo, PairType}; -#[cfg(feature = "token_factory")] -use white_whale_std::pool_network::denom::MsgBurn; -use white_whale_std::pool_network::mock_querier::mock_dependencies; -use white_whale_std::pool_network::pair::{Cw20HookMsg, ExecuteMsg, InstantiateMsg, PoolFee}; - -use crate::contract::{execute, instantiate, reply}; -use crate::error::ContractError; -use crate::state::{get_fees_for_asset, store_fee, COLLECTED_PROTOCOL_FEES}; - -#[test] -fn withdraw_xyk_liquidity_cw20_lp() { - let mut deps = mock_dependencies(&[Coin { - denom: "uusd".to_string(), - amount: Uint128::from(100u128), - }]); - - deps.querier.with_token_balances(&[ - ( - &"liquidity0000".to_string(), - &[(&"addr0000".to_string(), &Uint128::from(100u128))], - ), - ( - &"asset0000".to_string(), - &[(&MOCK_CONTRACT_ADDR.to_string(), &Uint128::from(100u128))], - ), - ]); - - let msg = InstantiateMsg { - asset_infos: [ - AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - AssetInfo::Token { - contract_addr: "asset0000".to_string(), - }, - ], - token_code_id: 10u64, - asset_decimals: [6u8, 8u8], - pool_fees: PoolFee { - protocol_fee: Fee { - share: Decimal::percent(1u64), - }, - swap_fee: Fee { - share: Decimal::percent(1u64), - }, - burn_fee: Fee { - share: Decimal::zero(), - }, - }, - fee_collector_addr: "collector".to_string(), - pair_type: PairType::ConstantProduct, - token_factory_lp: false, - }; - - let env = mock_env(); - let info = mock_info("addr0000", &[]); - // we can just call .unwrap() to assert this was a success - let _res = instantiate(deps.as_mut(), env, info, msg).unwrap(); - - // store liquidity token - let reply_msg = Reply { - id: 1, - result: SubMsgResult::Ok(SubMsgResponse { - events: vec![], - data: Some( - vec![ - 10, 13, 108, 105, 113, 117, 105, 100, 105, 116, 121, 48, 48, 48, 48, - ] - .into(), - ), - }), - }; - - let _res = reply(deps.as_mut(), mock_env(), reply_msg).unwrap(); - - // store some protocol fees in both native and token - store_fee( - deps.as_mut().storage, - Uint128::from(10u8), - "uusd".to_string(), - COLLECTED_PROTOCOL_FEES, - ) - .unwrap(); - store_fee( - deps.as_mut().storage, - Uint128::from(20u8), - "asset0000".to_string(), - COLLECTED_PROTOCOL_FEES, - ) - .unwrap(); - - // withdraw liquidity - let msg = ExecuteMsg::Receive(Cw20ReceiveMsg { - sender: "addr0000".to_string(), - msg: to_binary(&Cw20HookMsg::WithdrawLiquidity {}).unwrap(), - amount: Uint128::from(100u128), - }); - - let env = mock_env(); - let info = mock_info("liquidity0000", &[]); - let res = execute(deps.as_mut(), env, info, msg).unwrap(); - let log_withdrawn_share = res.attributes.get(2).expect("no log"); - let log_refund_assets = res.attributes.get(3).expect("no log"); - let msg_refund_0 = res.messages.get(0).expect("no message"); - let msg_refund_1 = res.messages.get(1).expect("no message"); - let msg_burn_liquidity = res.messages.get(2).expect("no message"); - - let protocol_fee_native = get_fees_for_asset( - deps.as_mut().storage, - "uusd".to_string(), - COLLECTED_PROTOCOL_FEES, - ) - .unwrap(); - let expected_native_refund_amount: Uint128 = Uint128::from(100u128) - .checked_sub(protocol_fee_native.amount) - .unwrap(); - - let protocol_fee_token = get_fees_for_asset( - deps.as_mut().storage, - "asset0000".to_string(), - COLLECTED_PROTOCOL_FEES, - ) - .unwrap(); - let expected_token_refund_amount: Uint128 = Uint128::from(100u128) - .checked_sub(protocol_fee_token.amount) - .unwrap(); - - assert_eq!( - msg_refund_0, - &SubMsg::new(CosmosMsg::Bank(BankMsg::Send { - to_address: "addr0000".to_string(), - amount: vec![Coin { - denom: "uusd".to_string(), - amount: expected_native_refund_amount, - }], - })) - ); - assert_eq!( - msg_refund_1, - &SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: "asset0000".to_string(), - msg: to_binary(&Cw20ExecuteMsg::Transfer { - recipient: "addr0000".to_string(), - amount: expected_token_refund_amount, - }) - .unwrap(), - funds: vec![], - })) - ); - assert_eq!( - msg_burn_liquidity, - &SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: "liquidity0000".to_string(), - msg: to_binary(&Cw20ExecuteMsg::Burn { - amount: Uint128::from(100u128), - }) - .unwrap(), - funds: vec![], - })) - ); - - assert_eq!( - log_withdrawn_share, - &attr("withdrawn_share", 100u128.to_string()) - ); - assert_eq!( - log_refund_assets, - &attr("refund_assets", "90uusd, 80asset0000") - ); -} - -#[test] -fn withdraw_stableswap_liquidity() { - let mut deps = mock_dependencies(&[Coin { - denom: "uusd".to_string(), - amount: Uint128::from(100u128), - }]); - - deps.querier.with_token_balances(&[ - ( - &"liquidity0000".to_string(), - &[(&"addr0000".to_string(), &Uint128::from(100u128))], - ), - ( - &"asset0000".to_string(), - &[(&MOCK_CONTRACT_ADDR.to_string(), &Uint128::from(100u128))], - ), - ]); - - let msg = InstantiateMsg { - asset_infos: [ - AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - AssetInfo::Token { - contract_addr: "asset0000".to_string(), - }, - ], - token_code_id: 10u64, - asset_decimals: [6u8, 8u8], - pool_fees: PoolFee { - protocol_fee: Fee { - share: Decimal::percent(1u64), - }, - swap_fee: Fee { - share: Decimal::percent(1u64), - }, - burn_fee: Fee { - share: Decimal::zero(), - }, - }, - fee_collector_addr: "collector".to_string(), - pair_type: PairType::StableSwap { amp: 100 }, - token_factory_lp: false, - }; - - let env = mock_env(); - let info = mock_info("addr0000", &[]); - instantiate(deps.as_mut(), env, info, msg).unwrap(); - - // store liquidity token - let reply_msg = Reply { - id: 1, - result: SubMsgResult::Ok(SubMsgResponse { - events: vec![], - data: Some( - vec![ - 10, 13, 108, 105, 113, 117, 105, 100, 105, 116, 121, 48, 48, 48, 48, - ] - .into(), - ), - }), - }; - reply(deps.as_mut(), mock_env(), reply_msg).unwrap(); - - // store some protocol fees in both native and token - store_fee( - deps.as_mut().storage, - Uint128::from(10u8), - "uusd".to_string(), - COLLECTED_PROTOCOL_FEES, - ) - .unwrap(); - store_fee( - deps.as_mut().storage, - Uint128::from(20u8), - "asset0000".to_string(), - COLLECTED_PROTOCOL_FEES, - ) - .unwrap(); - - // withdraw liquidity - let msg = ExecuteMsg::Receive(Cw20ReceiveMsg { - sender: "addr0000".to_string(), - msg: to_binary(&Cw20HookMsg::WithdrawLiquidity {}).unwrap(), - amount: Uint128::from(100u128), - }); - - let env = mock_env(); - let info = mock_info("liquidity0000", &[]); - let res = execute(deps.as_mut(), env, info, msg).unwrap(); - - let protocol_fee_native = get_fees_for_asset( - deps.as_mut().storage, - "uusd".to_string(), - COLLECTED_PROTOCOL_FEES, - ) - .unwrap(); - let expected_native_refund_amount: Uint128 = Uint128::from(100u128) - .checked_sub(protocol_fee_native.amount) - .unwrap(); - - let protocol_fee_token = get_fees_for_asset( - deps.as_mut().storage, - "asset0000".to_string(), - COLLECTED_PROTOCOL_FEES, - ) - .unwrap(); - let expected_token_refund_amount: Uint128 = Uint128::from(100u128) - .checked_sub(protocol_fee_token.amount) - .unwrap(); - - assert_eq!( - res, - Response::new() - .add_messages(vec![ - CosmosMsg::Bank(BankMsg::Send { - to_address: "addr0000".to_string(), - amount: vec![Coin { - denom: "uusd".to_string(), - amount: expected_native_refund_amount, - }], - }), - CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: "asset0000".to_string(), - msg: to_binary(&Cw20ExecuteMsg::Transfer { - recipient: "addr0000".to_string(), - amount: expected_token_refund_amount, - }) - .unwrap(), - funds: vec![], - }), - CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: "liquidity0000".to_string(), - msg: to_binary(&Cw20ExecuteMsg::Burn { - amount: Uint128::from(100u128), - }) - .unwrap(), - funds: vec![], - }), - ]) - .add_attributes(vec![ - ("action", "withdraw_liquidity"), - ("sender", "addr0000"), - ("withdrawn_share", "100"), - ("refund_assets", ("90uusd, 80asset0000")), - ]) - ); -} - -#[test] -fn test_withdrawal_unauthorized() { - let mut deps = mock_dependencies(&[Coin { - denom: "uusd".to_string(), - amount: Uint128::from(100u128), - }]); - - deps.querier.with_token_balances(&[ - ( - &"liquidity0000".to_string(), - &[(&"addr0000".to_string(), &Uint128::from(100u128))], - ), - ( - &"asset0000".to_string(), - &[(&MOCK_CONTRACT_ADDR.to_string(), &Uint128::from(100u128))], - ), - ]); - - let msg = InstantiateMsg { - asset_infos: [ - AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - AssetInfo::Token { - contract_addr: "asset0000".to_string(), - }, - ], - token_code_id: 10u64, - asset_decimals: [6u8, 8u8], - pool_fees: PoolFee { - protocol_fee: Fee { - share: Decimal::percent(1u64), - }, - swap_fee: Fee { - share: Decimal::percent(1u64), - }, - burn_fee: Fee { - share: Decimal::zero(), - }, - }, - fee_collector_addr: "collector".to_string(), - pair_type: PairType::ConstantProduct, - token_factory_lp: false, - }; - - let env = mock_env(); - let info = mock_info("addr0000", &[]); - instantiate(deps.as_mut(), env, info, msg).unwrap(); - - // withdraw liquidity should fail - let msg = ExecuteMsg::Receive(Cw20ReceiveMsg { - sender: "addr0000".to_string(), - msg: to_binary(&Cw20HookMsg::WithdrawLiquidity {}).unwrap(), - amount: Uint128::from(100u128), - }); - - let env = mock_env(); - let info = mock_info("not_cw20", &[]); - let res = execute(deps.as_mut(), env, info, msg); - match res { - Ok(_) => panic!("should return ContractError::Unauthorized"), - Err(ContractError::Unauthorized { .. }) => (), - _ => panic!("should return ContractError::Unauthorized"), - } -} - -#[test] -fn test_withdrawal_wrong_message() { - let mut deps = mock_dependencies(&[Coin { - denom: "uusd".to_string(), - amount: Uint128::from(100u128), - }]); - - deps.querier.with_token_balances(&[ - ( - &"liquidity0000".to_string(), - &[(&"addr0000".to_string(), &Uint128::from(100u128))], - ), - ( - &"asset0000".to_string(), - &[(&MOCK_CONTRACT_ADDR.to_string(), &Uint128::from(100u128))], - ), - ]); - - let msg = InstantiateMsg { - asset_infos: [ - AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - AssetInfo::Token { - contract_addr: "asset0000".to_string(), - }, - ], - token_code_id: 10u64, - asset_decimals: [6u8, 8u8], - pool_fees: PoolFee { - protocol_fee: Fee { - share: Decimal::percent(1u64), - }, - swap_fee: Fee { - share: Decimal::percent(1u64), - }, - burn_fee: Fee { - share: Decimal::zero(), - }, - }, - fee_collector_addr: "collector".to_string(), - pair_type: PairType::ConstantProduct, - token_factory_lp: false, - }; - - let env = mock_env(); - let info = mock_info("addr0000", &[]); - instantiate(deps.as_mut(), env, info, msg).unwrap(); - - // withdraw liquidity should fail - let msg = ExecuteMsg::Receive(Cw20ReceiveMsg { - sender: "addr0000".to_string(), - msg: to_binary(&"invalid_message").unwrap(), - amount: Uint128::from(100u128), - }); - - let env = mock_env(); - let info = mock_info("liquidity0000", &[]); - let res = execute(deps.as_mut(), env, info, msg); - match res { - Ok(_) => panic!("should return ContractError::Std"), - Err(ContractError::Std { .. }) => (), - _ => panic!("should return ContractError::Std"), - } -} - -#[cfg(feature = "token_factory")] -#[test] -fn withdraw_xyk_liquidity_token_factory_lp() { - let lp_denom = format!("{}/{MOCK_CONTRACT_ADDR}/{LP_SYMBOL}", "factory"); - - let mut deps = mock_dependencies(&[ - Coin { - denom: "uusd".to_string(), - amount: Uint128::from(2000u128), - }, - Coin { - denom: "uwhale".to_string(), - amount: Uint128::from(2000u128), - }, - Coin { - denom: lp_denom.clone(), - amount: Uint128::from(1000u128), - }, - ]); - - deps.querier.with_balance(&[( - &"addr0000".to_string(), - vec![Coin { - denom: lp_denom.clone(), - amount: Uint128::from(1000u128 /* user deposit must be pre-applied */), - }], - )]); - - let msg = InstantiateMsg { - asset_infos: [ - AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - AssetInfo::NativeToken { - denom: "uwhale".to_string(), - }, - ], - token_code_id: 10u64, - asset_decimals: [6u8, 8u8], - pool_fees: PoolFee { - protocol_fee: Fee { - share: Decimal::percent(1u64), - }, - swap_fee: Fee { - share: Decimal::percent(1u64), - }, - burn_fee: Fee { - share: Decimal::zero(), - }, - }, - fee_collector_addr: "collector".to_string(), - pair_type: PairType::ConstantProduct, - token_factory_lp: true, - }; - - let env = mock_env(); - let info = mock_info("addr0000", &[]); - // we can just call .unwrap() to assert this was a success - let _res = instantiate(deps.as_mut(), env, info, msg).unwrap(); - - // withdraw liquidity - let msg = ExecuteMsg::WithdrawLiquidity {}; - - let env = mock_env(); - let info = mock_info( - "addr0000", - &[Coin { - denom: lp_denom.clone(), - amount: Uint128::from(1000u128), - }], - ); - let res = execute(deps.as_mut(), env, info, msg).unwrap(); - - let log_withdrawn_share = res.attributes.get(2).expect("no log"); - let log_refund_assets = res.attributes.get(3).expect("no log"); - let msg_refund_0 = res.messages.get(0).expect("no message").clone().msg; - let msg_refund_1 = res.messages.get(1).expect("no message").clone().msg; - let msg_burn_liquidity = res.messages.get(2).expect("no message").clone().msg; - - let expected_asset_0_refund_amount: Uint128 = Uint128::from(1000u128); - let expected_asset_1_refund_amount: Uint128 = Uint128::from(1000u128); - - let msg_refund_0_expected = CosmosMsg::Bank(BankMsg::Send { - to_address: "addr0000".to_string(), - amount: vec![coin(expected_asset_0_refund_amount.u128(), "uusd")], - }); - let msg_refund_1_expected = CosmosMsg::Bank(BankMsg::Send { - to_address: "addr0000".to_string(), - amount: vec![coin(expected_asset_1_refund_amount.u128(), "uwhale")], - }); - let msg_burn_liquidity_expected = >::into(MsgBurn { - sender: MOCK_CONTRACT_ADDR.to_string(), - amount: Some(pool_network::denom::Coin { - denom: lp_denom.clone(), - amount: "1000".to_string(), - }), - }); - - assert_eq!(msg_refund_0, msg_refund_0_expected); - assert_eq!(msg_refund_1, msg_refund_1_expected); - assert_eq!(msg_burn_liquidity, msg_burn_liquidity_expected); - - assert_eq!( - log_withdrawn_share, - &attr("withdrawn_share", 1000u128.to_string()) - ); - assert_eq!( - log_refund_assets, - &attr("refund_assets", "1000uusd, 1000uwhale") - ); -} - -#[cfg(feature = "token_factory")] -#[test] -fn withdraw_xyk_liquidity_token_factory_lp_wrong_asset() { - let lp_denom = format!("{}/{MOCK_CONTRACT_ADDR}/{LP_SYMBOL}", "factory"); - - let mut deps = mock_dependencies(&[ - Coin { - denom: "uusd".to_string(), - amount: Uint128::from(2000u128), - }, - Coin { - denom: "uwhale".to_string(), - amount: Uint128::from(2000u128), - }, - Coin { - denom: lp_denom.clone(), - amount: Uint128::from(1000u128), - }, - ]); - - deps.querier.with_balance(&[( - &"addr0000".to_string(), - vec![Coin { - denom: lp_denom.clone(), - amount: Uint128::from(1000u128 /* user deposit must be pre-applied */), - }], - )]); - - let msg = InstantiateMsg { - asset_infos: [ - AssetInfo::NativeToken { - denom: "uusd".to_string(), - }, - AssetInfo::NativeToken { - denom: "uwhale".to_string(), - }, - ], - token_code_id: 10u64, - asset_decimals: [6u8, 8u8], - pool_fees: PoolFee { - protocol_fee: Fee { - share: Decimal::percent(1u64), - }, - swap_fee: Fee { - share: Decimal::percent(1u64), - }, - burn_fee: Fee { - share: Decimal::zero(), - }, - }, - fee_collector_addr: "collector".to_string(), - pair_type: PairType::ConstantProduct, - token_factory_lp: true, - }; - - let env = mock_env(); - let info = mock_info("addr0000", &[]); - // we can just call .unwrap() to assert this was a success - let _res = instantiate(deps.as_mut(), env, info, msg).unwrap(); - - // withdraw liquidity - let msg = ExecuteMsg::WithdrawLiquidity {}; - - let env = mock_env(); - let info = mock_info( - "addr0000", - &[Coin { - denom: "not_lp_denom".to_string(), - amount: Uint128::from(1000u128), - }], - ); - let err = execute(deps.as_mut(), env, info, msg).unwrap_err(); - - assert_eq!(err, ContractError::AssetMismatch {}); -} diff --git a/packages/white-whale-std/src/pool_manager.rs b/packages/white-whale-std/src/pool_manager.rs index 29b947025..62c606f0d 100644 --- a/packages/white-whale-std/src/pool_manager.rs +++ b/packages/white-whale-std/src/pool_manager.rs @@ -1,6 +1,6 @@ use std::fmt; -use crate::{fee::PoolFee, pool_network::asset::PairType}; +use crate::fee::PoolFee; use cosmwasm_schema::{cw_serde, QueryResponses}; use cosmwasm_std::{Addr, Coin, Decimal, Uint128}; use cw_ownable::{cw_ownable_execute, cw_ownable_query}; @@ -88,20 +88,38 @@ pub struct StableSwapParams { pub future_amp_block: String, } -// Store PairInfo to N -// We define a custom struct for which allows for dynamic but defined pairs +// Store PoolInfo to N +// We define a custom struct for which allows for dynamic but defined pools #[cw_serde] -pub struct PairInfo { +pub struct PoolInfo { pub asset_denoms: Vec, pub lp_denom: String, pub asset_decimals: Vec, pub assets: Vec, - pub pair_type: PairType, + pub pool_type: PoolType, pub pool_fees: PoolFee, - // TODO: Add stable swap params - // pub stable_swap_params: Option + //pub stable_swap_params: Option +} +impl PoolInfo {} + +#[cw_serde] +pub enum PoolType { + StableSwap { + /// The amount of amplification to perform on the constant product part of the swap formula. + amp: u64, + }, + ConstantProduct, +} + +impl PoolType { + /// Gets a string representation of the pair type + pub fn get_label(&self) -> &str { + match self { + PoolType::ConstantProduct => "ConstantProduct", + PoolType::StableSwap { .. } => "StableSwap", + } + } } -impl PairInfo {} #[cw_serde] pub struct Config { @@ -129,19 +147,18 @@ pub struct MigrateMsg {} #[cw_ownable_execute] #[cw_serde] pub enum ExecuteMsg { - //todo maybe to rename to CreatePool? - /// Creates a new pair. - CreatePair { - /// The asset denoms for the pair. + /// Creates a new pool. + CreatePool { + /// The asset denoms for the pool. asset_denoms: Vec, /// The decimals for the given asset denoms, provided in the same order as `asset_denoms`. asset_decimals: Vec, /// The fees for the pool. pool_fees: PoolFee, - /// The type of pair to create. - pair_type: PairType, - /// The identifier for the pair. - pair_identifier: Option, + /// The type of pool to create. + pool_type: PoolType, + /// The identifier for the pool. + pool_identifier: Option, }, /// Provides liquidity to the pool ProvideLiquidity { @@ -149,14 +166,14 @@ pub enum ExecuteMsg { /// When provided, if the slippage exceeds this value, the liquidity provision will not be /// executed. slippage_tolerance: Option, - /// The maximum allowable spread between the bid and ask prices for the pair. + /// The maximum allowable spread between the bid and ask prices for the pool. /// When provided, if the spread exceeds this value, the liquidity provision will not be /// executed. max_spread: Option, /// The receiver of the LP receiver: Option, - /// The identifier for the pair to provide liquidity for. - pair_identifier: String, + /// The identifier for the pool to provide liquidity for. + pool_identifier: String, /// The amount of time in seconds to unlock tokens if taking part on the incentives. If not passed, /// the tokens will not be locked and the LP tokens will be returned to the user. unlocking_duration: Option, @@ -175,11 +192,11 @@ pub enum ExecuteMsg { /// The recipient of the output tokens. If not provided, the tokens will be sent to the sender /// of the message. receiver: Option, - /// The identifier for the pair to swap in. - pair_identifier: String, + /// The identifier for the pool to swap in. + pool_identifier: String, }, /// Withdraws liquidity from the pool. - WithdrawLiquidity { pair_identifier: String }, + WithdrawLiquidity { pool_identifier: String }, /// Execute multiple [`SwapOperations`] to allow for multi-hop swaps. ExecuteSwapOperations { /// The operations that should be performed in sequence. @@ -193,7 +210,7 @@ pub enum ExecuteMsg { /// The (optional) recipient of the output tokens. /// /// If left unspecified, tokens will be sent to the sender of the message. - to: Option, + receiver: Option, /// The (optional) maximum spread to incur when performing any swap. /// /// If left unspecified, there is no limit to what spread the transaction can incur. @@ -227,7 +244,7 @@ pub enum QueryMsg { /// Retrieves the decimals for the given asset. #[returns(AssetDecimalsResponse)] AssetDecimals { - pair_identifier: String, + pool_identifier: String, denom: String, }, @@ -235,7 +252,7 @@ pub enum QueryMsg { #[returns(SimulationResponse)] Simulation { offer_asset: Coin, - pair_identifier: String, + pool_identifier: String, }, /// Simulates a reverse swap, i.e. given the ask asset, how much of the offer asset is needed to /// perform the swap. @@ -243,7 +260,7 @@ pub enum QueryMsg { ReverseSimulation { ask_asset: Coin, offer_asset: Coin, - pair_identifier: String, + pool_identifier: String, }, /// Gets the swap route for the given offer and ask assets. @@ -270,8 +287,8 @@ pub enum QueryMsg { operations: Vec, }, - #[returns(PairInfoResponse)] - Pair { pair_identifier: String }, + #[returns(PoolInfoResponse)] + Pool { pool_identifier: String }, /// Retrieves the creator of the swap routes that can then remove them. #[returns(SwapRouteCreatorResponse)] SwapRouteCreator { @@ -291,17 +308,17 @@ pub struct SwapRoutesResponse { } #[cw_serde] -pub struct PairInfoResponse { - pub pair_info: PairInfo, +pub struct PoolInfoResponse { + pub pool_info: PoolInfo, pub total_share: Coin, } /// The response for the `AssetDecimals` query. #[cw_serde] pub struct AssetDecimalsResponse { - /// The pair identifier to do the query for. - pub pair_identifier: String, - /// The queried denom in the given pair_identifier. + /// The pool identifier to do the query for. + pub pool_identifier: String, + /// The queried denom in the given pool_identifier. pub denom: String, /// The decimals for the requested denom. pub decimals: u8, From 96be33f2a52d375c633035b7053fbf738e49ca91 Mon Sep 17 00:00:00 2001 From: Kerber0x Date: Thu, 2 May 2024 16:05:13 +0100 Subject: [PATCH 4/7] refactor: add docs to messages and queries --- .../pool-manager/schema/pool-manager.json | 301 ++++++++++++++---- .../pool-manager/schema/raw/execute.json | 29 +- .../pool-manager/schema/raw/instantiate.json | 9 +- .../pool-manager/schema/raw/migrate.json | 1 - .../pool-manager/schema/raw/query.json | 76 +++-- .../schema/raw/response_to_config.json | 21 +- .../schema/raw/response_to_pool.json | 49 ++- ...e_to_reverse_simulate_swap_operations.json | 8 +- .../raw/response_to_reverse_simulation.json | 35 +- .../response_to_simulate_swap_operations.json | 8 +- .../schema/raw/response_to_simulation.json | 35 +- .../schema/raw/response_to_swap_route.json | 17 +- .../raw/response_to_swap_route_creator.json | 2 + .../schema/raw/response_to_swap_routes.json | 11 + .../pool-manager/src/contract.rs | 6 +- .../liquidity_hub/pool-manager/src/queries.rs | 1 - .../pool-manager/src/tests/suite.rs | 8 +- packages/white-whale-std/src/pool_manager.rs | 106 ++++-- 18 files changed, 563 insertions(+), 160 deletions(-) diff --git a/contracts/liquidity_hub/pool-manager/schema/pool-manager.json b/contracts/liquidity_hub/pool-manager/schema/pool-manager.json index 8d15e2023..7c030414c 100644 --- a/contracts/liquidity_hub/pool-manager/schema/pool-manager.json +++ b/contracts/liquidity_hub/pool-manager/schema/pool-manager.json @@ -13,13 +13,20 @@ ], "properties": { "bonding_manager_addr": { + "description": "The address of the bonding manager contract.", "type": "string" }, "incentive_manager_addr": { + "description": "The address of the incentive manager contract.", "type": "string" }, "pool_creation_fee": { - "$ref": "#/definitions/Coin" + "description": "How much it costs to create a pool. It helps prevent spamming of new pools.", + "allOf": [ + { + "$ref": "#/definitions/Coin" + } + ] } }, "additionalProperties": false, @@ -540,7 +547,7 @@ ] }, "FeatureToggle": { - "description": "Pool feature toggle", + "description": "Pool feature toggle, can control whether swaps, deposits, and withdrawals are enabled.", "type": "object", "required": [ "deposits_enabled", @@ -549,12 +556,15 @@ ], "properties": { "deposits_enabled": { + "description": "Whether or not deposits are enabled", "type": "boolean" }, "swaps_enabled": { + "description": "Whether or not swaps are enabled", "type": "boolean" }, "withdrawals_enabled": { + "description": "Whether or not swaps are enabled", "type": "boolean" } }, @@ -617,14 +627,10 @@ "additionalProperties": false }, "PoolType": { + "description": "Possible pool types, it can be either a constant product (xyk) pool or a stable swap pool.", "oneOf": [ { - "type": "string", - "enum": [ - "constant_product" - ] - }, - { + "description": "A stable swap pool.", "type": "object", "required": [ "stable_swap" @@ -647,12 +653,21 @@ } }, "additionalProperties": false + }, + { + "description": "xyk pool", + "type": "string", + "enum": [ + "constant_product" + ] } ] }, "SwapOperation": { + "description": "The type of swap operation to perform.", "oneOf": [ { + "description": "A swap operation that uses the WhaleSwap router.", "type": "object", "required": [ "whale_swap" @@ -667,12 +682,15 @@ ], "properties": { "pool_identifier": { + "description": "The identifier of the pool to use for the swap.", "type": "string" }, "token_in_denom": { + "description": "The token denom to swap in.", "type": "string" }, "token_out_denom": { + "description": "The token denom returning from the swap.", "type": "string" } }, @@ -684,6 +702,7 @@ ] }, "SwapRoute": { + "description": "The swap route structure", "type": "object", "required": [ "ask_asset_denom", @@ -692,12 +711,15 @@ ], "properties": { "ask_asset_denom": { + "description": "The ask asset denom, i.e. the asset that is being received.", "type": "string" }, "offer_asset_denom": { + "description": "The offer asset denom, i.e. the asset that is being swapped.", "type": "string" }, "swap_operations": { + "description": "The swap operations to perform to get from offer asset to ask asset.", "type": "array", "items": { "$ref": "#/definitions/SwapOperation" @@ -730,17 +752,10 @@ "oneOf": [ { "description": "Retrieves the contract's config.", - "type": "object", - "required": [ + "type": "string", + "enum": [ "config" - ], - "properties": { - "config": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false + ] }, { "description": "Retrieves the decimals for the given asset.", @@ -757,9 +772,11 @@ ], "properties": { "denom": { + "description": "The queried denom in the given pool_identifier.", "type": "string" }, "pool_identifier": { + "description": "The pool identifier to do the query for.", "type": "string" } }, @@ -783,9 +800,15 @@ ], "properties": { "offer_asset": { - "$ref": "#/definitions/Coin" + "description": "The offer asset to swap.", + "allOf": [ + { + "$ref": "#/definitions/Coin" + } + ] }, "pool_identifier": { + "description": "The pool identifier to swap in.", "type": "string" } }, @@ -805,17 +828,19 @@ "type": "object", "required": [ "ask_asset", - "offer_asset", "pool_identifier" ], "properties": { "ask_asset": { - "$ref": "#/definitions/Coin" - }, - "offer_asset": { - "$ref": "#/definitions/Coin" + "description": "The ask asset to get after the swap.", + "allOf": [ + { + "$ref": "#/definitions/Coin" + } + ] }, "pool_identifier": { + "description": "The pool identifier to swap in.", "type": "string" } }, @@ -839,9 +864,11 @@ ], "properties": { "ask_asset_denom": { + "description": "The ask asset denom, i.e. the asset that is being received.", "type": "string" }, "offer_asset_denom": { + "description": "The offer asset denom, i.e. the asset that is being swapped.", "type": "string" } }, @@ -852,17 +879,10 @@ }, { "description": "Gets all swap routes registered", - "type": "object", - "required": [ + "type": "string", + "enum": [ "swap_routes" - ], - "properties": { - "swap_routes": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false + ] }, { "description": "Simulates swap operations.", @@ -879,9 +899,15 @@ ], "properties": { "offer_amount": { - "$ref": "#/definitions/Uint128" + "description": "The amount to swap.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] }, "operations": { + "description": "The operations to perform.", "type": "array", "items": { "$ref": "#/definitions/SwapOperation" @@ -908,9 +934,15 @@ ], "properties": { "ask_amount": { - "$ref": "#/definitions/Uint128" + "description": "The amount to get after the swap.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] }, "operations": { + "description": "The operations to perform.", "type": "array", "items": { "$ref": "#/definitions/SwapOperation" @@ -923,6 +955,7 @@ "additionalProperties": false }, { + "description": "Retrieves the pool information for the given pool identifier.", "type": "object", "required": [ "pool" @@ -944,7 +977,7 @@ "additionalProperties": false }, { - "description": "Retrieves the creator of the swap routes that can then remove them.", + "description": "Retrieves the creator of the swap route to get from offer to ask asset. The creator of the swap route can remove it.", "type": "object", "required": [ "swap_route_creator" @@ -958,9 +991,11 @@ ], "properties": { "ask_asset_denom": { + "description": "The ask asset denom, i.e. the asset that is being received.", "type": "string" }, "offer_asset_denom": { + "description": "The offer asset denom, i.e. the asset that is being swapped.", "type": "string" } }, @@ -1001,8 +1036,10 @@ } }, "SwapOperation": { + "description": "The type of swap operation to perform.", "oneOf": [ { + "description": "A swap operation that uses the WhaleSwap router.", "type": "object", "required": [ "whale_swap" @@ -1017,12 +1054,15 @@ ], "properties": { "pool_identifier": { + "description": "The identifier of the pool to use for the swap.", "type": "string" }, "token_in_denom": { + "description": "The token denom to swap in.", "type": "string" }, "token_out_denom": { + "description": "The token denom returning from the swap.", "type": "string" } }, @@ -1042,7 +1082,6 @@ "migrate": { "$schema": "http://json-schema.org/draft-07/schema#", "title": "MigrateMsg", - "description": "The migrate message", "type": "object", "additionalProperties": false }, @@ -1079,13 +1118,19 @@ "config": { "$schema": "http://json-schema.org/draft-07/schema#", "title": "ConfigResponse", + "description": "The response for the `Config` query.", "type": "object", "required": [ "config" ], "properties": { "config": { - "$ref": "#/definitions/Config" + "description": "The contract configuration.", + "allOf": [ + { + "$ref": "#/definitions/Config" + } + ] } }, "additionalProperties": false, @@ -1110,6 +1155,7 @@ } }, "Config": { + "description": "The contract configuration.", "type": "object", "required": [ "bonding_manager_addr", @@ -1138,13 +1184,18 @@ ] }, "pool_creation_fee": { - "$ref": "#/definitions/Coin" + "description": "How much it costs to create a pool. It helps prevent spamming of new pools.", + "allOf": [ + { + "$ref": "#/definitions/Coin" + } + ] } }, "additionalProperties": false }, "FeatureToggle": { - "description": "Pool feature toggle", + "description": "Pool feature toggle, can control whether swaps, deposits, and withdrawals are enabled.", "type": "object", "required": [ "deposits_enabled", @@ -1153,12 +1204,15 @@ ], "properties": { "deposits_enabled": { + "description": "Whether or not deposits are enabled", "type": "boolean" }, "swaps_enabled": { + "description": "Whether or not swaps are enabled", "type": "boolean" }, "withdrawals_enabled": { + "description": "Whether or not swaps are enabled", "type": "boolean" } }, @@ -1268,6 +1322,7 @@ "pool": { "$schema": "http://json-schema.org/draft-07/schema#", "title": "PoolInfoResponse", + "description": "The response for the `Pool` query.", "type": "object", "required": [ "pool_info", @@ -1275,10 +1330,20 @@ ], "properties": { "pool_info": { - "$ref": "#/definitions/PoolInfo" + "description": "The pool information for the given pool identifier.", + "allOf": [ + { + "$ref": "#/definitions/PoolInfo" + } + ] }, "total_share": { - "$ref": "#/definitions/Coin" + "description": "The total LP tokens in the pool.", + "allOf": [ + { + "$ref": "#/definitions/Coin" + } + ] } }, "additionalProperties": false, @@ -1359,6 +1424,7 @@ "additionalProperties": false }, "PoolInfo": { + "description": "Contains the pool information", "type": "object", "required": [ "asset_decimals", @@ -1370,6 +1436,7 @@ ], "properties": { "asset_decimals": { + "description": "The decimals for the given asset denoms, provided in the same order as asset_denoms.", "type": "array", "items": { "type": "integer", @@ -1378,38 +1445,47 @@ } }, "asset_denoms": { + "description": "The asset denoms for the pool.", "type": "array", "items": { "type": "string" } }, "assets": { + "description": "The total amount of assets in the pool.", "type": "array", "items": { "$ref": "#/definitions/Coin" } }, "lp_denom": { + "description": "The LP denom of the pool.", "type": "string" }, "pool_fees": { - "$ref": "#/definitions/PoolFee" + "description": "The fees for the pool.", + "allOf": [ + { + "$ref": "#/definitions/PoolFee" + } + ] }, "pool_type": { - "$ref": "#/definitions/PoolType" + "description": "The type of pool to create.", + "allOf": [ + { + "$ref": "#/definitions/PoolType" + } + ] } }, "additionalProperties": false }, "PoolType": { + "description": "Possible pool types, it can be either a constant product (xyk) pool or a stable swap pool.", "oneOf": [ { - "type": "string", - "enum": [ - "constant_product" - ] - }, - { + "description": "A stable swap pool.", "type": "object", "required": [ "stable_swap" @@ -1432,6 +1508,13 @@ } }, "additionalProperties": false + }, + { + "description": "xyk pool", + "type": "string", + "enum": [ + "constant_product" + ] } ] }, @@ -1444,13 +1527,19 @@ "reverse_simulate_swap_operations": { "$schema": "http://json-schema.org/draft-07/schema#", "title": "ReverseSimulateSwapOperationsResponse", + "description": "The response for the `ReverseSimulateSwapOperations` query.", "type": "object", "required": [ "amount" ], "properties": { "amount": { - "$ref": "#/definitions/Uint128" + "description": "The amount of the initial token needed to get the final token after the swap operations.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] } }, "additionalProperties": false, @@ -1475,19 +1564,44 @@ ], "properties": { "burn_fee_amount": { - "$ref": "#/definitions/Uint128" + "description": "The burn fee amount of the swap.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] }, "offer_amount": { - "$ref": "#/definitions/Uint128" + "description": "The amount of the offer asset needed to get the ask amount.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] }, "protocol_fee_amount": { - "$ref": "#/definitions/Uint128" + "description": "The protocol fee amount of the swap.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] }, "spread_amount": { - "$ref": "#/definitions/Uint128" + "description": "The spread amount of the swap.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] }, "swap_fee_amount": { - "$ref": "#/definitions/Uint128" + "description": "The swap fee amount of the swap.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] } }, "additionalProperties": false, @@ -1501,13 +1615,19 @@ "simulate_swap_operations": { "$schema": "http://json-schema.org/draft-07/schema#", "title": "SimulateSwapOperationsResponse", + "description": "The response for the `SimulateSwapOperations` query.", "type": "object", "required": [ "amount" ], "properties": { "amount": { - "$ref": "#/definitions/Uint128" + "description": "The amount of the final token after the swap operations.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] } }, "additionalProperties": false, @@ -1532,19 +1652,44 @@ ], "properties": { "burn_fee_amount": { - "$ref": "#/definitions/Uint128" + "description": "The burn fee amount of the swap.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] }, "protocol_fee_amount": { - "$ref": "#/definitions/Uint128" + "description": "The protocol fee amount of the swap.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] }, "return_amount": { - "$ref": "#/definitions/Uint128" + "description": "The return amount of the ask asset given the offer amount.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] }, "spread_amount": { - "$ref": "#/definitions/Uint128" + "description": "The spread amount of the swap.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] }, "swap_fee_amount": { - "$ref": "#/definitions/Uint128" + "description": "The swap fee amount of the swap.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] } }, "additionalProperties": false, @@ -1558,20 +1703,28 @@ "swap_route": { "$schema": "http://json-schema.org/draft-07/schema#", "title": "SwapRouteResponse", + "description": "The response for the `SwapRoute` query.", "type": "object", "required": [ "swap_route" ], "properties": { "swap_route": { - "$ref": "#/definitions/SwapRoute" + "description": "The swap route taken for the queried swap.", + "allOf": [ + { + "$ref": "#/definitions/SwapRoute" + } + ] } }, "additionalProperties": false, "definitions": { "SwapOperation": { + "description": "The type of swap operation to perform.", "oneOf": [ { + "description": "A swap operation that uses the WhaleSwap router.", "type": "object", "required": [ "whale_swap" @@ -1586,12 +1739,15 @@ ], "properties": { "pool_identifier": { + "description": "The identifier of the pool to use for the swap.", "type": "string" }, "token_in_denom": { + "description": "The token denom to swap in.", "type": "string" }, "token_out_denom": { + "description": "The token denom returning from the swap.", "type": "string" } }, @@ -1603,6 +1759,7 @@ ] }, "SwapRoute": { + "description": "The swap route structure", "type": "object", "required": [ "ask_asset_denom", @@ -1611,12 +1768,15 @@ ], "properties": { "ask_asset_denom": { + "description": "The ask asset denom, i.e. the asset that is being received.", "type": "string" }, "offer_asset_denom": { + "description": "The offer asset denom, i.e. the asset that is being swapped.", "type": "string" }, "swap_operations": { + "description": "The swap operations to perform to get from offer asset to ask asset.", "type": "array", "items": { "$ref": "#/definitions/SwapOperation" @@ -1630,12 +1790,14 @@ "swap_route_creator": { "$schema": "http://json-schema.org/draft-07/schema#", "title": "SwapRouteCreatorResponse", + "description": "The response for the `SwapRouteCreator` query.", "type": "object", "required": [ "creator" ], "properties": { "creator": { + "description": "The creator of the swap route.", "type": "string" } }, @@ -1644,12 +1806,14 @@ "swap_routes": { "$schema": "http://json-schema.org/draft-07/schema#", "title": "SwapRoutesResponse", + "description": "The response for the `SwapRoutes` query.", "type": "object", "required": [ "swap_routes" ], "properties": { "swap_routes": { + "description": "The swap routes registered in the contract.", "type": "array", "items": { "$ref": "#/definitions/SwapRoute" @@ -1659,8 +1823,10 @@ "additionalProperties": false, "definitions": { "SwapOperation": { + "description": "The type of swap operation to perform.", "oneOf": [ { + "description": "A swap operation that uses the WhaleSwap router.", "type": "object", "required": [ "whale_swap" @@ -1675,12 +1841,15 @@ ], "properties": { "pool_identifier": { + "description": "The identifier of the pool to use for the swap.", "type": "string" }, "token_in_denom": { + "description": "The token denom to swap in.", "type": "string" }, "token_out_denom": { + "description": "The token denom returning from the swap.", "type": "string" } }, @@ -1692,6 +1861,7 @@ ] }, "SwapRoute": { + "description": "The swap route structure", "type": "object", "required": [ "ask_asset_denom", @@ -1700,12 +1870,15 @@ ], "properties": { "ask_asset_denom": { + "description": "The ask asset denom, i.e. the asset that is being received.", "type": "string" }, "offer_asset_denom": { + "description": "The offer asset denom, i.e. the asset that is being swapped.", "type": "string" }, "swap_operations": { + "description": "The swap operations to perform to get from offer asset to ask asset.", "type": "array", "items": { "$ref": "#/definitions/SwapOperation" diff --git a/contracts/liquidity_hub/pool-manager/schema/raw/execute.json b/contracts/liquidity_hub/pool-manager/schema/raw/execute.json index 15e611b06..e40859b6b 100644 --- a/contracts/liquidity_hub/pool-manager/schema/raw/execute.json +++ b/contracts/liquidity_hub/pool-manager/schema/raw/execute.json @@ -493,7 +493,7 @@ ] }, "FeatureToggle": { - "description": "Pool feature toggle", + "description": "Pool feature toggle, can control whether swaps, deposits, and withdrawals are enabled.", "type": "object", "required": [ "deposits_enabled", @@ -502,12 +502,15 @@ ], "properties": { "deposits_enabled": { + "description": "Whether or not deposits are enabled", "type": "boolean" }, "swaps_enabled": { + "description": "Whether or not swaps are enabled", "type": "boolean" }, "withdrawals_enabled": { + "description": "Whether or not swaps are enabled", "type": "boolean" } }, @@ -570,14 +573,10 @@ "additionalProperties": false }, "PoolType": { + "description": "Possible pool types, it can be either a constant product (xyk) pool or a stable swap pool.", "oneOf": [ { - "type": "string", - "enum": [ - "constant_product" - ] - }, - { + "description": "A stable swap pool.", "type": "object", "required": [ "stable_swap" @@ -600,12 +599,21 @@ } }, "additionalProperties": false + }, + { + "description": "xyk pool", + "type": "string", + "enum": [ + "constant_product" + ] } ] }, "SwapOperation": { + "description": "The type of swap operation to perform.", "oneOf": [ { + "description": "A swap operation that uses the WhaleSwap router.", "type": "object", "required": [ "whale_swap" @@ -620,12 +628,15 @@ ], "properties": { "pool_identifier": { + "description": "The identifier of the pool to use for the swap.", "type": "string" }, "token_in_denom": { + "description": "The token denom to swap in.", "type": "string" }, "token_out_denom": { + "description": "The token denom returning from the swap.", "type": "string" } }, @@ -637,6 +648,7 @@ ] }, "SwapRoute": { + "description": "The swap route structure", "type": "object", "required": [ "ask_asset_denom", @@ -645,12 +657,15 @@ ], "properties": { "ask_asset_denom": { + "description": "The ask asset denom, i.e. the asset that is being received.", "type": "string" }, "offer_asset_denom": { + "description": "The offer asset denom, i.e. the asset that is being swapped.", "type": "string" }, "swap_operations": { + "description": "The swap operations to perform to get from offer asset to ask asset.", "type": "array", "items": { "$ref": "#/definitions/SwapOperation" diff --git a/contracts/liquidity_hub/pool-manager/schema/raw/instantiate.json b/contracts/liquidity_hub/pool-manager/schema/raw/instantiate.json index 8fdc47956..f73769af3 100644 --- a/contracts/liquidity_hub/pool-manager/schema/raw/instantiate.json +++ b/contracts/liquidity_hub/pool-manager/schema/raw/instantiate.json @@ -9,13 +9,20 @@ ], "properties": { "bonding_manager_addr": { + "description": "The address of the bonding manager contract.", "type": "string" }, "incentive_manager_addr": { + "description": "The address of the incentive manager contract.", "type": "string" }, "pool_creation_fee": { - "$ref": "#/definitions/Coin" + "description": "How much it costs to create a pool. It helps prevent spamming of new pools.", + "allOf": [ + { + "$ref": "#/definitions/Coin" + } + ] } }, "additionalProperties": false, diff --git a/contracts/liquidity_hub/pool-manager/schema/raw/migrate.json b/contracts/liquidity_hub/pool-manager/schema/raw/migrate.json index be217b7d3..7fbe8c570 100644 --- a/contracts/liquidity_hub/pool-manager/schema/raw/migrate.json +++ b/contracts/liquidity_hub/pool-manager/schema/raw/migrate.json @@ -1,7 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "title": "MigrateMsg", - "description": "The migrate message", "type": "object", "additionalProperties": false } diff --git a/contracts/liquidity_hub/pool-manager/schema/raw/query.json b/contracts/liquidity_hub/pool-manager/schema/raw/query.json index f8f2f798c..e9162721d 100644 --- a/contracts/liquidity_hub/pool-manager/schema/raw/query.json +++ b/contracts/liquidity_hub/pool-manager/schema/raw/query.json @@ -4,17 +4,10 @@ "oneOf": [ { "description": "Retrieves the contract's config.", - "type": "object", - "required": [ + "type": "string", + "enum": [ "config" - ], - "properties": { - "config": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false + ] }, { "description": "Retrieves the decimals for the given asset.", @@ -31,9 +24,11 @@ ], "properties": { "denom": { + "description": "The queried denom in the given pool_identifier.", "type": "string" }, "pool_identifier": { + "description": "The pool identifier to do the query for.", "type": "string" } }, @@ -57,9 +52,15 @@ ], "properties": { "offer_asset": { - "$ref": "#/definitions/Coin" + "description": "The offer asset to swap.", + "allOf": [ + { + "$ref": "#/definitions/Coin" + } + ] }, "pool_identifier": { + "description": "The pool identifier to swap in.", "type": "string" } }, @@ -79,17 +80,19 @@ "type": "object", "required": [ "ask_asset", - "offer_asset", "pool_identifier" ], "properties": { "ask_asset": { - "$ref": "#/definitions/Coin" - }, - "offer_asset": { - "$ref": "#/definitions/Coin" + "description": "The ask asset to get after the swap.", + "allOf": [ + { + "$ref": "#/definitions/Coin" + } + ] }, "pool_identifier": { + "description": "The pool identifier to swap in.", "type": "string" } }, @@ -113,9 +116,11 @@ ], "properties": { "ask_asset_denom": { + "description": "The ask asset denom, i.e. the asset that is being received.", "type": "string" }, "offer_asset_denom": { + "description": "The offer asset denom, i.e. the asset that is being swapped.", "type": "string" } }, @@ -126,17 +131,10 @@ }, { "description": "Gets all swap routes registered", - "type": "object", - "required": [ + "type": "string", + "enum": [ "swap_routes" - ], - "properties": { - "swap_routes": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false + ] }, { "description": "Simulates swap operations.", @@ -153,9 +151,15 @@ ], "properties": { "offer_amount": { - "$ref": "#/definitions/Uint128" + "description": "The amount to swap.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] }, "operations": { + "description": "The operations to perform.", "type": "array", "items": { "$ref": "#/definitions/SwapOperation" @@ -182,9 +186,15 @@ ], "properties": { "ask_amount": { - "$ref": "#/definitions/Uint128" + "description": "The amount to get after the swap.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] }, "operations": { + "description": "The operations to perform.", "type": "array", "items": { "$ref": "#/definitions/SwapOperation" @@ -197,6 +207,7 @@ "additionalProperties": false }, { + "description": "Retrieves the pool information for the given pool identifier.", "type": "object", "required": [ "pool" @@ -218,7 +229,7 @@ "additionalProperties": false }, { - "description": "Retrieves the creator of the swap routes that can then remove them.", + "description": "Retrieves the creator of the swap route to get from offer to ask asset. The creator of the swap route can remove it.", "type": "object", "required": [ "swap_route_creator" @@ -232,9 +243,11 @@ ], "properties": { "ask_asset_denom": { + "description": "The ask asset denom, i.e. the asset that is being received.", "type": "string" }, "offer_asset_denom": { + "description": "The offer asset denom, i.e. the asset that is being swapped.", "type": "string" } }, @@ -275,8 +288,10 @@ } }, "SwapOperation": { + "description": "The type of swap operation to perform.", "oneOf": [ { + "description": "A swap operation that uses the WhaleSwap router.", "type": "object", "required": [ "whale_swap" @@ -291,12 +306,15 @@ ], "properties": { "pool_identifier": { + "description": "The identifier of the pool to use for the swap.", "type": "string" }, "token_in_denom": { + "description": "The token denom to swap in.", "type": "string" }, "token_out_denom": { + "description": "The token denom returning from the swap.", "type": "string" } }, diff --git a/contracts/liquidity_hub/pool-manager/schema/raw/response_to_config.json b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_config.json index b1b907f1e..b9a36357c 100644 --- a/contracts/liquidity_hub/pool-manager/schema/raw/response_to_config.json +++ b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_config.json @@ -1,13 +1,19 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "title": "ConfigResponse", + "description": "The response for the `Config` query.", "type": "object", "required": [ "config" ], "properties": { "config": { - "$ref": "#/definitions/Config" + "description": "The contract configuration.", + "allOf": [ + { + "$ref": "#/definitions/Config" + } + ] } }, "additionalProperties": false, @@ -32,6 +38,7 @@ } }, "Config": { + "description": "The contract configuration.", "type": "object", "required": [ "bonding_manager_addr", @@ -60,13 +67,18 @@ ] }, "pool_creation_fee": { - "$ref": "#/definitions/Coin" + "description": "How much it costs to create a pool. It helps prevent spamming of new pools.", + "allOf": [ + { + "$ref": "#/definitions/Coin" + } + ] } }, "additionalProperties": false }, "FeatureToggle": { - "description": "Pool feature toggle", + "description": "Pool feature toggle, can control whether swaps, deposits, and withdrawals are enabled.", "type": "object", "required": [ "deposits_enabled", @@ -75,12 +87,15 @@ ], "properties": { "deposits_enabled": { + "description": "Whether or not deposits are enabled", "type": "boolean" }, "swaps_enabled": { + "description": "Whether or not swaps are enabled", "type": "boolean" }, "withdrawals_enabled": { + "description": "Whether or not swaps are enabled", "type": "boolean" } }, diff --git a/contracts/liquidity_hub/pool-manager/schema/raw/response_to_pool.json b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_pool.json index 9a3ce9fcb..ac073d626 100644 --- a/contracts/liquidity_hub/pool-manager/schema/raw/response_to_pool.json +++ b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_pool.json @@ -1,6 +1,7 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "title": "PoolInfoResponse", + "description": "The response for the `Pool` query.", "type": "object", "required": [ "pool_info", @@ -8,10 +9,20 @@ ], "properties": { "pool_info": { - "$ref": "#/definitions/PoolInfo" + "description": "The pool information for the given pool identifier.", + "allOf": [ + { + "$ref": "#/definitions/PoolInfo" + } + ] }, "total_share": { - "$ref": "#/definitions/Coin" + "description": "The total LP tokens in the pool.", + "allOf": [ + { + "$ref": "#/definitions/Coin" + } + ] } }, "additionalProperties": false, @@ -92,6 +103,7 @@ "additionalProperties": false }, "PoolInfo": { + "description": "Contains the pool information", "type": "object", "required": [ "asset_decimals", @@ -103,6 +115,7 @@ ], "properties": { "asset_decimals": { + "description": "The decimals for the given asset denoms, provided in the same order as asset_denoms.", "type": "array", "items": { "type": "integer", @@ -111,38 +124,47 @@ } }, "asset_denoms": { + "description": "The asset denoms for the pool.", "type": "array", "items": { "type": "string" } }, "assets": { + "description": "The total amount of assets in the pool.", "type": "array", "items": { "$ref": "#/definitions/Coin" } }, "lp_denom": { + "description": "The LP denom of the pool.", "type": "string" }, "pool_fees": { - "$ref": "#/definitions/PoolFee" + "description": "The fees for the pool.", + "allOf": [ + { + "$ref": "#/definitions/PoolFee" + } + ] }, "pool_type": { - "$ref": "#/definitions/PoolType" + "description": "The type of pool to create.", + "allOf": [ + { + "$ref": "#/definitions/PoolType" + } + ] } }, "additionalProperties": false }, "PoolType": { + "description": "Possible pool types, it can be either a constant product (xyk) pool or a stable swap pool.", "oneOf": [ { - "type": "string", - "enum": [ - "constant_product" - ] - }, - { + "description": "A stable swap pool.", "type": "object", "required": [ "stable_swap" @@ -165,6 +187,13 @@ } }, "additionalProperties": false + }, + { + "description": "xyk pool", + "type": "string", + "enum": [ + "constant_product" + ] } ] }, diff --git a/contracts/liquidity_hub/pool-manager/schema/raw/response_to_reverse_simulate_swap_operations.json b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_reverse_simulate_swap_operations.json index 6e6216b7e..9c364c10a 100644 --- a/contracts/liquidity_hub/pool-manager/schema/raw/response_to_reverse_simulate_swap_operations.json +++ b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_reverse_simulate_swap_operations.json @@ -1,13 +1,19 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "title": "ReverseSimulateSwapOperationsResponse", + "description": "The response for the `ReverseSimulateSwapOperations` query.", "type": "object", "required": [ "amount" ], "properties": { "amount": { - "$ref": "#/definitions/Uint128" + "description": "The amount of the initial token needed to get the final token after the swap operations.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] } }, "additionalProperties": false, diff --git a/contracts/liquidity_hub/pool-manager/schema/raw/response_to_reverse_simulation.json b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_reverse_simulation.json index 93cb52989..f901b023c 100644 --- a/contracts/liquidity_hub/pool-manager/schema/raw/response_to_reverse_simulation.json +++ b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_reverse_simulation.json @@ -12,19 +12,44 @@ ], "properties": { "burn_fee_amount": { - "$ref": "#/definitions/Uint128" + "description": "The burn fee amount of the swap.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] }, "offer_amount": { - "$ref": "#/definitions/Uint128" + "description": "The amount of the offer asset needed to get the ask amount.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] }, "protocol_fee_amount": { - "$ref": "#/definitions/Uint128" + "description": "The protocol fee amount of the swap.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] }, "spread_amount": { - "$ref": "#/definitions/Uint128" + "description": "The spread amount of the swap.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] }, "swap_fee_amount": { - "$ref": "#/definitions/Uint128" + "description": "The swap fee amount of the swap.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] } }, "additionalProperties": false, diff --git a/contracts/liquidity_hub/pool-manager/schema/raw/response_to_simulate_swap_operations.json b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_simulate_swap_operations.json index b15e18ee0..80f0fc325 100644 --- a/contracts/liquidity_hub/pool-manager/schema/raw/response_to_simulate_swap_operations.json +++ b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_simulate_swap_operations.json @@ -1,13 +1,19 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "title": "SimulateSwapOperationsResponse", + "description": "The response for the `SimulateSwapOperations` query.", "type": "object", "required": [ "amount" ], "properties": { "amount": { - "$ref": "#/definitions/Uint128" + "description": "The amount of the final token after the swap operations.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] } }, "additionalProperties": false, diff --git a/contracts/liquidity_hub/pool-manager/schema/raw/response_to_simulation.json b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_simulation.json index d364c2b5a..7faa00a3c 100644 --- a/contracts/liquidity_hub/pool-manager/schema/raw/response_to_simulation.json +++ b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_simulation.json @@ -12,19 +12,44 @@ ], "properties": { "burn_fee_amount": { - "$ref": "#/definitions/Uint128" + "description": "The burn fee amount of the swap.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] }, "protocol_fee_amount": { - "$ref": "#/definitions/Uint128" + "description": "The protocol fee amount of the swap.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] }, "return_amount": { - "$ref": "#/definitions/Uint128" + "description": "The return amount of the ask asset given the offer amount.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] }, "spread_amount": { - "$ref": "#/definitions/Uint128" + "description": "The spread amount of the swap.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] }, "swap_fee_amount": { - "$ref": "#/definitions/Uint128" + "description": "The swap fee amount of the swap.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] } }, "additionalProperties": false, diff --git a/contracts/liquidity_hub/pool-manager/schema/raw/response_to_swap_route.json b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_swap_route.json index 82801ed31..c988b63ec 100644 --- a/contracts/liquidity_hub/pool-manager/schema/raw/response_to_swap_route.json +++ b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_swap_route.json @@ -1,20 +1,28 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "title": "SwapRouteResponse", + "description": "The response for the `SwapRoute` query.", "type": "object", "required": [ "swap_route" ], "properties": { "swap_route": { - "$ref": "#/definitions/SwapRoute" + "description": "The swap route taken for the queried swap.", + "allOf": [ + { + "$ref": "#/definitions/SwapRoute" + } + ] } }, "additionalProperties": false, "definitions": { "SwapOperation": { + "description": "The type of swap operation to perform.", "oneOf": [ { + "description": "A swap operation that uses the WhaleSwap router.", "type": "object", "required": [ "whale_swap" @@ -29,12 +37,15 @@ ], "properties": { "pool_identifier": { + "description": "The identifier of the pool to use for the swap.", "type": "string" }, "token_in_denom": { + "description": "The token denom to swap in.", "type": "string" }, "token_out_denom": { + "description": "The token denom returning from the swap.", "type": "string" } }, @@ -46,6 +57,7 @@ ] }, "SwapRoute": { + "description": "The swap route structure", "type": "object", "required": [ "ask_asset_denom", @@ -54,12 +66,15 @@ ], "properties": { "ask_asset_denom": { + "description": "The ask asset denom, i.e. the asset that is being received.", "type": "string" }, "offer_asset_denom": { + "description": "The offer asset denom, i.e. the asset that is being swapped.", "type": "string" }, "swap_operations": { + "description": "The swap operations to perform to get from offer asset to ask asset.", "type": "array", "items": { "$ref": "#/definitions/SwapOperation" diff --git a/contracts/liquidity_hub/pool-manager/schema/raw/response_to_swap_route_creator.json b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_swap_route_creator.json index 825c4ef49..0c80f1348 100644 --- a/contracts/liquidity_hub/pool-manager/schema/raw/response_to_swap_route_creator.json +++ b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_swap_route_creator.json @@ -1,12 +1,14 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "title": "SwapRouteCreatorResponse", + "description": "The response for the `SwapRouteCreator` query.", "type": "object", "required": [ "creator" ], "properties": { "creator": { + "description": "The creator of the swap route.", "type": "string" } }, diff --git a/contracts/liquidity_hub/pool-manager/schema/raw/response_to_swap_routes.json b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_swap_routes.json index c1f6e47c1..4096e3684 100644 --- a/contracts/liquidity_hub/pool-manager/schema/raw/response_to_swap_routes.json +++ b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_swap_routes.json @@ -1,12 +1,14 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "title": "SwapRoutesResponse", + "description": "The response for the `SwapRoutes` query.", "type": "object", "required": [ "swap_routes" ], "properties": { "swap_routes": { + "description": "The swap routes registered in the contract.", "type": "array", "items": { "$ref": "#/definitions/SwapRoute" @@ -16,8 +18,10 @@ "additionalProperties": false, "definitions": { "SwapOperation": { + "description": "The type of swap operation to perform.", "oneOf": [ { + "description": "A swap operation that uses the WhaleSwap router.", "type": "object", "required": [ "whale_swap" @@ -32,12 +36,15 @@ ], "properties": { "pool_identifier": { + "description": "The identifier of the pool to use for the swap.", "type": "string" }, "token_in_denom": { + "description": "The token denom to swap in.", "type": "string" }, "token_out_denom": { + "description": "The token denom returning from the swap.", "type": "string" } }, @@ -49,6 +56,7 @@ ] }, "SwapRoute": { + "description": "The swap route structure", "type": "object", "required": [ "ask_asset_denom", @@ -57,12 +65,15 @@ ], "properties": { "ask_asset_denom": { + "description": "The ask asset denom, i.e. the asset that is being received.", "type": "string" }, "offer_asset_denom": { + "description": "The offer asset denom, i.e. the asset that is being swapped.", "type": "string" }, "swap_operations": { + "description": "The swap operations to perform to get from offer asset to ask asset.", "type": "array", "items": { "$ref": "#/definitions/SwapOperation" diff --git a/contracts/liquidity_hub/pool-manager/src/contract.rs b/contracts/liquidity_hub/pool-manager/src/contract.rs index fc3ae0bb2..71d7a6a18 100644 --- a/contracts/liquidity_hub/pool-manager/src/contract.rs +++ b/contracts/liquidity_hub/pool-manager/src/contract.rs @@ -191,7 +191,7 @@ pub fn execute( #[cfg_attr(not(feature = "library"), entry_point)] pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result { match msg { - QueryMsg::Config {} => Ok(to_json_binary(&queries::query_config(deps)?)?), + QueryMsg::Config => Ok(to_json_binary(&queries::query_config(deps)?)?), QueryMsg::AssetDecimals { pool_identifier, denom, @@ -210,13 +210,11 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result Ok(to_json_binary(&queries::query_reverse_simulation( deps, env, ask_asset, - offer_asset, pool_identifier, )?)?), QueryMsg::SimulateSwapOperations { @@ -241,7 +239,7 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result Ok(to_json_binary(&queries::get_swap_routes(deps)?)?), + QueryMsg::SwapRoutes => Ok(to_json_binary(&queries::get_swap_routes(deps)?)?), QueryMsg::Ownership {} => Ok(to_json_binary(&cw_ownable::get_ownership(deps.storage)?)?), QueryMsg::Pool { pool_identifier } => { Ok(to_json_binary(&queries::get_pool(deps, pool_identifier)?)?) diff --git a/contracts/liquidity_hub/pool-manager/src/queries.rs b/contracts/liquidity_hub/pool-manager/src/queries.rs index c4227798d..90d826f4c 100644 --- a/contracts/liquidity_hub/pool-manager/src/queries.rs +++ b/contracts/liquidity_hub/pool-manager/src/queries.rs @@ -115,7 +115,6 @@ pub fn query_reverse_simulation( deps: Deps, _env: Env, ask_asset: Coin, - _offer_asset: Coin, pool_identifier: String, ) -> Result { let pool_info = get_pool_by_identifier(&deps, &pool_identifier)?; diff --git a/contracts/liquidity_hub/pool-manager/src/tests/suite.rs b/contracts/liquidity_hub/pool-manager/src/tests/suite.rs index 09f56c42e..ff94f0c2a 100644 --- a/contracts/liquidity_hub/pool-manager/src/tests/suite.rs +++ b/contracts/liquidity_hub/pool-manager/src/tests/suite.rs @@ -597,10 +597,6 @@ impl TestingSuite { self.app.wrap().query_wasm_smart( &self.pool_manager_addr, &white_whale_std::pool_manager::QueryMsg::ReverseSimulation { - offer_asset: Coin { - amount: Uint128::zero(), - denom: offer_asset, - }, ask_asset, pool_identifier, }, @@ -688,7 +684,7 @@ impl TestingSuite { .wrap() .query_wasm_smart( &self.pool_manager_addr, - &white_whale_std::pool_manager::QueryMsg::Config {}, + &white_whale_std::pool_manager::QueryMsg::Config, ) .unwrap() } @@ -720,7 +716,7 @@ impl TestingSuite { ) -> &mut Self { let swap_routes_response: StdResult = self.app.wrap().query_wasm_smart( &self.pool_manager_addr, - &white_whale_std::pool_manager::QueryMsg::SwapRoutes {}, + &white_whale_std::pool_manager::QueryMsg::SwapRoutes, ); result(swap_routes_response); diff --git a/packages/white-whale-std/src/pool_manager.rs b/packages/white-whale-std/src/pool_manager.rs index 62c606f0d..b1623b791 100644 --- a/packages/white-whale-std/src/pool_manager.rs +++ b/packages/white-whale-std/src/pool_manager.rs @@ -5,11 +5,16 @@ use cosmwasm_schema::{cw_serde, QueryResponses}; use cosmwasm_std::{Addr, Coin, Decimal, Uint128}; use cw_ownable::{cw_ownable_execute, cw_ownable_query}; +/// The type of swap operation to perform. #[cw_serde] pub enum SwapOperation { + /// A swap operation that uses the WhaleSwap router. WhaleSwap { + /// The token denom to swap in. token_in_denom: String, + /// The token denom returning from the swap. token_out_denom: String, + /// The identifier of the pool to use for the swap. pool_identifier: String, }, } @@ -47,16 +52,21 @@ impl fmt::Display for SwapOperation { } } +/// The swap route structure #[cw_serde] pub struct SwapRoute { + /// The offer asset denom, i.e. the asset that is being swapped. pub offer_asset_denom: String, + /// The ask asset denom, i.e. the asset that is being received. pub ask_asset_denom: String, + /// The swap operations to perform to get from offer asset to ask asset. pub swap_operations: Vec, } -// Used for all swap routes +/// The response for the `SwapRoute` query. #[cw_serde] pub struct SwapRouteResponse { + /// The swap route taken for the queried swap. pub swap_route: SwapRoute, } @@ -70,7 +80,8 @@ impl fmt::Display for SwapRoute { } } -// Define a structure for Fees which names a number of defined fee collection types, maybe leaving room for a custom room a user can use to pass a fee with a defined custom name +// Defines a structure for Fees which names a number of defined fee collection types, leaving +// room for a custom fee a user can use to pass a fee with a defined custom name #[cw_serde] pub enum FeeTypes { Protocol, @@ -79,35 +90,48 @@ pub enum FeeTypes { Custom(String), } +/// Params for the stable swap, used when changing the amplification factor #[cw_serde] - pub struct StableSwapParams { + /// Initial amplification factor pub initial_amp: String, + /// Future amplification factor, i.e. target pub future_amp: String, + /// Block height when the initial amplification factor kicks in. It goes gradually from the + /// initial to the future amplification factor between the given blocks. pub initial_amp_block: String, + /// Block height when the future amplification factor will be set. It goes gradually from the + /// initial to the future amplification factor between the given blocks. pub future_amp_block: String, } -// Store PoolInfo to N -// We define a custom struct for which allows for dynamic but defined pools +/// Contains the pool information #[cw_serde] pub struct PoolInfo { + /// The asset denoms for the pool. pub asset_denoms: Vec, + /// The LP denom of the pool. pub lp_denom: String, + /// The decimals for the given asset denoms, provided in the same order as asset_denoms. pub asset_decimals: Vec, + /// The total amount of assets in the pool. pub assets: Vec, + /// The type of pool to create. pub pool_type: PoolType, + /// The fees for the pool. pub pool_fees: PoolFee, //pub stable_swap_params: Option } -impl PoolInfo {} +/// Possible pool types, it can be either a constant product (xyk) pool or a stable swap pool. #[cw_serde] pub enum PoolType { + /// A stable swap pool. StableSwap { /// The amount of amplification to perform on the constant product part of the swap formula. amp: u64, }, + /// xyk pool ConstantProduct, } @@ -121,13 +145,14 @@ impl PoolType { } } +/// The contract configuration. #[cw_serde] pub struct Config { /// The address of the bonding manager contract. pub bonding_manager_addr: Addr, /// The address of the incentive manager contract. pub incentive_manager_addr: Addr, - // We must set a creation fee on instantiation to prevent spamming of pools + /// How much it costs to create a pool. It helps prevent spamming of new pools. pub pool_creation_fee: Coin, // Whether or not swaps, deposits, and withdrawals are enabled pub feature_toggle: FeatureToggle, @@ -135,12 +160,14 @@ pub struct Config { #[cw_serde] pub struct InstantiateMsg { + /// The address of the bonding manager contract. pub bonding_manager_addr: String, + /// The address of the incentive manager contract. pub incentive_manager_addr: String, + /// How much it costs to create a pool. It helps prevent spamming of new pools. pub pool_creation_fee: Coin, } -/// The migrate message #[cw_serde] pub struct MigrateMsg {} @@ -239,77 +266,94 @@ pub enum ExecuteMsg { pub enum QueryMsg { /// Retrieves the contract's config. #[returns(ConfigResponse)] - Config {}, - + Config, /// Retrieves the decimals for the given asset. #[returns(AssetDecimalsResponse)] AssetDecimals { + /// The pool identifier to do the query for. pool_identifier: String, + /// The queried denom in the given pool_identifier. denom: String, }, - /// Simulates a swap. #[returns(SimulationResponse)] Simulation { + /// The offer asset to swap. offer_asset: Coin, + /// The pool identifier to swap in. pool_identifier: String, }, - /// Simulates a reverse swap, i.e. given the ask asset, how much of the offer asset is needed to - /// perform the swap. + /// Simulates a reverse swap, i.e. given the ask asset, how much of the offer asset is needed + /// to perform the swap. #[returns(ReverseSimulationResponse)] ReverseSimulation { + /// The ask asset to get after the swap. ask_asset: Coin, - offer_asset: Coin, + /// The pool identifier to swap in. pool_identifier: String, }, - /// Gets the swap route for the given offer and ask assets. #[returns(SwapRouteResponse)] SwapRoute { + /// The offer asset denom, i.e. the asset that is being swapped. offer_asset_denom: String, + /// The ask asset denom, i.e. the asset that is being received. ask_asset_denom: String, }, /// Gets all swap routes registered #[returns(SwapRoutesResponse)] - SwapRoutes {}, - + SwapRoutes, /// Simulates swap operations. #[returns(SimulateSwapOperationsResponse)] SimulateSwapOperations { + /// The amount to swap. offer_amount: Uint128, + /// The operations to perform. operations: Vec, }, /// Simulates a reverse swap operations, i.e. given the ask asset, how much of the offer asset /// is needed to perform the swap. #[returns(ReverseSimulateSwapOperationsResponse)] ReverseSimulateSwapOperations { + /// The amount to get after the swap. ask_amount: Uint128, + /// The operations to perform. operations: Vec, }, - + /// Retrieves the pool information for the given pool identifier. #[returns(PoolInfoResponse)] Pool { pool_identifier: String }, - /// Retrieves the creator of the swap routes that can then remove them. + /// Retrieves the creator of the swap route to get from offer to ask asset. The creator of + /// the swap route can remove it. #[returns(SwapRouteCreatorResponse)] SwapRouteCreator { + /// The offer asset denom, i.e. the asset that is being swapped. offer_asset_denom: String, + /// The ask asset denom, i.e. the asset that is being received. ask_asset_denom: String, }, } +/// The response for the `Config` query. #[cw_serde] pub struct ConfigResponse { + /// The contract configuration. pub config: Config, } +/// The response for the `SwapRoutes` query. #[cw_serde] pub struct SwapRoutesResponse { + /// The swap routes registered in the contract. pub swap_routes: Vec, } +/// The response for the `Pool` query. #[cw_serde] pub struct PoolInfoResponse { + /// The pool information for the given pool identifier. pub pool_info: PoolInfo, + /// The total LP tokens in the pool. pub total_share: Coin, } @@ -327,11 +371,17 @@ pub struct AssetDecimalsResponse { /// SimulationResponse returns swap simulation response #[cw_serde] pub struct SimulationResponse { + /// The return amount of the ask asset given the offer amount. pub return_amount: Uint128, + /// The spread amount of the swap. pub spread_amount: Uint128, + /// The swap fee amount of the swap. pub swap_fee_amount: Uint128, + /// The protocol fee amount of the swap. pub protocol_fee_amount: Uint128, + /// The burn fee amount of the swap. pub burn_fee_amount: Uint128, + /// The fee amount of the swap going to the osmosis community pool. #[cfg(feature = "osmosis")] pub osmosis_fee_amount: Uint128, } @@ -339,35 +389,49 @@ pub struct SimulationResponse { /// ReverseSimulationResponse returns reverse swap simulation response #[cw_serde] pub struct ReverseSimulationResponse { + /// The amount of the offer asset needed to get the ask amount. pub offer_amount: Uint128, + /// The spread amount of the swap. pub spread_amount: Uint128, + /// The swap fee amount of the swap. pub swap_fee_amount: Uint128, + /// The protocol fee amount of the swap. pub protocol_fee_amount: Uint128, + /// The burn fee amount of the swap. pub burn_fee_amount: Uint128, + /// The fee amount of the swap going to the osmosis community pool. #[cfg(feature = "osmosis")] pub osmosis_fee_amount: Uint128, } -/// Pool feature toggle +/// Pool feature toggle, can control whether swaps, deposits, and withdrawals are enabled. #[cw_serde] pub struct FeatureToggle { + /// Whether or not swaps are enabled pub withdrawals_enabled: bool, + /// Whether or not deposits are enabled pub deposits_enabled: bool, + /// Whether or not swaps are enabled pub swaps_enabled: bool, } -// We define a custom struct for each query response +/// The response for the `SimulateSwapOperations` query. #[cw_serde] pub struct SimulateSwapOperationsResponse { + /// The amount of the final token after the swap operations. pub amount: Uint128, } +/// The response for the `ReverseSimulateSwapOperations` query. #[cw_serde] pub struct ReverseSimulateSwapOperationsResponse { + /// The amount of the initial token needed to get the final token after the swap operations. pub amount: Uint128, } +/// The response for the `SwapRouteCreator` query. #[cw_serde] pub struct SwapRouteCreatorResponse { + /// The creator of the swap route. pub creator: String, } From 809b24e230fd02631bcd365bee4ae67c784e6ef6 Mon Sep 17 00:00:00 2001 From: Kerber0x Date: Fri, 3 May 2024 16:10:44 +0100 Subject: [PATCH 5/7] refactor: swap --- .../liquidity_hub/pool-manager/src/helpers.rs | 299 ++++---- .../liquidity_hub/pool-manager/src/queries.rs | 2 + .../pool-manager/src/router/commands.rs | 5 +- .../pool-manager/src/swap/commands.rs | 5 +- .../pool-manager/src/swap/perform_swap.rs | 85 +-- .../src/tests/integration_tests.rs | 681 +++++++++++++++++- .../pool-manager/src/tests/suite.rs | 1 - packages/white-whale-std/src/pool_manager.rs | 2 + 8 files changed, 906 insertions(+), 174 deletions(-) diff --git a/contracts/liquidity_hub/pool-manager/src/helpers.rs b/contracts/liquidity_hub/pool-manager/src/helpers.rs index 594d28dea..a3ea5ccc3 100644 --- a/contracts/liquidity_hub/pool-manager/src/helpers.rs +++ b/contracts/liquidity_hub/pool-manager/src/helpers.rs @@ -138,6 +138,7 @@ pub fn calculate_stableswap_y( Err(ContractError::ConvergeError) } +/// computes a swap pub fn compute_swap( offer_pool: Uint128, ask_pool: Uint128, @@ -161,71 +162,14 @@ pub fn compute_swap( // calculate spread, swap and protocol fees let exchange_rate = Decimal256::from_ratio(ask_pool, offer_pool); let spread_amount: Uint256 = (offer_amount * exchange_rate) - return_amount; - let swap_fee_amount: Uint256 = pool_fees.swap_fee.compute(return_amount); - let protocol_fee_amount: Uint256 = pool_fees.protocol_fee.compute(return_amount); - let burn_fee_amount: Uint256 = pool_fees.burn_fee.compute(return_amount); - //todo compute the extra fees - //let extra_fees_amount: Uint256 = pool_fees.extra_fees.compute(return_amount); + let fees_computation = compute_fees(pool_fees, return_amount)?; - // swap and protocol fee will be absorbed by the pool. Burn fee amount will be burned on a subsequent msg. - #[cfg(not(feature = "osmosis"))] - { - let return_amount: Uint256 = return_amount - .checked_sub(swap_fee_amount)? - .checked_sub(protocol_fee_amount)? - .checked_sub(burn_fee_amount)?; - - Ok(SwapComputation { - return_amount: return_amount - .try_into() - .map_err(|_| ContractError::SwapOverflowError)?, - spread_amount: spread_amount - .try_into() - .map_err(|_| ContractError::SwapOverflowError)?, - swap_fee_amount: swap_fee_amount - .try_into() - .map_err(|_| ContractError::SwapOverflowError)?, - protocol_fee_amount: protocol_fee_amount - .try_into() - .map_err(|_| ContractError::SwapOverflowError)?, - burn_fee_amount: burn_fee_amount - .try_into() - .map_err(|_| ContractError::SwapOverflowError)?, - }) - } - - #[cfg(feature = "osmosis")] - { - let osmosis_fee_amount: Uint256 = pool_fees.osmosis_fee.compute(return_amount); - - let return_amount: Uint256 = return_amount - .checked_sub(swap_fee_amount)? - .checked_sub(protocol_fee_amount)? - .checked_sub(burn_fee_amount)? - .checked_sub(osmosis_fee_amount)?; - - Ok(SwapComputation { - return_amount: return_amount - .try_into() - .map_err(|_| ContractError::SwapOverflowError)?, - spread_amount: spread_amount - .try_into() - .map_err(|_| ContractError::SwapOverflowError)?, - swap_fee_amount: swap_fee_amount - .try_into() - .map_err(|_| ContractError::SwapOverflowError)?, - protocol_fee_amount: protocol_fee_amount - .try_into() - .map_err(|_| ContractError::SwapOverflowError)?, - burn_fee_amount: burn_fee_amount - .try_into() - .map_err(|_| ContractError::SwapOverflowError)?, - osmosis_fee_amount: osmosis_fee_amount - .try_into() - .map_err(|_| ContractError::SwapOverflowError)?, - }) - } + Ok(get_swap_computation( + return_amount, + spread_amount, + fees_computation, + )?) } PoolType::StableSwap { amp } => { let offer_pool = Decimal256::decimal_with_precision(offer_pool, offer_precision)?; @@ -251,72 +195,150 @@ pub fn compute_swap( .to_uint256_with_precision(u32::from(ask_precision))? .saturating_sub(return_amount); - // subtract fees from return_amount - let swap_fee_amount: Uint256 = pool_fees.swap_fee.compute(return_amount); - let protocol_fee_amount: Uint256 = pool_fees.protocol_fee.compute(return_amount); - let burn_fee_amount: Uint256 = pool_fees.burn_fee.compute(return_amount); + let fees_computation = compute_fees(pool_fees, return_amount)?; - #[cfg(not(feature = "osmosis"))] - { - let return_amount = return_amount - .checked_sub(swap_fee_amount)? - .checked_sub(protocol_fee_amount)? - .checked_sub(burn_fee_amount)?; - - Ok(SwapComputation { - return_amount: return_amount - .try_into() - .map_err(|_| ContractError::SwapOverflowError)?, - spread_amount: spread_amount - .try_into() - .map_err(|_| ContractError::SwapOverflowError)?, - swap_fee_amount: swap_fee_amount - .try_into() - .map_err(|_| ContractError::SwapOverflowError)?, - protocol_fee_amount: protocol_fee_amount - .try_into() - .map_err(|_| ContractError::SwapOverflowError)?, - burn_fee_amount: burn_fee_amount - .try_into() - .map_err(|_| ContractError::SwapOverflowError)?, - }) - } + Ok(get_swap_computation( + return_amount, + spread_amount, + fees_computation, + )?) + } + } +} - #[cfg(feature = "osmosis")] - { - let osmosis_fee_amount: Uint256 = pool_fees.osmosis_fee.compute(return_amount); - - let return_amount = return_amount - .checked_sub(swap_fee_amount)? - .checked_sub(protocol_fee_amount)? - .checked_sub(burn_fee_amount)? - .checked_sub(osmosis_fee_amount)?; - - Ok(SwapComputation { - return_amount: return_amount - .try_into() - .map_err(|_| ContractError::SwapOverflowError)?, - spread_amount: spread_amount - .try_into() - .map_err(|_| ContractError::SwapOverflowError)?, - swap_fee_amount: swap_fee_amount - .try_into() - .map_err(|_| ContractError::SwapOverflowError)?, - protocol_fee_amount: protocol_fee_amount - .try_into() - .map_err(|_| ContractError::SwapOverflowError)?, - burn_fee_amount: burn_fee_amount - .try_into() - .map_err(|_| ContractError::SwapOverflowError)?, - osmosis_fee_amount: osmosis_fee_amount - .try_into() - .map_err(|_| ContractError::SwapOverflowError)?, - }) - } +/// Computes the pool fees for a given (return) amount +fn compute_fees(pool_fees: PoolFee, amount: Uint256) -> Result { + let swap_fee_amount: Uint256 = pool_fees.swap_fee.compute(amount); + let protocol_fee_amount: Uint256 = pool_fees.protocol_fee.compute(amount); + let burn_fee_amount: Uint256 = pool_fees.burn_fee.compute(amount); + + let extra_fees_amount: Uint256 = if !pool_fees.extra_fees.is_empty() { + let mut extra_fees_amount: Uint256 = Uint256::zero(); + + for extra_fee in pool_fees.extra_fees { + extra_fees_amount = extra_fees_amount.checked_add(extra_fee.compute(amount))?; } + + extra_fees_amount + } else { + Uint256::zero() + }; + + #[cfg(not(feature = "osmosis"))] + { + Ok(FeesComputation { + swap_fee_amount, + protocol_fee_amount, + burn_fee_amount, + extra_fees_amount, + }) + } + + #[cfg(feature = "osmosis")] + { + let osmosis_fee_amount: Uint256 = pool_fees.osmosis_fee.compute(amount); + + Ok(FeesComputation { + swap_fee_amount, + protocol_fee_amount, + burn_fee_amount, + extra_fees_amount, + osmosis_fee_amount, + }) } } +/// Builds the swap computation struct, subtracting the fees from the return amount. +fn get_swap_computation( + return_amount: Uint256, + spread_amount: Uint256, + fees_computation: FeesComputation, +) -> Result { + #[cfg(not(feature = "osmosis"))] + { + let return_amount = return_amount + .checked_sub(fees_computation.swap_fee_amount)? + .checked_sub(fees_computation.protocol_fee_amount)? + .checked_sub(fees_computation.burn_fee_amount)? + .checked_sub(fees_computation.extra_fees_amount)?; + + Ok(SwapComputation { + return_amount: return_amount + .try_into() + .map_err(|_| ContractError::SwapOverflowError)?, + spread_amount: spread_amount + .try_into() + .map_err(|_| ContractError::SwapOverflowError)?, + swap_fee_amount: fees_computation + .swap_fee_amount + .try_into() + .map_err(|_| ContractError::SwapOverflowError)?, + protocol_fee_amount: fees_computation + .protocol_fee_amount + .try_into() + .map_err(|_| ContractError::SwapOverflowError)?, + burn_fee_amount: fees_computation + .burn_fee_amount + .try_into() + .map_err(|_| ContractError::SwapOverflowError)?, + extra_fees_amount: fees_computation + .extra_fees_amount + .try_into() + .map_err(|_| ContractError::SwapOverflowError)?, + }) + } + + #[cfg(feature = "osmosis")] + { + let return_amount = return_amount + .checked_sub(fees_computation.swap_fee_amount)? + .checked_sub(fees_computation.protocol_fee_amount)? + .checked_sub(fees_computation.burn_fee_amount)? + .checked_sub(fees_computation.extra_fees_amount)? + .checked_sub(fees_computation.osmosis_fee_amount)?; + + Ok(SwapComputation { + return_amount: return_amount + .try_into() + .map_err(|_| ContractError::SwapOverflowError)?, + spread_amount: spread_amount + .try_into() + .map_err(|_| ContractError::SwapOverflowError)?, + swap_fee_amount: fees_computation + .swap_fee_amount + .try_into() + .map_err(|_| ContractError::SwapOverflowError)?, + protocol_fee_amount: fees_computation + .protocol_fee_amount + .try_into() + .map_err(|_| ContractError::SwapOverflowError)?, + burn_fee_amount: fees_computation + .burn_fee_amount + .try_into() + .map_err(|_| ContractError::SwapOverflowError)?, + extra_fees_amount: fees_computation + .extra_fees_amount + .try_into() + .map_err(|_| ContractError::SwapOverflowError)?, + osmosis_fee_amount: fees_computation + .osmosis_fee_amount + .try_into() + .map_err(|_| ContractError::SwapOverflowError)?, + }) + } +} + +/// Represents the swap computation values +#[cw_serde] +pub struct FeesComputation { + pub swap_fee_amount: Uint256, + pub protocol_fee_amount: Uint256, + pub burn_fee_amount: Uint256, + pub extra_fees_amount: Uint256, + #[cfg(feature = "osmosis")] + pub osmosis_fee_amount: Uint256, +} + /// Represents the swap computation values #[cw_serde] pub struct SwapComputation { @@ -325,10 +347,41 @@ pub struct SwapComputation { pub swap_fee_amount: Uint128, pub protocol_fee_amount: Uint128, pub burn_fee_amount: Uint128, + pub extra_fees_amount: Uint128, #[cfg(feature = "osmosis")] pub osmosis_fee_amount: Uint128, } +impl SwapComputation { + /// Converts the SwapComputation struct to a SimulationResponse struct + pub fn to_simulation_response(&self) -> SimulationResponse { + #[cfg(not(feature = "osmosis"))] + { + SimulationResponse { + return_amount: self.return_amount, + spread_amount: self.spread_amount, + swap_fee_amount: self.swap_fee_amount, + protocol_fee_amount: self.protocol_fee_amount, + burn_fee_amount: self.burn_fee_amount, + extra_fees_amount: self.extra_fees_amount, + } + } + + #[cfg(feature = "osmosis")] + { + SimulationResponse { + return_amount: self.return_amount, + spread_amount: self.spread_amount, + swap_fee_amount: self.swap_fee_amount, + protocol_fee_amount: self.protocol_fee_amount, + burn_fee_amount: self.burn_fee_amount, + osmosis_fee_amount: self.osmosis_fee_amount, + extra_fees_amount: self.extra_fees_amount, + } + } + } +} + pub fn compute_offer_amount( offer_pool: Uint128, ask_pool: Uint128, diff --git a/contracts/liquidity_hub/pool-manager/src/queries.rs b/contracts/liquidity_hub/pool-manager/src/queries.rs index 90d826f4c..eeb7f48e4 100644 --- a/contracts/liquidity_hub/pool-manager/src/queries.rs +++ b/contracts/liquidity_hub/pool-manager/src/queries.rs @@ -93,6 +93,7 @@ pub fn query_simulation( swap_fee_amount: swap_computation.swap_fee_amount, protocol_fee_amount: swap_computation.protocol_fee_amount, burn_fee_amount: swap_computation.burn_fee_amount, + extra_fees_amount: swap_computation.extra_fees_amount, }) } @@ -104,6 +105,7 @@ pub fn query_simulation( swap_fee_amount: swap_computation.swap_fee_amount, protocol_fee_amount: swap_computation.protocol_fee_amount, burn_fee_amount: swap_computation.burn_fee_amount, + extra_fees_amount: swap_computation.extra_fees_amount, osmosis_fee_amount: swap_computation.osmosis_fee_amount, }) } diff --git a/contracts/liquidity_hub/pool-manager/src/router/commands.rs b/contracts/liquidity_hub/pool-manager/src/router/commands.rs index 5036b4db3..ec9a42d27 100644 --- a/contracts/liquidity_hub/pool-manager/src/router/commands.rs +++ b/contracts/liquidity_hub/pool-manager/src/router/commands.rs @@ -86,7 +86,9 @@ pub fn execute_swap_operations( for operation in operations { match operation { SwapOperation::WhaleSwap { - pool_identifier, .. + token_out_denom, + pool_identifier, + .. } => { // inside assert_operations() we have already checked that // the output of each swap is the input of the next swap. @@ -94,6 +96,7 @@ pub fn execute_swap_operations( let swap_result = perform_swap( deps.branch(), previous_swap_output.clone(), + token_out_denom, pool_identifier, None, max_spread, diff --git a/contracts/liquidity_hub/pool-manager/src/swap/commands.rs b/contracts/liquidity_hub/pool-manager/src/swap/commands.rs index 0f16e1c60..03f07f428 100644 --- a/contracts/liquidity_hub/pool-manager/src/swap/commands.rs +++ b/contracts/liquidity_hub/pool-manager/src/swap/commands.rs @@ -35,7 +35,7 @@ pub fn swap( // verify that the assets sent match the ones from the pool let pool = get_pool_by_identifier(&deps.as_ref(), &pool_identifier)?; ensure!( - vec![ask_asset_denom, offer_asset.denom.clone()] + vec![ask_asset_denom.clone(), offer_asset.denom.clone()] .iter() .all(|asset| pool .assets @@ -48,6 +48,7 @@ pub fn swap( let swap_result = perform_swap( deps.branch(), offer_asset.clone(), + ask_asset_denom, pool_identifier, belief_price, max_spread, @@ -84,6 +85,8 @@ pub fn swap( ); } + println!("messages: {:?}", messages); + Ok(Response::new().add_messages(messages).add_attributes(vec![ ("action", "swap".to_string()), ("sender", sender.into_string()), diff --git a/contracts/liquidity_hub/pool-manager/src/swap/perform_swap.rs b/contracts/liquidity_hub/pool-manager/src/swap/perform_swap.rs index eb1216d13..cd74f92d3 100644 --- a/contracts/liquidity_hub/pool-manager/src/swap/perform_swap.rs +++ b/contracts/liquidity_hub/pool-manager/src/swap/perform_swap.rs @@ -1,8 +1,9 @@ -use cosmwasm_std::{Coin, Decimal, DepsMut, Uint128}; +use cosmwasm_std::{ensure, Coin, Decimal, DepsMut, Uint128}; use white_whale_std::pool_manager::PoolInfo; use white_whale_std::pool_network::swap::assert_max_spread; +use crate::helpers::aggregate_outgoing_fees; use crate::{ helpers, state::{get_pool_by_identifier, POOLS}, @@ -39,6 +40,7 @@ pub struct SwapResult { pub fn perform_swap( deps: DepsMut, offer_asset: Coin, + ask_asset_denom: String, pool_identifier: String, belief_price: Option, max_spread: Option, @@ -46,36 +48,33 @@ pub fn perform_swap( let mut pool_info = get_pool_by_identifier(&deps.as_ref(), &pool_identifier)?; let pools = &pool_info.assets; - // compute the offer and ask pool - let offer_pool: Coin; - let ask_pool: Coin; - let offer_decimal: u8; - let ask_decimal: u8; + // Find the index of the offer and ask asset in the pools + let offer_index = pools + .iter() + .position(|pool| offer_asset.denom == pool.denom) + .ok_or(ContractError::AssetMismatch)?; + let ask_index = pools + .iter() + .position(|pool| ask_asset_denom == pool.denom) + .ok_or(ContractError::AssetMismatch)?; + + // make sure it's not the same asset + ensure!(offer_index != ask_index, ContractError::AssetMismatch); + let decimals = &pool_info.asset_decimals; - // calculate the swap - // first, set relevant variables - if offer_asset.denom == pools[0].denom { - offer_pool = pools[0].clone(); - ask_pool = pools[1].clone(); - offer_decimal = decimals[0]; - ask_decimal = decimals[1]; - } else if offer_asset.denom == pools[1].denom { - offer_pool = pools[1].clone(); - ask_pool = pools[0].clone(); - - offer_decimal = decimals[1]; - ask_decimal = decimals[0]; - } else { - return Err(ContractError::AssetMismatch); - } + let offer_asset_in_pool = pools[offer_index].clone(); + let ask_asset_in_pool = pools[ask_index].clone(); + let offer_decimal = decimals[offer_index]; + let ask_decimal = decimals[ask_index]; let offer_amount = offer_asset.amount; let pool_fees = pool_info.pool_fees.clone(); + // compute the swap let swap_computation = helpers::compute_swap( - offer_pool.amount, - ask_pool.amount, + offer_asset_in_pool.amount, + ask_asset_in_pool.amount, offer_amount, pool_fees, &pool_info.pool_type, @@ -84,7 +83,7 @@ pub fn perform_swap( )?; let return_asset = Coin { - denom: ask_pool.denom.clone(), + denom: ask_asset_in_pool.denom.clone(), amount: swap_computation.return_amount, }; @@ -99,33 +98,35 @@ pub fn perform_swap( )?; // State changes to the pools balances - // Deduct the return amount from the pool and add the offer amount to the pool - if offer_asset.denom == pools[0].denom { - pool_info.assets[0].amount += offer_amount; - pool_info.assets[1].amount -= swap_computation.return_amount; - pool_info.assets[1].amount -= swap_computation.protocol_fee_amount; - pool_info.assets[1].amount -= swap_computation.burn_fee_amount; - } else { - pool_info.assets[1].amount += offer_amount; - pool_info.assets[0].amount -= swap_computation.return_amount; - pool_info.assets[0].amount -= swap_computation.protocol_fee_amount; - pool_info.assets[0].amount -= swap_computation.burn_fee_amount; - } + { + // add the offer amount to the pool + pool_info.assets[offer_index].amount = pool_info.assets[offer_index] + .amount + .checked_add(offer_amount)?; + + // Deduct the return amount and fees from the pool + let outgoing_fees = aggregate_outgoing_fees(&swap_computation.to_simulation_response())?; - POOLS.save(deps.storage, &pool_identifier, &pool_info)?; + pool_info.assets[ask_index].amount = pool_info.assets[ask_index] + .amount + .checked_sub(return_asset.amount)? + .checked_sub(outgoing_fees)?; + + POOLS.save(deps.storage, &pool_identifier, &pool_info)?; + } let burn_fee_asset = Coin { - denom: ask_pool.denom.clone(), + denom: ask_asset_in_pool.denom.clone(), amount: swap_computation.burn_fee_amount, }; let protocol_fee_asset = Coin { - denom: ask_pool.denom.clone(), + denom: ask_asset_in_pool.denom.clone(), amount: swap_computation.protocol_fee_amount, }; #[allow(clippy::redundant_clone)] let swap_fee_asset = Coin { - denom: ask_pool.denom.clone(), + denom: ask_asset_in_pool.denom.clone(), amount: swap_computation.swap_fee_amount, }; @@ -144,7 +145,7 @@ pub fn perform_swap( #[cfg(feature = "osmosis")] { let osmosis_fee_asset = Coin { - denom: ask_pool.denom, + denom: ask_asset_in_pool.denom, amount: swap_computation.swap_fee_amount, }; diff --git a/contracts/liquidity_hub/pool-manager/src/tests/integration_tests.rs b/contracts/liquidity_hub/pool-manager/src/tests/integration_tests.rs index ec8b515ad..c297a7842 100644 --- a/contracts/liquidity_hub/pool-manager/src/tests/integration_tests.rs +++ b/contracts/liquidity_hub/pool-manager/src/tests/integration_tests.rs @@ -1797,6 +1797,7 @@ mod swapping { use std::cell::RefCell; use cosmwasm_std::assert_approx_eq; + use white_whale_std::pool_manager::PoolType; use super::*; @@ -1903,7 +1904,7 @@ mod swapping { response.total_share, Coin { denom: response.pool_info.lp_denom, - amount: Uint128::from(1_000_000u128) + amount: Uint128::from(1_000_000u128), } ); }); @@ -1971,7 +1972,6 @@ mod swapping { let simulated_offer_amount = RefCell::new(Uint128::zero()); suite.query_reverse_simulation( "whale-uluna".to_string(), - "uluna".to_string(), Coin { denom: "uwhale".to_string(), amount: Uint128::from(1000u128), @@ -2164,7 +2164,6 @@ mod swapping { let simulated_offer_amount = RefCell::new(Uint128::zero()); suite.query_reverse_simulation( "whale-uluna".to_string(), - "uluna".to_string(), Coin { denom: "uwhale".to_string(), amount: Uint128::from(1000u128), @@ -2958,7 +2957,7 @@ mod provide_liquidity { creator.clone(), "whale-uluna".to_string(), None, - None,None, + None, None, None, vec![], |result| { @@ -2974,7 +2973,7 @@ mod provide_liquidity { creator.clone(), "whale-uluna".to_string(), None, - None,None, + None, None, None, vec![Coin { denom: "uosmo".to_string(), @@ -2993,7 +2992,7 @@ mod provide_liquidity { creator.clone(), "whale-uluna".to_string(), None, - None,None, + None, None, None, vec![Coin { denom: "uwhale".to_string(), @@ -3485,3 +3484,673 @@ mod provide_liquidity { ); } } + +mod multiple_pools { + use cosmwasm_std::{coin, Coin, Decimal, Uint128}; + + use white_whale_std::fee::{Fee, PoolFee}; + use white_whale_std::pool_manager::{PoolInfo, PoolType}; + + use crate::tests::suite::TestingSuite; + use crate::ContractError; + + #[cfg(not(feature = "osmosis"))] + #[test] + fn provide_liquidity_to_multiple_pools_check_fees() { + let mut suite = TestingSuite::default_with_balances(vec![ + coin(1_000_000_000u128, "uwhale".to_string()), + coin(1_000_000_000u128, "uluna".to_string()), + coin(1_000_000_000u128, "uosmo".to_string()), + coin(1_000_000_000u128, "uusd".to_string()), + ]); + let creator = suite.creator(); + let other = suite.senders[1].clone(); + + // Asset denoms with uwhale and uluna + let asset_denoms_1 = vec!["uwhale".to_string(), "uluna".to_string()]; + let asset_denoms_2 = vec!["uluna".to_string(), "uusd".to_string()]; + + #[cfg(not(feature = "osmosis"))] + let pool_fees_1 = PoolFee { + protocol_fee: Fee { + share: Decimal::percent(10), + }, + swap_fee: Fee { + share: Decimal::percent(7), + }, + burn_fee: Fee { + share: Decimal::percent(3), + }, + extra_fees: vec![], + }; + + #[cfg(not(feature = "osmosis"))] + let pool_fees_2 = PoolFee { + protocol_fee: Fee { + share: Decimal::zero(), + }, + swap_fee: Fee { + share: Decimal::percent(15), + }, + burn_fee: Fee { + share: Decimal::percent(5), + }, + extra_fees: vec![], + }; + + // Create pools + suite + .instantiate_default() + .create_pool( + creator.clone(), + asset_denoms_1.clone(), + vec![6u8, 6u8], + pool_fees_1.clone(), + PoolType::ConstantProduct, + Some("whale-uluna-pool-1".to_string()), + vec![coin(1000, "uusd")], + |result| { + result.unwrap(); + }, + ) + .create_pool( + creator.clone(), + asset_denoms_1, + vec![6u8, 6u8], + pool_fees_2.clone(), + PoolType::ConstantProduct, + Some("whale-uluna-pool-2".to_string()), + vec![coin(1000, "uusd")], + |result| { + result.unwrap(); + }, + ) + .create_pool( + creator.clone(), + asset_denoms_2, + vec![6u8, 6u8], + pool_fees_1.clone(), + PoolType::ConstantProduct, + Some("uluna-uusd-pool-1".to_string()), + vec![coin(1000, "uusd")], + |result| { + result.unwrap(); + }, + ); + + let pool_manager_addr = suite.pool_manager_addr.clone(); + let bonding_manager_addr = suite.bonding_manager_addr.clone(); + + // let's provide liquidity with two assets + suite + .provide_liquidity( + creator.clone(), + "whale-uluna".to_string(), + None, + None, + None, + None, + vec![ + Coin { + denom: "uwhale".to_string(), + amount: Uint128::from(1_000_000u128), + }, + Coin { + denom: "uluna".to_string(), + amount: Uint128::from(1_000_000u128), + }, + ], + |result| { + let err = result.unwrap_err().downcast::().unwrap(); + match err { + ContractError::UnExistingPool => {} + _ => panic!("Wrong error type, should return ContractError::UnExistingPool"), + } + }, + ) + .provide_liquidity( + creator.clone(), + "whale-uluna-pool-1".to_string(), + None, + None, + None, + None, + vec![ + Coin { + denom: "uwhale".to_string(), + amount: Uint128::from(1_000_000u128), + }, + Coin { + denom: "uluna".to_string(), + amount: Uint128::from(1_000_000u128), + }, + ], + |result| { + result.unwrap(); + }, + ) + .provide_liquidity( + other.clone(), + "whale-uluna-pool-2".to_string(), + None, + None, + None, + None, + vec![ + Coin { + denom: "uwhale".to_string(), + amount: Uint128::from(1_000_000u128), + }, + Coin { + denom: "uluna".to_string(), + amount: Uint128::from(1_000_000u128), + }, + ], + |result| { + result.unwrap(); + }, + ) + .provide_liquidity( + other.clone(), + "uluna-uusd-pool-1".to_string(), + None, + None, + None, + None, + vec![ + Coin { + denom: "uluna".to_string(), + amount: Uint128::from(1_000_000u128), + }, + Coin { + denom: "uusd".to_string(), + amount: Uint128::from(1_000_000u128), + }, + ], + |result| { + result.unwrap(); + }, + ) + .query_all_balances(pool_manager_addr.to_string(), |result| { + let balances = result.unwrap(); + assert_eq!( + balances, + vec![ + Coin { + denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uluna-uusd.pool.uluna-uusd-pool-1.uLP".to_string(), + amount: Uint128::from(1_000u128), + }, + Coin { + denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uwhale-uluna.pool.whale-uluna-pool-1.uLP".to_string(), + amount: Uint128::from(1_000u128), + }, + Coin { + denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uwhale-uluna.pool.whale-uluna-pool-2.uLP".to_string(), + amount: Uint128::from(1_000u128), + }, + Coin { + denom: "uluna".to_string(), + amount: Uint128::from(3_000_000u128), + }, + Coin { + denom: "uusd".to_string(), + amount: Uint128::from(1_000_000u128), + }, + Coin { + denom: "uwhale".to_string(), + amount: Uint128::from(2_000_000u128), + }, + ] + ); + }); + + // let's do swaps in whale-uluna-pool-1 and verify the fees are channeled correctly + suite + .swap( + creator.clone(), + "uluna".to_string(), + None, + None, + None, + "whale-uluna-pool-1".to_string(), + vec![coin(1000u128, "uwhale".to_string())], + |result| { + result.unwrap(); + }, + ) + .query_pool_info("whale-uluna-pool-1".to_string(), |result| { + let response = result.unwrap(); + let pool_info = response.pool_info; + + // swapped 1000 uwhale + // fees: + // swap -> 69 (~7%) + // protocol -> 99 (~10%) + // burn -> 29 (~3%) + // total_fees = 197, of which 69 stay in the pool (for LPs). + // Going out of the pool is 99 (bonding manager) + 29 (burned) + + assert_eq!(pool_info, PoolInfo { + asset_denoms: vec!["uwhale".to_string(), "uluna".to_string()], + lp_denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uwhale-uluna.pool.whale-uluna-pool-1.uLP".to_string(), + asset_decimals: vec![6u8, 6u8], + assets: vec![coin(1001000, "uwhale"), coin(999070, "uluna")], + pool_type: PoolType::ConstantProduct, + pool_fees: pool_fees_1.clone(), + }); + }) + ; + + // verify the fees went to the bonding manager + suite.query_balance( + bonding_manager_addr.clone().to_string(), + "uluna", + |result| { + assert_eq!(result.unwrap(), coin(99, "uluna")); + }, + ) + .swap( + creator.clone(), + "uwhale".to_string(), + None, + None, + None, + "whale-uluna-pool-1".to_string(), + vec![coin(2_000u128, "uluna".to_string())], + |result| { + result.unwrap(); + }, + ) + .query_pool_info("whale-uluna-pool-1".to_string(), |result| { + let response = result.unwrap(); + let pool_info = response.pool_info; + + // swapped 2000 uluna + // fees: + // swap -> 139 (~7%) + // protocol -> 199 (~10%) + // burn -> 59 (~3%) + // total_fees = 397, of which 139 stay in the pool (for LPs). + // Going out of the pool is 199 (bonding manager) + 59 (burned) + + assert_eq!(pool_info, PoolInfo { + asset_denoms: vec!["uwhale".to_string(), "uluna".to_string()], + lp_denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uwhale-uluna.pool.whale-uluna-pool-1.uLP".to_string(), + asset_decimals: vec![6u8, 6u8], + assets: vec![coin(999_140, "uwhale"), coin(1_001_070, "uluna")], + pool_type: PoolType::ConstantProduct, + pool_fees: pool_fees_1.clone(), + }); + }) + ; + + suite + .query_balance( + bonding_manager_addr.clone().to_string(), + "uwhale", + |result| { + assert_eq!(result.unwrap(), coin(199, "uwhale")); + }, + ) + .query_balance( + bonding_manager_addr.clone().to_string(), + "uluna", + |result| { + assert_eq!(result.unwrap(), coin(99, "uluna")); + }, + ); + + // let's do swaps in whale-uluna-pool-2 and verify the fees are channeled correctly + suite + .swap( + creator.clone(), + "uluna".to_string(), + None, + None, + None, + "whale-uluna-pool-2".to_string(), + vec![coin(1000u128, "uwhale".to_string())], + |result| { + result.unwrap(); + }, + ) + .query_pool_info("whale-uluna-pool-2".to_string(), |result| { + let response = result.unwrap(); + let pool_info = response.pool_info; + + // swapped 1000 uwhale + // fees: + // swap -> 149 (~15%) + // protocol -> 0 (0%) + // burn -> 49 (~5%) + // total_fees = 198, of which 149 stay in the pool (for LPs). + // Going out of the pool is 49 (burned) + + assert_eq!(pool_info, PoolInfo { + asset_denoms: vec!["uwhale".to_string(), "uluna".to_string()], + lp_denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uwhale-uluna.pool.whale-uluna-pool-2.uLP".to_string(), + asset_decimals: vec![6u8, 6u8], + assets: vec![coin(1001000, "uwhale"), coin(999_150, "uluna")], + pool_type: PoolType::ConstantProduct, + pool_fees: pool_fees_2.clone(), + }); + }) + ; + + suite + .swap( + creator.clone(), + "uwhale".to_string(), + None, + None, + None, + "whale-uluna-pool-2".to_string(), + vec![coin(2_000u128, "uluna".to_string())], + |result| { + result.unwrap(); + }, + ) + .query_pool_info("whale-uluna-pool-2".to_string(), |result| { + let response = result.unwrap(); + let pool_info = response.pool_info; + + // swapped 2000 uluna + // fees: + // swap -> 299 (~15%) + // protocol -> 0 (0%) + // burn -> 99 (~5%) + // total_fees = 398, of which 299 stay in the pool (for LPs). + // Going out of the pool is 99 (burned) + + assert_eq!(pool_info, PoolInfo { + asset_denoms: vec!["uwhale".to_string(), "uluna".to_string()], + lp_denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uwhale-uluna.pool.whale-uluna-pool-2.uLP".to_string(), + asset_decimals: vec![6u8, 6u8], + assets: vec![coin(999_300, "uwhale"), coin(1_001_150, "uluna")], + pool_type: PoolType::ConstantProduct, + pool_fees: pool_fees_2.clone(), + }); + }); + + suite + .query_balance( + bonding_manager_addr.clone().to_string(), + "uwhale", + |result| { + // no additional funds were sent to the bonding manager + assert_eq!(result.unwrap(), coin(199, "uwhale")); + }, + ) + .query_balance( + bonding_manager_addr.clone().to_string(), + "uluna", + |result| { + // no additional funds were sent to the bonding manager + assert_eq!(result.unwrap(), coin(99, "uluna")); + }, + ); + + // let's do swaps in uluna-uusd-pool-1 and verify the fees are channeled correctly + suite + .swap( + creator.clone(), + "uusd".to_string(), + None, + None, + None, + "uluna-uusd-pool-1".to_string(), + vec![coin(3000u128, "uluna".to_string())], + |result| { + result.unwrap(); + }, + ) + .query_pool_info("uluna-uusd-pool-1".to_string(), |result| { + let response = result.unwrap(); + let pool_info = response.pool_info; + + // swapped 3000 uluna + // fees: + // swap -> 209 (~7%) + // protocol -> 299 (~10%) + // burn -> 89 (~3%) + // total_fees = 597, of which 209 stay in the pool (for LPs). + // Going out of the pool is 299 (bonding manager) + 89 (burned) + + assert_eq!(pool_info, PoolInfo { + asset_denoms: vec!["uluna".to_string(), "uusd".to_string()], + lp_denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uluna-uusd.pool.uluna-uusd-pool-1.uLP".to_string(), + asset_decimals: vec![6u8, 6u8], + assets: vec![coin(1003000, "uluna"), coin(997_218, "uusd")], + pool_type: PoolType::ConstantProduct, + pool_fees: pool_fees_1.clone(), + }); + }) + ; + + suite.query_balance(bonding_manager_addr.clone().to_string(), "uusd", |result| { + // 3000 of pool creation fees + 299 from the previous swap + assert_eq!(result.unwrap(), coin(3299, "uusd")); + }); + + suite + .swap( + creator.clone(), + "uluna".to_string(), + None, + None, + None, + "uluna-uusd-pool-1".to_string(), + vec![coin(1_500u128, "uusd".to_string())], + |result| { + result.unwrap(); + }, + ) + .query_pool_info("uluna-uusd-pool-1".to_string(), |result| { + let response = result.unwrap(); + let pool_info = response.pool_info; + + // swapped 1500 uusd + // fees: + // swap -> 105 (~7%) + // protocol -> 150 (~10%) + // burn -> 45 (~3%) + // total_fees = 300, of which 105 stay in the pool (for LPs). + // Going out of the pool is 150 (bonding manager) + 45 (burned) + + assert_eq!(pool_info, PoolInfo { + asset_denoms: vec!["uluna".to_string(), "uusd".to_string()], + lp_denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uluna-uusd.pool.uluna-uusd-pool-1.uLP".to_string(), + asset_decimals: vec![6u8, 6u8], + assets: vec![coin(1_001_599, "uluna"), coin(998_718, "uusd")], + pool_type: PoolType::ConstantProduct, + pool_fees: pool_fees_1.clone(), + }); + }) + ; + + suite + .query_balance( + bonding_manager_addr.clone().to_string(), + "uwhale", + |result| { + // no additional funds were sent to the bonding manager + assert_eq!(result.unwrap(), coin(199, "uwhale")); + }, + ) + .query_balance( + bonding_manager_addr.clone().to_string(), + "uluna", + |result| { + // 99 + 150 + assert_eq!(result.unwrap(), coin(249, "uluna")); + }, + ).query_balance( + bonding_manager_addr.clone().to_string(), + "uusd", + |result| { + // 99 + 150 + assert_eq!(result.unwrap(), coin(3299, "uusd")); + }, + ) + .query_all_balances( + pool_manager_addr.clone().to_string(), + |result| { + let balances = result.unwrap(); + assert_eq!(balances, vec![ + Coin { + denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uluna-uusd.pool.uluna-uusd-pool-1.uLP".to_string(), + amount: Uint128::from(1_000u128), + }, + Coin { + denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uwhale-uluna.pool.whale-uluna-pool-1.uLP".to_string(), + amount: Uint128::from(1_000u128), + }, + Coin { + denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uwhale-uluna.pool.whale-uluna-pool-2.uLP".to_string(), + amount: Uint128::from(1_000u128), + }, + Coin { + denom: "uluna".to_string(), + amount: Uint128::from(3_003_819u128), + }, + Coin { + denom: "uusd".to_string(), + amount: Uint128::from(998_718u128), + }, + Coin { + denom: "uwhale".to_string(), + amount: Uint128::from(1_998_440u128), + }, + ]); + }, + ); + + // swap via the router now + let swap_operations = vec![ + white_whale_std::pool_manager::SwapOperation::WhaleSwap { + token_in_denom: "uwhale".to_string(), + token_out_denom: "uluna".to_string(), + pool_identifier: "whale-uluna-pool-2".to_string(), + }, + white_whale_std::pool_manager::SwapOperation::WhaleSwap { + token_in_denom: "uluna".to_string(), + token_out_denom: "uusd".to_string(), + pool_identifier: "uluna-uusd-pool-1".to_string(), + }, + ]; + + suite.execute_swap_operations( + creator.clone(), + swap_operations, + None, + None, + None, + vec![coin(5_000u128, "uwhale".to_string())], + |result| { + result.unwrap(); + }, + ).query_pool_info("whale-uluna-pool-1".to_string(), |result| { + let response = result.unwrap(); + let pool_info = response.pool_info; + + // this should have not changed since last time, since we didn't touch this pool + assert_eq!(pool_info, PoolInfo { + asset_denoms: vec!["uwhale".to_string(), "uluna".to_string()], + lp_denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uwhale-uluna.pool.whale-uluna-pool-1.uLP".to_string(), + asset_decimals: vec![6u8, 6u8], + assets: vec![coin(999_140, "uwhale"), coin(1_001_070, "uluna")], + pool_type: PoolType::ConstantProduct, + pool_fees: pool_fees_1.clone(), + }); + }) + .query_pool_info("whale-uluna-pool-2".to_string(), |result| { + let response = result.unwrap(); + let pool_info = response.pool_info; + + // the swap above was: + // SwapComputation { return_amount: Uint128(3988), + // spread_amount: Uint128(25), swap_fee_amount: Uint128(747), + // protocol_fee_amount: Uint128(0), burn_fee_amount: Uint128(249) } + + assert_eq!(pool_info, PoolInfo { + asset_denoms: vec!["uwhale".to_string(), "uluna".to_string()], + lp_denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uwhale-uluna.pool.whale-uluna-pool-2.uLP".to_string(), + asset_decimals: vec![6u8, 6u8], + assets: vec![coin(1_004_300, "uwhale"), coin(996_913, "uluna")], + pool_type: PoolType::ConstantProduct, + pool_fees: pool_fees_2.clone(), + }); + }).query_pool_info("uluna-uusd-pool-1".to_string(), |result| { + let response = result.unwrap(); + let pool_info = response.pool_info; + + // the swap above was: + // SwapComputation { return_amount: Uint128(3169), + // spread_amount: Uint128(16), swap_fee_amount: Uint128(277), + // protocol_fee_amount: Uint128(396), burn_fee_amount: Uint128(118) } + + assert_eq!(pool_info, PoolInfo { + asset_denoms: vec!["uluna".to_string(), "uusd".to_string()], + lp_denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uluna-uusd.pool.uluna-uusd-pool-1.uLP".to_string(), + asset_decimals: vec![6u8, 6u8], + assets: vec![coin(1_005_587, "uluna"), coin(995_035, "uusd")], + pool_type: PoolType::ConstantProduct, + pool_fees: pool_fees_1.clone(), + }); + }); + + suite.query_all_balances( + bonding_manager_addr.clone().to_string(), + |result| { + let balances = result.unwrap(); + assert_eq!(balances, vec![ + // the whale-uluna-pool-2 doesn't have protocol fees, hence no luna was accrued + // in the last swap + Coin { + denom: "uluna".to_string(), + amount: Uint128::from(249u128), + }, + Coin { + denom: "uusd".to_string(), + amount: Uint128::from(3_695u128), + }, + Coin { + denom: "uwhale".to_string(), + amount: Uint128::from(199u128), + }, + ]); + }, + ).query_all_balances( + pool_manager_addr.clone().to_string(), + |result| { + let balances = result.unwrap(); + assert_eq!(balances, vec![ + Coin { + denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uluna-uusd.pool.uluna-uusd-pool-1.uLP".to_string(), + amount: Uint128::from(1_000u128), + }, + Coin { + denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uwhale-uluna.pool.whale-uluna-pool-1.uLP".to_string(), + amount: Uint128::from(1_000u128), + }, + Coin { + denom: "factory/migaloo1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftqqhavvl/uwhale-uluna.pool.whale-uluna-pool-2.uLP".to_string(), + amount: Uint128::from(1_000u128), + }, + Coin { + denom: "uluna".to_string(), + amount: Uint128::from(3_003_570u128), + }, + Coin { + denom: "uusd".to_string(), + amount: Uint128::from(995_035u128), + }, + Coin { + denom: "uwhale".to_string(), + amount: Uint128::from(2_003_440u128), + }, + ]); + }, + ); + } +} diff --git a/contracts/liquidity_hub/pool-manager/src/tests/suite.rs b/contracts/liquidity_hub/pool-manager/src/tests/suite.rs index ff94f0c2a..43871361e 100644 --- a/contracts/liquidity_hub/pool-manager/src/tests/suite.rs +++ b/contracts/liquidity_hub/pool-manager/src/tests/suite.rs @@ -589,7 +589,6 @@ impl TestingSuite { pub(crate) fn query_reverse_simulation( &mut self, pool_identifier: String, - offer_asset: String, ask_asset: Coin, result: impl Fn(StdResult), ) -> &mut Self { diff --git a/packages/white-whale-std/src/pool_manager.rs b/packages/white-whale-std/src/pool_manager.rs index b1623b791..ce8d40c83 100644 --- a/packages/white-whale-std/src/pool_manager.rs +++ b/packages/white-whale-std/src/pool_manager.rs @@ -381,6 +381,8 @@ pub struct SimulationResponse { pub protocol_fee_amount: Uint128, /// The burn fee amount of the swap. pub burn_fee_amount: Uint128, + /// The extra fees amount of the swap. + pub extra_fees_amount: Uint128, /// The fee amount of the swap going to the osmosis community pool. #[cfg(feature = "osmosis")] pub osmosis_fee_amount: Uint128, From 464407b994db21e2246b7eecc9c8249ea568828e Mon Sep 17 00:00:00 2001 From: Kerber0x Date: Fri, 3 May 2024 16:52:53 +0100 Subject: [PATCH 6/7] refactor: abstract some simulation queries common logic --- .../pool-manager/schema/pool-manager.json | 14 ++++ .../pool-manager/schema/raw/query.json | 5 ++ .../schema/raw/response_to_simulation.json | 9 +++ .../pool-manager/src/contract.rs | 7 +- .../liquidity_hub/pool-manager/src/error.rs | 3 + .../liquidity_hub/pool-manager/src/helpers.rs | 56 ++++++++++--- .../pool-manager/src/liquidity/commands.rs | 21 ++++- .../liquidity_hub/pool-manager/src/queries.rs | 79 ++++++++----------- .../pool-manager/src/swap/perform_swap.rs | 41 +++------- .../src/tests/integration_tests.rs | 4 + .../pool-manager/src/tests/suite.rs | 4 + packages/white-whale-std/src/pool_manager.rs | 4 + 12 files changed, 160 insertions(+), 87 deletions(-) diff --git a/contracts/liquidity_hub/pool-manager/schema/pool-manager.json b/contracts/liquidity_hub/pool-manager/schema/pool-manager.json index 7c030414c..ac0316fc4 100644 --- a/contracts/liquidity_hub/pool-manager/schema/pool-manager.json +++ b/contracts/liquidity_hub/pool-manager/schema/pool-manager.json @@ -795,10 +795,15 @@ "simulation": { "type": "object", "required": [ + "ask_asset_denom", "offer_asset", "pool_identifier" ], "properties": { + "ask_asset_denom": { + "description": "The ask asset denom to get.", + "type": "string" + }, "offer_asset": { "description": "The offer asset to swap.", "allOf": [ @@ -1645,6 +1650,7 @@ "type": "object", "required": [ "burn_fee_amount", + "extra_fees_amount", "protocol_fee_amount", "return_amount", "spread_amount", @@ -1659,6 +1665,14 @@ } ] }, + "extra_fees_amount": { + "description": "The extra fees amount of the swap.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] + }, "protocol_fee_amount": { "description": "The protocol fee amount of the swap.", "allOf": [ diff --git a/contracts/liquidity_hub/pool-manager/schema/raw/query.json b/contracts/liquidity_hub/pool-manager/schema/raw/query.json index e9162721d..b0194f558 100644 --- a/contracts/liquidity_hub/pool-manager/schema/raw/query.json +++ b/contracts/liquidity_hub/pool-manager/schema/raw/query.json @@ -47,10 +47,15 @@ "simulation": { "type": "object", "required": [ + "ask_asset_denom", "offer_asset", "pool_identifier" ], "properties": { + "ask_asset_denom": { + "description": "The ask asset denom to get.", + "type": "string" + }, "offer_asset": { "description": "The offer asset to swap.", "allOf": [ diff --git a/contracts/liquidity_hub/pool-manager/schema/raw/response_to_simulation.json b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_simulation.json index 7faa00a3c..d4d0906a5 100644 --- a/contracts/liquidity_hub/pool-manager/schema/raw/response_to_simulation.json +++ b/contracts/liquidity_hub/pool-manager/schema/raw/response_to_simulation.json @@ -5,6 +5,7 @@ "type": "object", "required": [ "burn_fee_amount", + "extra_fees_amount", "protocol_fee_amount", "return_amount", "spread_amount", @@ -19,6 +20,14 @@ } ] }, + "extra_fees_amount": { + "description": "The extra fees amount of the swap.", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] + }, "protocol_fee_amount": { "description": "The protocol fee amount of the swap.", "allOf": [ diff --git a/contracts/liquidity_hub/pool-manager/src/contract.rs b/contracts/liquidity_hub/pool-manager/src/contract.rs index 71d7a6a18..0e8e4d03a 100644 --- a/contracts/liquidity_hub/pool-manager/src/contract.rs +++ b/contracts/liquidity_hub/pool-manager/src/contract.rs @@ -189,7 +189,7 @@ pub fn execute( } #[cfg_attr(not(feature = "library"), entry_point)] -pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result { +pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result { match msg { QueryMsg::Config => Ok(to_json_binary(&queries::query_config(deps)?)?), QueryMsg::AssetDecimals { @@ -202,19 +202,22 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result Ok(to_json_binary(&queries::query_simulation( deps, offer_asset, + ask_asset_denom, pool_identifier, )?)?), QueryMsg::ReverseSimulation { ask_asset, + offer_asset_denom, pool_identifier, } => Ok(to_json_binary(&queries::query_reverse_simulation( deps, - env, ask_asset, + offer_asset_denom, pool_identifier, )?)?), QueryMsg::SimulateSwapOperations { diff --git a/contracts/liquidity_hub/pool-manager/src/error.rs b/contracts/liquidity_hub/pool-manager/src/error.rs index 7edbd3297..d8ba8036a 100644 --- a/contracts/liquidity_hub/pool-manager/src/error.rs +++ b/contracts/liquidity_hub/pool-manager/src/error.rs @@ -73,6 +73,9 @@ pub enum ContractError { #[error("Cannot provide single-side liquidity when the pool is empty")] EmptyPoolForSingleSideLiquidityProvision, + #[error("Cannot provide single-side liquidity on a pool with more than 2 assets")] + InvalidPoolAssetsForSingleSideLiquidityProvision, + #[error("Pool does not exist")] UnExistingPool, diff --git a/contracts/liquidity_hub/pool-manager/src/helpers.rs b/contracts/liquidity_hub/pool-manager/src/helpers.rs index a3ea5ccc3..3e7870f6e 100644 --- a/contracts/liquidity_hub/pool-manager/src/helpers.rs +++ b/contracts/liquidity_hub/pool-manager/src/helpers.rs @@ -7,7 +7,7 @@ use cosmwasm_std::{ }; use white_whale_std::fee::PoolFee; -use white_whale_std::pool_manager::{PoolType, SimulationResponse}; +use white_whale_std::pool_manager::{PoolInfo, PoolType, SimulationResponse}; use white_whale_std::pool_network::asset::{Asset, AssetInfo}; use crate::error::ContractError; @@ -383,13 +383,13 @@ impl SwapComputation { } pub fn compute_offer_amount( - offer_pool: Uint128, - ask_pool: Uint128, + offer_asset_in_pool: Uint128, + ask_asset_in_pool: Uint128, ask_amount: Uint128, pool_fees: PoolFee, ) -> StdResult { - let offer_pool: Uint256 = offer_pool.into(); - let ask_pool: Uint256 = ask_pool.into(); + let offer_asset_in_pool: Uint256 = offer_asset_in_pool.into(); + let ask_asset_in_pool: Uint256 = ask_asset_in_pool.into(); let ask_amount: Uint256 = ask_amount.into(); // ask => offer @@ -415,17 +415,17 @@ pub fn compute_offer_amount( let one_minus_commission = Decimal256::one() - fees; let inv_one_minus_commission = Decimal256::one() / one_minus_commission; - let cp: Uint256 = offer_pool * ask_pool; + let cp: Uint256 = offer_asset_in_pool * ask_asset_in_pool; let offer_amount: Uint256 = Uint256::one() .multiply_ratio( cp, - ask_pool.checked_sub(ask_amount * inv_one_minus_commission)?, + ask_asset_in_pool.checked_sub(ask_amount * inv_one_minus_commission)?, ) - .checked_sub(offer_pool)?; + .checked_sub(offer_asset_in_pool)?; let before_commission_deduction: Uint256 = ask_amount * inv_one_minus_commission; let before_spread_deduction: Uint256 = - offer_amount * Decimal256::from_ratio(ask_pool, offer_pool); + offer_amount * Decimal256::from_ratio(ask_asset_in_pool, offer_asset_in_pool); let spread_amount = before_spread_deduction.saturating_sub(before_commission_deduction); @@ -624,3 +624,41 @@ pub fn aggregate_outgoing_fees( Ok(fees) } + +/// Gets the offer and ask asset indexes in a pool, together with their decimals. +pub fn get_asset_indexes_in_pool( + pool_info: &PoolInfo, + offer_asset_denom: String, + ask_asset_denom: String, +) -> Result<(Coin, Coin, usize, usize, u8, u8), ContractError> { + // Find the index of the offer and ask asset in the pools + let offer_index = pool_info + .assets + .iter() + .position(|pool| offer_asset_denom == pool.denom) + .ok_or(ContractError::AssetMismatch)?; + let ask_index = pool_info + .assets + .iter() + .position(|pool| ask_asset_denom == pool.denom) + .ok_or(ContractError::AssetMismatch)?; + + // make sure it's not the same asset + ensure!(offer_index != ask_index, ContractError::AssetMismatch); + + let decimals = &pool_info.asset_decimals; + + let offer_asset_in_pool = pool_info.assets[offer_index].clone(); + let ask_asset_in_pool = pool_info.assets[ask_index].clone(); + let offer_decimal = decimals[offer_index]; + let ask_decimal = decimals[ask_index]; + + Ok(( + offer_asset_in_pool, + ask_asset_in_pool, + offer_index, + ask_index, + offer_decimal, + ask_decimal, + )) +} diff --git a/contracts/liquidity_hub/pool-manager/src/liquidity/commands.rs b/contracts/liquidity_hub/pool-manager/src/liquidity/commands.rs index ceebf4789..6c2420e84 100644 --- a/contracts/liquidity_hub/pool-manager/src/liquidity/commands.rs +++ b/contracts/liquidity_hub/pool-manager/src/liquidity/commands.rs @@ -80,16 +80,33 @@ pub fn provide_liquidity( ContractError::EmptyPoolForSingleSideLiquidityProvision ); + // can't provide single side liquidity on a pool with more than 2 assets + ensure!( + pool_assets.len() == 2, + ContractError::InvalidPoolAssetsForSingleSideLiquidityProvision + ); + let deposit = deposits[0].clone(); + let ask_asset_denom = pool_assets + .iter() + .find(|pool_asset| pool_asset.denom != deposit.denom) + .ok_or(ContractError::AssetMismatch)? + .denom + .clone(); + // swap half of the deposit asset for the other asset in the pool let swap_half = Coin { denom: deposit.denom.clone(), amount: deposit.amount.checked_div_floor((2u64, 1u64))?, }; - let swap_simulation_response = - query_simulation(deps.as_ref(), swap_half.clone(), pool_identifier.clone())?; + let swap_simulation_response = query_simulation( + deps.as_ref(), + swap_half.clone(), + ask_asset_denom, + pool_identifier.clone(), + )?; let ask_denom = pool_assets .iter() diff --git a/contracts/liquidity_hub/pool-manager/src/queries.rs b/contracts/liquidity_hub/pool-manager/src/queries.rs index eeb7f48e4..5a557d099 100644 --- a/contracts/liquidity_hub/pool-manager/src/queries.rs +++ b/contracts/liquidity_hub/pool-manager/src/queries.rs @@ -1,6 +1,6 @@ use std::cmp::Ordering; -use cosmwasm_std::{coin, Coin, Decimal256, Deps, Env, Fraction, Order, StdResult, Uint128}; +use cosmwasm_std::{coin, Coin, Decimal256, Deps, Fraction, Order, StdResult, Uint128}; use white_whale_std::pool_manager::{ AssetDecimalsResponse, Config, PoolInfoResponse, PoolType, ReverseSimulationResponse, @@ -8,6 +8,7 @@ use white_whale_std::pool_manager::{ SwapRouteCreatorResponse, SwapRouteResponse, SwapRoutesResponse, }; +use crate::helpers::get_asset_indexes_in_pool; use crate::state::{CONFIG, POOLS}; use crate::{ helpers::{self, calculate_stableswap_y, StableSwapDirection}, @@ -45,41 +46,19 @@ pub fn query_asset_decimals( pub fn query_simulation( deps: Deps, offer_asset: Coin, + ask_asset_denom: String, pool_identifier: String, ) -> Result { let pool_info = get_pool_by_identifier(&deps, &pool_identifier)?; - let pools = pool_info.assets.clone(); - - // determine what's the offer and ask pool based on the offer_asset - let offer_pool: Coin; - let ask_pool: Coin; - let offer_decimal: u8; - let ask_decimal: u8; - let decimals = pool_info.asset_decimals.clone(); - // We now have the pools and pool info; we can now calculate the swap - // Verify the pool - if offer_asset.denom == pools[0].denom { - offer_pool = pools[0].clone(); - ask_pool = pools[1].clone(); - offer_decimal = decimals[0]; - ask_decimal = decimals[1]; - } else if offer_asset.denom == pools[1].denom { - offer_pool = pools[1].clone(); - ask_pool = pools[0].clone(); - - offer_decimal = decimals[1]; - ask_decimal = decimals[0]; - } else { - return Err(ContractError::AssetMismatch); - } - let pool_fees = pool_info.pool_fees; + let (offer_asset_in_pool, ask_asset_in_pool, _, _, offer_decimal, ask_decimal) = + get_asset_indexes_in_pool(&pool_info, offer_asset.denom, ask_asset_denom)?; let swap_computation = helpers::compute_swap( - offer_pool.amount, - ask_pool.amount, + offer_asset_in_pool.amount, + ask_asset_in_pool.amount, offer_asset.amount, - pool_fees, + pool_info.pool_fees, &pool_info.pool_type, offer_decimal, ask_decimal, @@ -115,25 +94,23 @@ pub fn query_simulation( /// the number of target tokens. pub fn query_reverse_simulation( deps: Deps, - _env: Env, ask_asset: Coin, + offer_asset_denom: String, pool_identifier: String, ) -> Result { let pool_info = get_pool_by_identifier(&deps, &pool_identifier)?; - let pools = pool_info.assets.clone(); - let decimals = pool_info.asset_decimals.clone(); - let offer_pool: Coin = pools[0].clone(); - let offer_decimal = decimals[0]; - let ask_pool: Coin = pools[1].clone(); - let ask_decimal = decimals[1]; + let (offer_asset_in_pool, ask_asset_in_pool, _, _, offer_decimal, ask_decimal) = + get_asset_indexes_in_pool(&pool_info, offer_asset_denom, ask_asset.denom)?; + let pool_fees = pool_info.pool_fees; + //todo clean this up match pool_info.pool_type { PoolType::ConstantProduct => { let offer_amount_computation = helpers::compute_offer_amount( - offer_pool.amount, - ask_pool.amount, + offer_asset_in_pool.amount, + ask_asset_in_pool.amount, ask_asset.amount, pool_fees, )?; @@ -162,8 +139,10 @@ pub fn query_reverse_simulation( } } PoolType::StableSwap { amp } => { - let offer_pool = Decimal256::decimal_with_precision(offer_pool.amount, offer_decimal)?; - let ask_pool = Decimal256::decimal_with_precision(ask_pool.amount, ask_decimal)?; + let offer_pool = + Decimal256::decimal_with_precision(offer_asset_in_pool.amount, offer_decimal)?; + let ask_pool = + Decimal256::decimal_with_precision(ask_asset_in_pool.amount, ask_decimal)?; let before_fees = (Decimal256::one() .checked_sub(pool_fees.protocol_fee.to_decimal_256())? @@ -334,11 +313,15 @@ pub fn simulate_swap_operations( match operation { SwapOperation::WhaleSwap { token_in_denom, - token_out_denom: _, + token_out_denom, pool_identifier, } => { - let res = - query_simulation(deps, coin(amount.u128(), token_in_denom), pool_identifier)?; + let res = query_simulation( + deps, + coin(amount.u128(), token_in_denom), + token_out_denom, + pool_identifier, + )?; amount = res.return_amount; } } @@ -364,12 +347,16 @@ pub fn reverse_simulate_swap_operations( for operation in operations.into_iter().rev() { match operation { SwapOperation::WhaleSwap { - token_in_denom: _, + token_in_denom, token_out_denom, pool_identifier, } => { - let res = - query_simulation(deps, coin(amount.u128(), token_out_denom), pool_identifier)?; + let res = query_simulation( + deps, + coin(amount.u128(), token_out_denom), + token_in_denom, + pool_identifier, + )?; amount = res.return_amount; } } diff --git a/contracts/liquidity_hub/pool-manager/src/swap/perform_swap.rs b/contracts/liquidity_hub/pool-manager/src/swap/perform_swap.rs index cd74f92d3..01ba30198 100644 --- a/contracts/liquidity_hub/pool-manager/src/swap/perform_swap.rs +++ b/contracts/liquidity_hub/pool-manager/src/swap/perform_swap.rs @@ -1,9 +1,9 @@ -use cosmwasm_std::{ensure, Coin, Decimal, DepsMut, Uint128}; +use cosmwasm_std::{Coin, Decimal, DepsMut, Uint128}; use white_whale_std::pool_manager::PoolInfo; use white_whale_std::pool_network::swap::assert_max_spread; -use crate::helpers::aggregate_outgoing_fees; +use crate::helpers::{aggregate_outgoing_fees, get_asset_indexes_in_pool}; use crate::{ helpers, state::{get_pool_by_identifier, POOLS}, @@ -46,37 +46,22 @@ pub fn perform_swap( max_spread: Option, ) -> Result { let mut pool_info = get_pool_by_identifier(&deps.as_ref(), &pool_identifier)?; - let pools = &pool_info.assets; - // Find the index of the offer and ask asset in the pools - let offer_index = pools - .iter() - .position(|pool| offer_asset.denom == pool.denom) - .ok_or(ContractError::AssetMismatch)?; - let ask_index = pools - .iter() - .position(|pool| ask_asset_denom == pool.denom) - .ok_or(ContractError::AssetMismatch)?; - - // make sure it's not the same asset - ensure!(offer_index != ask_index, ContractError::AssetMismatch); - - let decimals = &pool_info.asset_decimals; - - let offer_asset_in_pool = pools[offer_index].clone(); - let ask_asset_in_pool = pools[ask_index].clone(); - let offer_decimal = decimals[offer_index]; - let ask_decimal = decimals[ask_index]; - - let offer_amount = offer_asset.amount; - let pool_fees = pool_info.pool_fees.clone(); + let ( + offer_asset_in_pool, + ask_asset_in_pool, + offer_index, + ask_index, + offer_decimal, + ask_decimal, + ) = get_asset_indexes_in_pool(&pool_info, offer_asset.denom, ask_asset_denom)?; // compute the swap let swap_computation = helpers::compute_swap( offer_asset_in_pool.amount, ask_asset_in_pool.amount, - offer_amount, - pool_fees, + offer_asset.amount, + pool_info.pool_fees.clone(), &pool_info.pool_type, offer_decimal, ask_decimal, @@ -102,7 +87,7 @@ pub fn perform_swap( // add the offer amount to the pool pool_info.assets[offer_index].amount = pool_info.assets[offer_index] .amount - .checked_add(offer_amount)?; + .checked_add(offer_asset.amount)?; // Deduct the return amount and fees from the pool let outgoing_fees = aggregate_outgoing_fees(&swap_computation.to_simulation_response())?; diff --git a/contracts/liquidity_hub/pool-manager/src/tests/integration_tests.rs b/contracts/liquidity_hub/pool-manager/src/tests/integration_tests.rs index c297a7842..80c1660d6 100644 --- a/contracts/liquidity_hub/pool-manager/src/tests/integration_tests.rs +++ b/contracts/liquidity_hub/pool-manager/src/tests/integration_tests.rs @@ -1916,6 +1916,7 @@ mod swapping { denom: "uwhale".to_string(), amount: Uint128::from(1000u128), }, + "uluna".to_string(), |result| { // Ensure that the return amount is 1_000 minus spread assert_eq!( @@ -1976,6 +1977,7 @@ mod swapping { denom: "uwhale".to_string(), amount: Uint128::from(1000u128), }, + "uluna".to_string(), |result| { *simulated_offer_amount.borrow_mut() = result.unwrap().offer_amount; }, @@ -2113,6 +2115,7 @@ mod swapping { denom: "uwhale".to_string(), amount: Uint128::from(1000u128), }, + "uluna".to_string(), |result| { *simulated_return_amount.borrow_mut() = result.unwrap().return_amount; }, @@ -2168,6 +2171,7 @@ mod swapping { denom: "uwhale".to_string(), amount: Uint128::from(1000u128), }, + "uluna".to_string(), |result| { *simulated_offer_amount.borrow_mut() = result.unwrap().offer_amount; }, diff --git a/contracts/liquidity_hub/pool-manager/src/tests/suite.rs b/contracts/liquidity_hub/pool-manager/src/tests/suite.rs index 43871361e..122a05856 100644 --- a/contracts/liquidity_hub/pool-manager/src/tests/suite.rs +++ b/contracts/liquidity_hub/pool-manager/src/tests/suite.rs @@ -571,12 +571,14 @@ impl TestingSuite { &mut self, pool_identifier: String, offer_asset: Coin, + ask_asset_denom: String, result: impl Fn(StdResult), ) -> &mut Self { let pool_info_response: StdResult = self.app.wrap().query_wasm_smart( &self.pool_manager_addr, &white_whale_std::pool_manager::QueryMsg::Simulation { offer_asset, + ask_asset_denom, pool_identifier, }, ); @@ -590,6 +592,7 @@ impl TestingSuite { &mut self, pool_identifier: String, ask_asset: Coin, + offer_asset_denom: String, result: impl Fn(StdResult), ) -> &mut Self { let pool_info_response: StdResult = @@ -597,6 +600,7 @@ impl TestingSuite { &self.pool_manager_addr, &white_whale_std::pool_manager::QueryMsg::ReverseSimulation { ask_asset, + offer_asset_denom, pool_identifier, }, ); diff --git a/packages/white-whale-std/src/pool_manager.rs b/packages/white-whale-std/src/pool_manager.rs index ce8d40c83..344e0e49d 100644 --- a/packages/white-whale-std/src/pool_manager.rs +++ b/packages/white-whale-std/src/pool_manager.rs @@ -280,6 +280,8 @@ pub enum QueryMsg { Simulation { /// The offer asset to swap. offer_asset: Coin, + /// The ask asset denom to get. + ask_asset_denom: String, /// The pool identifier to swap in. pool_identifier: String, }, @@ -289,6 +291,8 @@ pub enum QueryMsg { ReverseSimulation { /// The ask asset to get after the swap. ask_asset: Coin, + /// The offer asset denom to input. + offer_asset_denom: String, /// The pool identifier to swap in. pool_identifier: String, }, From 5e487cc3a2f41c2b4ccf476406facbe7d4f193fb Mon Sep 17 00:00:00 2001 From: Kerber0x Date: Fri, 3 May 2024 17:04:20 +0100 Subject: [PATCH 7/7] chore: cleanup after merge --- .../bonding-manager/src/tests/claim.rs | 2 +- .../bonding-manager/src/tests/rewards.rs | 6 ++--- .../bonding-manager/src/tests/robot.rs | 26 +++++++++---------- .../pool-manager/schema/pool-manager.json | 5 ++++ .../pool-manager/schema/raw/query.json | 5 ++++ 5 files changed, 27 insertions(+), 17 deletions(-) diff --git a/contracts/liquidity_hub/bonding-manager/src/tests/claim.rs b/contracts/liquidity_hub/bonding-manager/src/tests/claim.rs index 34f659a7b..e41955596 100644 --- a/contracts/liquidity_hub/bonding-manager/src/tests/claim.rs +++ b/contracts/liquidity_hub/bonding-manager/src/tests/claim.rs @@ -182,7 +182,7 @@ fn test_claim_successfully() { sender.clone(), asset_infos.clone(), pool_fees.clone(), - white_whale_std::pool_network::asset::PairType::ConstantProduct, + white_whale_std::pool_manager::PoolType::ConstantProduct, Some("whale-uusdc".to_string()), vec![coin(1000, "uwhale")], |result| { diff --git a/contracts/liquidity_hub/bonding-manager/src/tests/rewards.rs b/contracts/liquidity_hub/bonding-manager/src/tests/rewards.rs index a5c3768d4..b05b9f915 100644 --- a/contracts/liquidity_hub/bonding-manager/src/tests/rewards.rs +++ b/contracts/liquidity_hub/bonding-manager/src/tests/rewards.rs @@ -39,7 +39,7 @@ fn test_fill_rewards_from_pool_manager() { creator.clone(), asset_infos.clone(), pool_fees.clone(), - white_whale_std::pool_network::asset::PairType::ConstantProduct, + white_whale_std::pool_manager::PoolType::ConstantProduct, Some("whale-uusdc".to_string()), vec![coin(1000, "uwhale")], |result| { @@ -123,7 +123,7 @@ fn test_fill_rewards_from_pool_manager() { creator.clone(), asset_infos.clone(), pool_fees.clone(), - white_whale_std::pool_network::asset::PairType::ConstantProduct, + white_whale_std::pool_manager::PoolType::ConstantProduct, Some("whale-uusdc-second".to_string()), vec![coin(1000, "uwhale")], |result| { @@ -145,7 +145,7 @@ fn test_fill_rewards_from_pool_manager() { creator.clone(), asset_infos, pool_fees, - white_whale_std::pool_network::asset::PairType::ConstantProduct, + white_whale_std::pool_manager::PoolType::ConstantProduct, Some("whale-uusdc-third".to_string()), vec![coin(1000, "uwhale")], |result| { diff --git a/contracts/liquidity_hub/bonding-manager/src/tests/robot.rs b/contracts/liquidity_hub/bonding-manager/src/tests/robot.rs index 987880007..3b79f5b63 100644 --- a/contracts/liquidity_hub/bonding-manager/src/tests/robot.rs +++ b/contracts/liquidity_hub/bonding-manager/src/tests/robot.rs @@ -20,6 +20,7 @@ use white_whale_std::bonding_manager::{ }; use white_whale_std::bonding_manager::{ClaimableEpochsResponse, Epoch}; use white_whale_std::epoch_manager::epoch_manager::{Epoch as EpochV2, EpochConfig}; +use white_whale_std::pool_manager::PoolType; use white_whale_std::pool_network::asset::PairType; pub fn bonding_manager_contract() -> Box> { @@ -619,12 +620,12 @@ impl TestingRobot { pub(crate) fn provide_liquidity( &mut self, sender: Addr, - pair_identifier: String, + pool_identifier: String, funds: Vec, result: impl Fn(Result), ) -> &mut Self { let msg = white_whale_std::pool_manager::ExecuteMsg::ProvideLiquidity { - pair_identifier, + pool_identifier, slippage_tolerance: None, receiver: None, lock_position_identifier: None, @@ -644,22 +645,21 @@ impl TestingRobot { pub(crate) fn swap( &mut self, sender: Addr, - offer_asset: Coin, + _offer_asset: Coin, ask_asset_denom: String, belief_price: Option, max_spread: Option, - to: Option, - pair_identifier: String, + receiver: Option, + pool_identifier: String, funds: Vec, result: impl Fn(Result), ) -> &mut Self { let msg = white_whale_std::pool_manager::ExecuteMsg::Swap { - offer_asset, ask_asset_denom, belief_price, max_spread, - to, - pair_identifier, + receiver, + pool_identifier, }; result( @@ -710,16 +710,16 @@ impl TestingRobot { sender: Addr, asset_denoms: Vec, pool_fees: PoolFee, - pair_type: PairType, - pair_identifier: Option, + pool_type: PoolType, + pool_identifier: Option, pair_creation_fee_funds: Vec, result: impl Fn(Result), ) -> &mut Self { - let msg = white_whale_std::pool_manager::ExecuteMsg::CreatePair { + let msg = white_whale_std::pool_manager::ExecuteMsg::CreatePool { asset_denoms, pool_fees, - pair_type, - pair_identifier, + pool_type, + pool_identifier, asset_decimals: vec![6, 6], }; diff --git a/contracts/liquidity_hub/pool-manager/schema/pool-manager.json b/contracts/liquidity_hub/pool-manager/schema/pool-manager.json index ac0316fc4..b6932daf0 100644 --- a/contracts/liquidity_hub/pool-manager/schema/pool-manager.json +++ b/contracts/liquidity_hub/pool-manager/schema/pool-manager.json @@ -833,6 +833,7 @@ "type": "object", "required": [ "ask_asset", + "offer_asset_denom", "pool_identifier" ], "properties": { @@ -844,6 +845,10 @@ } ] }, + "offer_asset_denom": { + "description": "The offer asset denom to input.", + "type": "string" + }, "pool_identifier": { "description": "The pool identifier to swap in.", "type": "string" diff --git a/contracts/liquidity_hub/pool-manager/schema/raw/query.json b/contracts/liquidity_hub/pool-manager/schema/raw/query.json index b0194f558..ec6ac2fe0 100644 --- a/contracts/liquidity_hub/pool-manager/schema/raw/query.json +++ b/contracts/liquidity_hub/pool-manager/schema/raw/query.json @@ -85,6 +85,7 @@ "type": "object", "required": [ "ask_asset", + "offer_asset_denom", "pool_identifier" ], "properties": { @@ -96,6 +97,10 @@ } ] }, + "offer_asset_denom": { + "description": "The offer asset denom to input.", + "type": "string" + }, "pool_identifier": { "description": "The pool identifier to swap in.", "type": "string"