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}