abstract_dex_standard/
msg.rs

1#![warn(missing_docs)]
2//! # Dex Adapter API
3// re-export response types
4use abstract_std::{
5    adapter,
6    objects::{
7        fee::{Fee, UsageFee},
8        pool_id::{PoolAddressBase, UncheckedPoolAddress},
9        AnsAsset, AssetEntry, DexAssetPairing,
10    },
11    AbstractError, AbstractResult,
12};
13use cosmwasm_schema::QueryResponses;
14use cosmwasm_std::{Addr, Api, CosmosMsg, Decimal, Uint128};
15use cw_asset::{AssetBase, AssetInfoBase};
16
17pub use crate::action::DexAction;
18
19/// Max fee for the dex adapter actions
20pub const MAX_FEE: Decimal = Decimal::percent(5);
21
22/// The name of the dex to trade on.
23pub type DexName = String;
24
25/// The callback id for interacting with a dex over ibc
26pub const IBC_DEX_PROVIDER_ID: &str = "IBC_DEX_ACTION";
27
28/// Top-level Abstract Adapter execute message. This is the message that is passed to the `execute` entrypoint of the smart-contract.
29pub type ExecuteMsg = adapter::ExecuteMsg<DexExecuteMsg>;
30/// Top-level Abstract Adapter instantiate message. This is the message that is passed to the `instantiate` entrypoint of the smart-contract.
31pub type InstantiateMsg = adapter::InstantiateMsg<DexInstantiateMsg>;
32/// Top-level Abstract Adapter query message. This is the message that is passed to the `query` entrypoint of the smart-contract.
33pub type QueryMsg = adapter::QueryMsg<DexQueryMsg>;
34
35impl adapter::AdapterExecuteMsg for DexExecuteMsg {}
36impl adapter::AdapterQueryMsg for DexQueryMsg {}
37
38/// Response for simulating a swap.
39#[cosmwasm_schema::cw_serde]
40pub struct SimulateSwapResponse<A = AssetEntry> {
41    /// The pool on which the swap was simulated
42    pub pool: DexAssetPairing<A>,
43    /// Amount you would receive when performing the swap.
44    pub return_amount: Uint128,
45    /// Spread in ask_asset for this swap
46    pub spread_amount: Uint128,
47    // LP/protocol fees could be withheld from either input or output so commission asset must be included.
48    /// Commission charged for the swap
49    pub commission: (A, Uint128),
50    /// Adapter fee charged for the swap (paid in offer asset)
51    pub usage_fee: Uint128,
52}
53
54/// Response from GenerateMsgs
55#[cosmwasm_schema::cw_serde]
56pub struct GenerateMessagesResponse {
57    /// Messages generated for dex action
58    pub messages: Vec<CosmosMsg>,
59}
60
61/// Response for Dex Fees
62#[cosmwasm_schema::cw_serde]
63pub struct DexFeesResponse {
64    /// Fee for using swap action
65    pub swap_fee: Fee,
66    /// Address where all fees will go
67    pub recipient: Addr,
68}
69
70/// Instantiation message for dex adapter
71#[cosmwasm_schema::cw_serde]
72pub struct DexInstantiateMsg {
73    /// Fee charged on each swap.
74    pub swap_fee: Decimal,
75    /// Recipient account for fees.
76    pub recipient_account: u32,
77}
78
79/// Dex Execute msg
80#[cosmwasm_schema::cw_serde]
81pub enum DexExecuteMsg {
82    /// Update the fee
83    UpdateFee {
84        /// New fee to set
85        swap_fee: Option<Decimal>,
86        /// New recipient account for fees
87        recipient_account: Option<u32>,
88    },
89    /// Action to perform on the DEX with raw asset denominations
90    Action {
91        /// The name of the dex to interact with
92        dex: DexName,
93        /// The action to perform
94        action: DexAction,
95    },
96}
97
98#[cosmwasm_schema::cw_serde]
99/// Swap node for swap route
100pub struct SwapNode<T: cw_address_like::AddressLike> {
101    /// Pool id of the swap
102    pub pool_id: PoolAddressBase<T>,
103    /// Asset in return from the swap
104    pub ask_asset: AssetInfoBase<T>,
105}
106
107impl SwapNode<String> {
108    /// Validate data contained in an _unchecked_ **swap node** instance; return a new _checked_
109    /// **swap node** instance:
110    /// * For Contract addresses, assert its address is valid
111    ///
112    ///
113    /// ```rust,no_run
114    /// use cosmwasm_std::{Addr, Api};
115    /// use abstract_dex_standard::msg::SwapNode;
116    /// use abstract_std::AbstractResult;
117    ///
118    /// fn validate_swap_node(api: &dyn Api, swap_node_unchecked: SwapNode<String>) {
119    ///     match swap_node_unchecked.check(api) {
120    ///         Ok(info) => println!("swap node is valid: {}", info.pool_id.to_string()),
121    ///         Err(err) => println!("swap node is invalid! reason: {:?}", err),
122    ///     }
123    /// }
124    /// ```
125    pub fn check(self, api: &dyn Api) -> AbstractResult<SwapNode<Addr>> {
126        Ok(SwapNode {
127            pool_id: self.pool_id.check(api)?,
128            ask_asset: self.ask_asset.check(api, None)?,
129        })
130    }
131}
132
133/// Query messages for the dex adapter
134#[cosmwasm_schema::cw_serde]
135#[derive(QueryResponses, cw_orch::QueryFns)]
136pub enum DexQueryMsg {
137    /// Simulate a swap between two assets
138    /// Returns [`SimulateSwapResponse`]
139    #[returns(SimulateSwapResponse)]
140    SimulateSwap {
141        /// The asset to offer
142        offer_asset: AnsAsset,
143        /// The asset to receive
144        ask_asset: AssetEntry,
145        /// Name of the dex to simulate the swap on
146        dex: DexName,
147    },
148    /// Simulate a swap between two assets
149    /// Returns [`SimulateSwapResponse`]
150    #[returns(SimulateSwapResponse<AssetInfoBase<String>>)]
151    SimulateSwapRaw {
152        /// The asset to offer
153        offer_asset: AssetBase<String>,
154        /// The asset to receive
155        ask_asset: AssetInfoBase<String>,
156        /// Identifies of the pool to simulate the swap on.
157        pool: UncheckedPoolAddress,
158        /// Name of the dex to simulate the swap on
159        dex: DexName,
160    },
161    /// Endpoint can be used by front-end to easily interact with contracts.
162    /// Returns [`GenerateMessagesResponse`]
163    #[returns(GenerateMessagesResponse)]
164    GenerateMessages {
165        /// Execute message to generate messages for
166        message: DexExecuteMsg,
167        /// Sender Addr generate messages for
168        addr_as_sender: String,
169    },
170    /// Fee info for using the different dex actions
171    #[returns(DexFeesResponse)]
172    Fees {},
173}
174
175/// Fees for using the dex adapter
176#[cosmwasm_schema::cw_serde]
177pub struct DexFees {
178    /// Fee for using swap action
179    swap_fee: Fee,
180    /// Address where all fees will go
181    pub recipient: Addr,
182}
183
184impl DexFees {
185    /// Create checked DexFees
186    pub fn new(swap_fee_share: Decimal, recipient: Addr) -> AbstractResult<Self> {
187        Self::check_fee_share(swap_fee_share)?;
188        Ok(Self {
189            swap_fee: Fee::new(swap_fee_share)?,
190            recipient,
191        })
192    }
193
194    /// Update swap share
195    pub fn set_swap_fee_share(&mut self, new_swap_fee_share: Decimal) -> AbstractResult<()> {
196        Self::check_fee_share(new_swap_fee_share)?;
197        self.swap_fee = Fee::new(new_swap_fee_share)?;
198        Ok(())
199    }
200
201    /// Get swap fee
202    pub fn swap_fee(&self) -> Fee {
203        self.swap_fee
204    }
205
206    /// Usage fee for swap
207    pub fn swap_usage_fee(&self) -> AbstractResult<UsageFee> {
208        UsageFee::new(self.swap_fee.share(), self.recipient.clone())
209    }
210
211    fn check_fee_share(fee: Decimal) -> AbstractResult<()> {
212        if fee > MAX_FEE {
213            return Err(AbstractError::Fee(format!(
214                "fee share can't be bigger than {MAX_FEE}"
215            )));
216        }
217        Ok(())
218    }
219}