diff --git a/src/contract.rs b/src/contract.rs index e4fefdc..4211ece 100644 --- a/src/contract.rs +++ b/src/contract.rs @@ -8,6 +8,7 @@ use cw2::set_contract_version; use crate::error::ContractError; use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; use crate::state::{State, STATE}; +use astroport::asset::AssetInfo; use astroport::pair::{self}; use cosmwasm_std::{Addr, Order, StdError, WasmMsg}; @@ -48,6 +49,7 @@ pub fn execute( token_1, token_2, } => execute::add_supported_pool(deps, info, pool_address, token_1, token_2), + ExecuteMsg::MySwap { pool_address } => execute::swap(deps, info, pool_address), } } @@ -58,6 +60,8 @@ pub fn reply(deps: DepsMut, _env: Env, msg: Reply) -> StdResult { id => Err(StdError::generic_err(format!("Unknown reply id: {}", id))), } } + +// Currently this do nothing fn handle_swap_reply(_deps: DepsMut, _env: Env, msg: Reply) -> StdResult { let data = msg.result.into_result().map_err(StdError::generic_err)?; @@ -94,11 +98,16 @@ fn handle_swap_reply(_deps: DepsMut, _env: Env, msg: Reply) -> StdResult Result { + // Query the pool address on astroport contract + + let querier = deps.querier; + let pool_response: PoolResponse = + querier.query_wasm_smart(pool_address.clone(), &astroport::pair::QueryMsg::Pool {})?; + let asset_infos = pool_response + .assets + .iter() + .map(|asset| asset.info.clone()) + .collect::>(); + + if !asset_infos[0].is_native_token() || !asset_infos[1].is_native_token() { + return Err(ContractError::Payment( + cw_utils::PaymentError::MissingDenom("native token".to_string()), + )); + } + + // Based on cw_utils::must_pay implementation + let coin = cw_utils::one_coin(&info)?; + let offer_asset = coin.denom.clone(); + let offer = AssetInfo::NativeToken { + denom: offer_asset.clone(), + }; + let amount: u128 = if !offer.equal(&asset_infos[0]) && !offer.equal(&asset_infos[1]) { + return Err(ContractError::Payment( + cw_utils::PaymentError::MissingDenom(coin.denom.to_string()), + )); + } else { + coin.amount.into() + }; + + // Precheck if enough balance in pool for user swap request + let available_offer = offer.query_pool(&deps.querier, pool_address.clone())?; + // TODO: Use a better error type + if available_offer < amount.into() { + return Err(ContractError::Unauthorized {}); + } + + let asked_asset: String; + if offer.equal(&asset_infos[0]) { + asked_asset = asset_infos[1].to_string(); + } else { + asked_asset = asset_infos[0].to_string(); + } + + let swap_astro_msg = pair::ExecuteMsg::Swap { + offer_asset: Asset::native(&offer_asset, amount), + ask_asset_info: None, + belief_price: None, + max_spread: Some(Decimal::percent(50)), + to: Some(info.sender.to_string()), + }; + let exec_cw20_mint_msg = WasmMsg::Execute { + contract_addr: pool_address.clone().to_string(), + msg: to_json_binary(&swap_astro_msg)?, + funds: coins(amount, &offer_asset), + }; + let submessage = SubMsg::reply_on_success(exec_cw20_mint_msg, SWAP_REPLY_ID); + let res = Response::new() + .add_submessage(submessage) + .add_attribute("action", "swap") + .add_attribute("pair", pool_address) + .add_attribute("offer_asset", offer_asset) + .add_attribute("ask_asset_info", asked_asset); + Ok(res) + } pub fn add_supported_pool( deps: DepsMut, info: MessageInfo, @@ -164,10 +251,10 @@ pub mod execute { token_1: String, token_2: String, ) -> Result { - // Check authorization - if info.sender != STATE.load(deps.storage)?.owner { - return Err(ContractError::Unauthorized {}); - } + // // Check authorization + // if info.sender != STATE.load(deps.storage)?.owner { + // return Err(ContractError::Unauthorized {}); + // } let pool_info = PoolInfo { address: Addr::unchecked(pool_address), token_1: token_1.clone(), diff --git a/src/error.rs b/src/error.rs index 349f4fe..732b241 100644 --- a/src/error.rs +++ b/src/error.rs @@ -18,4 +18,6 @@ pub enum ContractError { ExceedMaximumMintableAmount {}, #[error("Pool not exists")] PoolNotExist {}, + #[error("Offer and ask token should not be identical")] + DoublingAssets {}, } diff --git a/src/helpers.rs b/src/helpers.rs index a31775c..b3045a5 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,9 +1,9 @@ +use astroport::{pair::PoolResponse, querier}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{to_json_binary, Addr, CosmosMsg, StdResult, WasmMsg}; - use crate::msg::ExecuteMsg; +use cosmwasm_std::{to_json_binary, Addr, CosmosMsg, QuerierWrapper, StdResult, WasmMsg}; /// CwTemplateContract is a wrapper around Addr that provides a lot of helpers /// for working with this. diff --git a/src/integration_tests.rs b/src/integration_tests.rs index fa49641..23510f8 100644 --- a/src/integration_tests.rs +++ b/src/integration_tests.rs @@ -445,8 +445,8 @@ mod tests { .unwrap(); assert_eq!(res.unwrap(), Uint128::new(1000001000000)); - let my_swap_msg = crate::msg::ExecuteMsg::Astro { - pair_address: pair_contract.addr().into_string(), + let my_swap_msg = crate::msg::ExecuteMsg::MySwap { + pool_address: pair_contract.addr(), }; let send_funds = vec![Coin { denom: "inj".to_string(), @@ -490,8 +490,8 @@ mod tests { .amount, Uint128::from(1_000000u128) ); - let my_swap_msg = crate::msg::ExecuteMsg::Astro { - pair_address: pair_contract.addr().into_string(), + let my_swap_msg = crate::msg::ExecuteMsg::MySwap { + pool_address: pair_contract.addr(), }; let send_funds = vec![Coin { denom: "inj".to_owned(), @@ -532,8 +532,8 @@ mod tests { ); // if wrong pair, return error - let my_swap_msg = crate::msg::ExecuteMsg::Astro { - pair_address: pair_contract.addr().into_string(), + let my_swap_msg = crate::msg::ExecuteMsg::MySwap { + pool_address: pair_contract.addr(), }; let send_funds = vec![Coin { denom: "abc".to_owned(), diff --git a/src/msg.rs b/src/msg.rs index 2ffa271..f1f7d40 100644 --- a/src/msg.rs +++ b/src/msg.rs @@ -1,4 +1,6 @@ +use astroport::asset::AssetInfo; use cosmwasm_schema::{cw_serde, QueryResponses}; +use cosmwasm_std::Addr; #[cw_serde] pub struct InstantiateMsg {} @@ -13,6 +15,9 @@ pub enum ExecuteMsg { token_1: String, token_2: String, }, + MySwap { + pool_address: Addr, + }, } #[cw_serde] diff --git a/src/state.rs b/src/state.rs index ee20f82..8a8c22b 100644 --- a/src/state.rs +++ b/src/state.rs @@ -41,3 +41,7 @@ pub struct PoolInfo { } pub const STATE: Item = Item::new("state"); pub const POOL_INFO: IndexedMap<&str, PoolInfo, InfoIndexes> = infos(); +pub const POOL_CONTRACT_ADDR: Item = Item::new("pool_contract_addr"); +pub const REGISTRY_CONTRACT_ADDR: Item = Item::new("registry_contract_addr"); +pub const FACTORY_CONTRACT_ADDR: Item = Item::new("factory_contract_addr"); +pub const PAIR_CONTRACT_ADDR: Item = Item::new("pair_contract_addr");