Skip to content

Commit

Permalink
Merge pull request #5 from quasar-finance/feat/improve-slippage-error
Browse files Browse the repository at this point in the history
add assets to minimum receive error
  • Loading branch information
0xLaurenzo authored Jun 12, 2024
2 parents 15b374a + 9e50b46 commit daaecce
Show file tree
Hide file tree
Showing 8 changed files with 412 additions and 450 deletions.
33 changes: 17 additions & 16 deletions src/contract.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
use apollo_cw_asset::{Asset, AssetInfo, AssetInfoUnchecked, AssetList, AssetListUnchecked};
use apollo_cw_asset::{Asset, AssetInfo, AssetInfoUnchecked};
#[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point;
use cosmwasm_std::{
from_binary, to_binary, Addr, Binary, CosmosMsg, Deps, DepsMut, Env, Event, MessageInfo, Order,
Response, StdError, StdResult, Uint128,
from_json, to_json_binary, Addr, Binary, CosmosMsg, Deps, DepsMut, Env, Event, MessageInfo,
Order, Response, StdError, StdResult, Uint128,
};
use cw2::set_contract_version;
use cw20::Cw20ReceiveMsg;

use crate::error::ContractError;
use crate::helpers::{receive_asset, receive_assets};
use crate::helpers::receive_asset;
use crate::msg::{
BestPathForPairResponse, CallbackMsg, Cw20HookMsg, ExecuteMsg, InstantiateMsg, MigrateMsg,
QueryMsg,
};
use crate::operations::{
SwapOperation, SwapOperationsList, SwapOperationsListBase, SwapOperationsListUnchecked,
};
use crate::operations::{SwapOperation, SwapOperationsList, SwapOperationsListUnchecked};
use crate::state::{ADMIN, PATHS};

const CONTRACT_NAME: &str = "crates.io:cw-dex-router";
Expand Down Expand Up @@ -129,7 +127,7 @@ pub fn receive_cw20(
) -> Result<Response, ContractError> {
let sender = deps.api.addr_validate(&cw20_msg.sender)?;

match from_binary(&cw20_msg.msg)? {
match from_json(&cw20_msg.msg)? {
Cw20HookMsg::ExecuteSwapOperations {
operations,
minimum_receive,
Expand Down Expand Up @@ -238,7 +236,10 @@ pub fn assert_minimum_receive(
let received_amount = recipient_balance.checked_sub(prev_balance)?;

if received_amount < minimum_receive {
return Err(ContractError::FailedMinimumReceive);
return Err(ContractError::FailedMinimumReceive {
wanted: Asset::new(asset_info.clone(), minimum_receive),
got: Asset::new(asset_info, received_amount),
});
}
Ok(Response::default())
}
Expand Down Expand Up @@ -363,19 +364,19 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
QueryMsg::SimulateSwapOperations {
offer_amount,
operations,
} => to_binary(&simulate_swap_operations(deps, offer_amount, operations)?),
} => to_json_binary(&simulate_swap_operations(deps, offer_amount, operations)?),
// QueryMsg::SimulateBasketLiquidate {
// offer_assets,
// receive_asset,
// } => to_binary(&simulate_basket_liquidate(
// } => to_json_binary(&simulate_basket_liquidate(
// deps,
// offer_assets,
// receive_asset,
// )?),
QueryMsg::PathsForPair {
offer_asset,
ask_asset,
} => to_binary(&query_paths_for_pair(
} => to_json_binary(&query_paths_for_pair(
deps,
offer_asset.check(deps.api)?,
ask_asset.check(deps.api)?,
Expand All @@ -385,18 +386,18 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
offer_amount,
ask_asset,
exclude_paths,
} => to_binary(&query_best_path_for_pair(
} => to_json_binary(&query_best_path_for_pair(
deps,
offer_amount,
offer_asset.check(deps.api)?,
ask_asset.check(deps.api)?,
exclude_paths,
)?),
QueryMsg::SupportedOfferAssets { ask_asset } => {
to_binary(&query_supported_offer_assets(deps, ask_asset)?)
to_json_binary(&query_supported_offer_assets(deps, ask_asset)?)
}
QueryMsg::SupportedAskAssets { offer_asset } => {
to_binary(&query_supported_ask_assets(deps, offer_asset)?)
to_json_binary(&query_supported_ask_assets(deps, offer_asset)?)
}
}
}
Expand Down Expand Up @@ -492,7 +493,7 @@ pub fn query_best_path_for_pair(

let swap_paths: Result<Vec<BestPathForPairResponse>, ContractError> = paths
.into_iter()
.map(|(id, swaps)| {
.map(|(_, swaps)| {
let out = simulate_swap_operations(deps, offer_amount, swaps.clone().into())?;
Ok(BestPathForPairResponse {
operations: swaps,
Expand Down
5 changes: 3 additions & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use apollo_cw_asset::Asset;
use cosmwasm_std::{OverflowError, StdError};
use cw_controllers::AdminError;
use cw_dex::CwDexError;
Expand Down Expand Up @@ -40,8 +41,8 @@ pub enum ContractError {
#[error("Paths to check is empty, excluded paths excludes all valid paths")]
NoPathsToCheck,

#[error("Did not receive minimum amount")]
FailedMinimumReceive,
#[error("Did not receive minimum amount, wanted: {wanted}, got: {got}")]
FailedMinimumReceive { wanted: Asset, got: Asset },

#[error("No path found for assets {offer:?} -> {ask:?}")]
NoPathFound { offer: String, ask: String },
Expand Down
18 changes: 8 additions & 10 deletions src/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
use std::vec;

use apollo_cw_asset::{Asset, AssetInfo, AssetInfoBase, AssetList};
use apollo_utils::assets::separate_natives_and_cw20s;
use apollo_cw_asset::{Asset, AssetInfo, AssetList};
use cosmwasm_schema::cw_serde;
use cw20::{Cw20Coin, Cw20ExecuteMsg};

use cosmwasm_std::{
to_binary, Addr, Api, Coin, CosmosMsg, Env, MessageInfo, QuerierWrapper, QueryRequest,
to_json_binary, Addr, Api, Coin, CosmosMsg, Env, MessageInfo, QuerierWrapper, QueryRequest,
StdError, StdResult, Uint128, WasmMsg, WasmQuery,
};

Expand Down Expand Up @@ -48,7 +46,7 @@ impl CwDexRouterUnchecked {
Ok(CosmosMsg::Wasm(WasmMsg::Instantiate {
code_id,
admin,
msg: to_binary(&InstantiateMsg {})?,
msg: to_json_binary(&InstantiateMsg {})?,
funds: vec![],
label: label.unwrap_or_else(|| "cw-dex-router".to_string()),
}))
Expand All @@ -65,7 +63,7 @@ impl CwDexRouter {
}

pub fn call<T: Into<ExecuteMsg>>(&self, msg: T, funds: Vec<Coin>) -> StdResult<CosmosMsg> {
let msg = to_binary(&msg.into())?;
let msg = to_json_binary(&msg.into())?;
Ok(WasmMsg::Execute {
contract_addr: self.addr().into(),
msg,
Expand Down Expand Up @@ -169,7 +167,7 @@ impl CwDexRouter {
) -> StdResult<Uint128> {
querier.query(&QueryRequest::Wasm(WasmQuery::Smart {
contract_addr: self.0.to_string(),
msg: to_binary(&QueryMsg::SimulateSwapOperations {
msg: to_json_binary(&QueryMsg::SimulateSwapOperations {
offer_amount,
operations: operations.into(),
})?,
Expand Down Expand Up @@ -199,7 +197,7 @@ impl CwDexRouter {
) -> StdResult<SwapOperationsList> {
querier.query(&QueryRequest::Wasm(WasmQuery::Smart {
contract_addr: self.0.to_string(),
msg: to_binary(&QueryMsg::PathsForPair {
msg: to_json_binary(&QueryMsg::PathsForPair {
offer_asset: offer_asset.to_owned().into(),
ask_asset: ask_asset.to_owned().into(),
})?,
Expand All @@ -213,7 +211,7 @@ impl CwDexRouter {
) -> StdResult<Vec<AssetInfo>> {
querier.query(&QueryRequest::Wasm(WasmQuery::Smart {
contract_addr: self.0.to_string(),
msg: to_binary(&QueryMsg::SupportedOfferAssets {
msg: to_json_binary(&QueryMsg::SupportedOfferAssets {
ask_asset: ask_asset.to_owned().into(),
})?,
}))
Expand All @@ -226,7 +224,7 @@ impl CwDexRouter {
) -> StdResult<Vec<AssetInfo>> {
querier.query(&QueryRequest::Wasm(WasmQuery::Smart {
contract_addr: self.0.to_string(),
msg: to_binary(&QueryMsg::SupportedAskAssets {
msg: to_json_binary(&QueryMsg::SupportedAskAssets {
offer_asset: offer_asset.to_owned().into(),
})?,
}))
Expand Down
2 changes: 1 addition & 1 deletion src/msg.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use apollo_cw_asset::{AssetInfo, AssetInfoUnchecked, AssetListUnchecked};
use apollo_cw_asset::{AssetInfo, AssetInfoUnchecked};
use cosmwasm_schema::{cw_serde, QueryResponses};
use cosmwasm_std::{wasm_execute, Addr, CosmosMsg, Empty, Env, Uint128};
use cw20::Cw20ReceiveMsg;
Expand Down
29 changes: 1 addition & 28 deletions src/tests/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,4 @@
use cosmwasm_std::{Attribute, Coin};
use osmosis_std::types::cosmwasm::wasm::v1::MsgExecuteContractResponse;
use osmosis_test_tube::ExecuteResponse;

pub fn create_cl_pool() {}

pub fn get_event_attributes_by_ty_and_key(
response: &ExecuteResponse<MsgExecuteContractResponse>,
ty: &str,
keys: Vec<&str>,
) -> Vec<Attribute> {
response
.events
.iter()
.filter(|event| event.ty == ty)
.flat_map(|event| event.attributes.clone())
.filter(|attribute| keys.contains(&attribute.key.as_str()))
.collect()
}

pub fn get_event_value_amount_numeric(value: &String) -> u128 {
// Find the position where the non-numeric part starts
let pos = value.find(|c: char| !c.is_numeric()).unwrap_or(value.len());
// Extract the numeric part from the string
let numeric_part = &value[0..pos];
// Try to parse the numeric string to u128
numeric_part.parse::<u128>().unwrap()
}
use cosmwasm_std::Coin;

pub fn sort_tokens(tokens: Vec<Coin>) -> Vec<Coin> {
let mut sorted_tokens = tokens;
Expand Down
Loading

0 comments on commit daaecce

Please sign in to comment.