Skip to content
This repository was archived by the owner on Oct 30, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions contracts/modules/apis/dex/src/commands.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::{error::DexError, DEX};
use abstract_os::dex::state::SWAP_FEE;
use abstract_os::objects::{DexAssetPairing, PoolReference};
use abstract_sdk::cw_helpers::fees::Chargeable;
use abstract_sdk::features::AbstractNameService;
use abstract_sdk::os::dex::AskAsset;
use abstract_sdk::os::objects::AnsAsset;
Expand Down Expand Up @@ -128,16 +130,20 @@ pub trait LocalDex: AbstractNameService + Execution {

let pair_address =
exchange.pair_address(deps, ans.host(), (offer_asset.clone(), ask_asset))?;
let offer_asset: Asset = Asset::new(offer_asset_info, offer_amount);

exchange.swap(
let mut offer_asset: Asset = Asset::new(offer_asset_info, offer_amount);
// account for fee
let fee = SWAP_FEE.load(deps.storage)?;
let fee_msg = offer_asset.charge_usage_fee(fee)?;
let mut swap_msgs = exchange.swap(
deps,
pair_address,
offer_asset,
ask_asset_info,
belief_price,
max_spread,
)
)?;
swap_msgs.push(fee_msg);
Ok(swap_msgs)
}

#[allow(clippy::too_many_arguments)]
Expand Down
11 changes: 5 additions & 6 deletions contracts/modules/apis/dex/src/contract.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
use crate::{error::DexError, handlers};
use abstract_api::ApiContract;
use abstract_sdk::os::{
dex::{DexExecuteMsg, DexQueryMsg},
EXCHANGE,
};
use cosmwasm_std::{Empty, Response};
use abstract_os::dex::{DexApiExecuteMsg, DexInstantiateMsg, DexQueryMsg};
use abstract_sdk::os::EXCHANGE;
use cosmwasm_std::Response;

const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");

pub type DexApi = ApiContract<DexError, DexExecuteMsg, Empty, DexQueryMsg>;
pub type DexApi = ApiContract<DexError, DexApiExecuteMsg, DexInstantiateMsg, DexQueryMsg>;
pub type DexResult<T = Response> = Result<T, DexError>;

pub const DEX_API: DexApi = DexApi::new(EXCHANGE, CONTRACT_VERSION, None)
.with_instantiate(handlers::instantiate_handler)
.with_execute(handlers::execute_handler)
.with_query(handlers::query_handler);

Expand Down
53 changes: 39 additions & 14 deletions contracts/modules/apis/dex/src/handlers/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ use crate::contract::{DexApi, DexResult};
use crate::error::DexError;
use crate::exchanges::exchange_resolver;
use crate::LocalDex;
use abstract_os::dex::{DexAction, DexExecuteMsg, DexName, IBC_DEX_ID};
use abstract_os::dex::state::SWAP_FEE;
use abstract_os::dex::{DexAction, DexApiExecuteMsg, DexExecuteMsg, DexName, IBC_DEX_ID};
use abstract_os::ibc_client::CallbackInfo;
use abstract_os::objects::ans_host::AnsHost;
use abstract_os::objects::AnsAsset;
use abstract_sdk::features::AbstractNameService;
use abstract_sdk::{IbcInterface, Resolve};
use abstract_sdk::{IbcInterface, OsVerification, Resolve};
use cosmwasm_std::{to_binary, Coin, Deps, DepsMut, Env, MessageInfo, Response, StdError};

const ACTION_RETRIES: u8 = 3;
Expand All @@ -17,19 +18,43 @@ pub fn execute_handler(
env: Env,
info: MessageInfo,
api: DexApi,
msg: DexExecuteMsg,
msg: DexApiExecuteMsg,
) -> DexResult {
let DexExecuteMsg {
dex: dex_name,
action,
} = msg;
let exchange = exchange_resolver::identify_exchange(&dex_name)?;
// if exchange is on an app-chain, execute the action on the app-chain
if exchange.over_ibc() {
handle_ibc_api_request(&deps, info, &api, dex_name, &action)
} else {
// the action can be executed on the local chain
handle_local_api_request(deps, env, info, api, action, dex_name)
match msg {
DexApiExecuteMsg::Action(msg) => {
let DexExecuteMsg {
dex: dex_name,
action,
} = msg;
let exchange = exchange_resolver::identify_exchange(&dex_name)?;
// if exchange is on an app-chain, execute the action on the app-chain
if exchange.over_ibc() {
handle_ibc_api_request(&deps, info, &api, dex_name, &action)
} else {
// the action can be executed on the local chain
handle_local_api_request(deps, env, info, api, action, dex_name)
}
}
DexApiExecuteMsg::UpdateFee {
swap_fee,
recipient_os_id,
} => {
// only previous OS can change the owner
api.os_registry(deps.as_ref()).assert_proxy(&info.sender)?;
if let Some(swap_fee) = swap_fee {
let mut fee = SWAP_FEE.load(deps.storage)?;
fee.set_share(swap_fee)?;
SWAP_FEE.save(deps.storage, &fee)?;
}

if let Some(os_id) = recipient_os_id {
let mut fee = SWAP_FEE.load(deps.storage)?;
let recipient = api.os_registry(deps.as_ref()).proxy_address(os_id)?;
fee.set_recipient(deps.api, recipient)?;
SWAP_FEE.save(deps.storage, &fee)?;
}
Ok(Response::default())
}
}
}

Expand Down
22 changes: 22 additions & 0 deletions contracts/modules/apis/dex/src/handlers/instantiate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use crate::contract::{DexApi, DexResult};
use abstract_os::{
dex::{state::SWAP_FEE, DexInstantiateMsg},
objects::fee::UsageFee,
};
use abstract_sdk::OsVerification;
use cosmwasm_std::{DepsMut, Env, MessageInfo, Response};

pub fn instantiate_handler(
deps: DepsMut,
_env: Env,
_info: MessageInfo,
api: DexApi,
msg: DexInstantiateMsg,
) -> DexResult {
let recipient = api
.os_registry(deps.as_ref())
.proxy_address(msg.recipient_os)?;
let fee = UsageFee::new(deps.api, msg.swap_fee, recipient)?;
SWAP_FEE.save(deps.storage, &fee)?;
Ok(Response::default())
}
3 changes: 2 additions & 1 deletion contracts/modules/apis/dex/src/handlers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod execute;
mod instantiate;
mod query;

pub use {execute::execute_handler, query::query_handler};
pub use {execute::execute_handler, instantiate::instantiate_handler, query::query_handler};
8 changes: 8 additions & 0 deletions contracts/modules/apis/dex/src/handlers/query.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::contract::{DexApi, DexResult};
use crate::exchanges::exchange_resolver::resolve_exchange;
use abstract_os::dex::state::SWAP_FEE;
use abstract_os::dex::{DexQueryMsg, OfferAsset, SimulateSwapResponse};
use abstract_os::objects::{AssetEntry, DexAssetPairing};
use abstract_sdk::features::AbstractNameService;
Expand Down Expand Up @@ -27,6 +28,8 @@ pub fn simulate_swap(
) -> DexResult<Binary> {
let exchange = resolve_exchange(&dex).map_err(|e| StdError::generic_err(e.to_string()))?;
let ans = api.name_service(deps);
let fee = SWAP_FEE.load(deps.storage)?;

// format input
offer_asset.name.format();
ask_asset.format();
Expand All @@ -47,6 +50,10 @@ pub fn simulate_swap(
let pool_info =
DexAssetPairing::new(offer_asset.name.clone(), ask_asset.clone(), exchange.name());

// compute api fee
let api_fee = fee.compute(offer_asset.amount);
offer_asset.amount -= api_fee;

let (return_amount, spread_amount, commission_amount, fee_on_input) = exchange
.simulate_swap(deps, pair_address, swap_offer_asset, ask_asset_info)
.map_err(|e| StdError::generic_err(e.to_string()))?;
Expand All @@ -60,6 +67,7 @@ pub fn simulate_swap(
return_amount,
spread_amount,
commission: (commission_asset, commission_amount),
api_fee,
};
to_binary(&resp).map_err(From::from)
}
1 change: 0 additions & 1 deletion contracts/native/ibc-client/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,6 @@ fn clear_accounts(store: &mut dyn Storage) {
mod test {
use super::*;
use crate::contract;

use abstract_os::{ibc_client::*, AbstractResult};
use abstract_testing::{TEST_ADMIN, TEST_ANS_HOST, TEST_VERSION_CONTROL};
use cosmwasm_std::{
Expand Down
10 changes: 4 additions & 6 deletions packages/abstract-app/src/endpoints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,14 @@ macro_rules! export_endpoints {

#[cfg(test)]
mod test {

use cosmwasm_std::{
testing::{mock_dependencies, mock_env, mock_info},
SubMsgResult,
};

use abstract_sdk::base::{
ExecuteEndpoint, InstantiateEndpoint, MigrateEndpoint, QueryEndpoint, ReplyEndpoint,
};
use abstract_testing::{TEST_ADMIN, TEST_ANS_HOST};
use cosmwasm_std::{
testing::{mock_dependencies, mock_env, mock_info},
SubMsgResult,
};
use speculoos::prelude::*;

use crate::test_common::*;
Expand Down
39 changes: 35 additions & 4 deletions packages/abstract-os/src/modules/apis/dex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,47 @@ pub type DexName = String;
pub type OfferAsset = AnsAsset;
pub type AskAsset = AnsAsset;

pub mod state {
use cw_storage_plus::Item;

use crate::objects::fee::UsageFee;

pub const SWAP_FEE: Item<UsageFee> = Item::new("swap_fee");
}

pub const IBC_DEX_ID: u32 = 11335;

pub type ExecuteMsg = api::ExecuteMsg<DexExecuteMsg>;
pub type ExecuteMsg = api::ExecuteMsg<DexApiExecuteMsg>;
pub type QueryMsg = api::QueryMsg<DexQueryMsg>;
pub type InstantiateMsg = api::InstantiateMsg<DexInstantiateMsg>;

impl api::ApiExecuteMsg for DexExecuteMsg {}

impl api::ApiExecuteMsg for DexApiExecuteMsg {}
impl api::ApiQueryMsg for DexQueryMsg {}

#[cosmwasm_schema::cw_serde]
pub struct DexInstantiateMsg {
pub swap_fee: Decimal,
pub recipient_os: u32,
}

/// Dex Execute msg
#[cosmwasm_schema::cw_serde]
pub enum DexApiExecuteMsg {
Action(DexExecuteMsg),
UpdateFee {
swap_fee: Option<Decimal>,
recipient_os_id: Option<u32>,
},
}
Comment on lines +40 to +47
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I guess the json would be:

{
  "app": {
    "action": {
      "action": {
        "swap": {...}
      },
      "dex": "lolswap",
    }
  }
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{
  "app": {
    "execute": {
      "dex": "lolswap",
      "action": {
        "swap": {...}
      },
    }
  }
}

?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The users shouldn't be interacting with the json too much but still the nested duplicate names can be confusing.

Copy link
Contributor

@adairrr adairrr Feb 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An alternative to this is to add a configure "endpoint" to the ApiExecuteMsg which would be a different "handler" on the API. That way we don't add additional nesting at the api module level.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmmm.....
Executing:

{
  "app": {
    "dex": "lolswap",
    "action": {
      "swap": {...}
    },
  }
}

Configuring:

{
  "configure": {
    "update_fee": {...}
  }
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to discuss this during standup

Copy link
Contributor Author

@CyberHoward CyberHoward Feb 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think adding a #[serde(flatten)] tag to the action variant should remove the nested nature of the msg

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not even sure if those unit-enum variants actually get their own key or if the inner value name is used as key.

Copy link
Contributor Author

@CyberHoward CyberHoward Feb 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code:

use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Clone, Debug)]
struct FooFoo {
    x: i32,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
enum Bar {
    Foo(FooFoo),
    Baz,
}

fn main() {
    let bar = Bar::Foo(FooFoo { x: 42 });

    println!("bar = {:?}", bar);
    println!("bar = {}", serde_json::to_string_pretty(&bar).unwrap());
}

Returns:

bar = Foo(FooFoo { x: 42 })
bar = {
  "Foo": {
    "x": 42
  }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could also opt for a "type" tag which would look like:

bar = {
  "type": "Foo",
  "x": 42
}

And change the Action name to something different.


impl From<DexExecuteMsg> for DexApiExecuteMsg {
fn from(action: DexExecuteMsg) -> Self {
DexApiExecuteMsg::Action(action)
}
}

/// Dex Execute msg
#[cosmwasm_schema::cw_serde]
// Struct messages not yet supported by BOOT
pub struct DexExecuteMsg {
pub dex: DexName,
pub action: DexAction,
Expand Down Expand Up @@ -100,4 +129,6 @@ pub struct SimulateSwapResponse {
pub spread_amount: Uint128,
/// Commission charged for the swap
pub commission: (AssetEntry, Uint128),
/// API fee charged for the swap (paid in offer asset)
pub api_fee: Uint128,
}
Loading