dexter 1.4.0

Dex optimized for liquid staked assets
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
use crate::asset::{Asset, AssetInfo};
use cosmwasm_schema::{cw_serde, QueryResponses};
use cosmwasm_std::{Addr, Binary, Decimal, Uint128};
use cw20::Cw20ReceiveMsg;
use std::fmt::{Display, Formatter, Result};

// TWAP PRECISION is 9 decimal places
pub const TWAP_PRECISION: u16 = 9u16;

// ----------------x----------------x----------------x----------------x----------------x----------------
// ----------------x----------------x    {{PoolType}} enum Type       x----------------x----------------
// ----------------x----------------x----------------x----------------x----------------x----------------

/// This enum describes the key for the different Pool types supported by Dexter
#[cw_serde]
pub enum PoolType {
    /// Stable pool type
    StableSwap {},
    /// Weighted pool type
    Weighted {},
    /// Custom pool type
    Custom(String),
}

// Return a raw encoded string representing the name of each pool type
impl Display for PoolType {
    fn fmt(&self, fmt: &mut Formatter) -> Result {
        match self {
            PoolType::Weighted {} => fmt.write_str("weighted"),
            PoolType::StableSwap {} => fmt.write_str("stable-swap"),
            PoolType::Custom(pool_type) => fmt.write_str(format!("custom-{}", pool_type).as_str()),
        }
    }
}

// ----------------x----------------x----------------x----------------x----------------x----------------
// ----------------x----------------x    {{SwapType}} enum Type    x----------------x-------------------
// ----------------x----------------x----------------x----------------x----------------x----------------

/// This enum describes available Swap types.
#[cw_serde]
pub enum SwapType {
    GiveIn {},
    GiveOut {},
    /// Custom swap type
    Custom(String),
}

impl Display for SwapType {
    fn fmt(&self, fmt: &mut Formatter) -> Result {
        match self {
            SwapType::GiveIn {} => fmt.write_str("give-in"),
            SwapType::GiveOut {} => fmt.write_str("give-out"),
            SwapType::Custom(swap_type) => fmt.write_str(format!("custom-{}", swap_type).as_str()),
        }
    }
}

// ----------------x----------------x----------------x----------------x----------------x----------------
// ----------------x----------------x    {{FeeInfo}} struct Type    x----------------x-------------------
// ----------------x----------------x----------------x----------------x----------------x----------------

// We want to keep a precision of 2 decimal places, so we need to keep FEE_PRECISION as 10^4.
// Fee % = (fee_bps / FEE_PRECISION) * 100
// => 1% = (10^2 / 10^4) * 100
// Similarly,
// => 10% = (10^3 / 10^4) * 100
// => MAX_TOTAL_FEE_BPS should be 10^3.
// Also, if we want to set a fee of 0.01%, then we would supply the fee_bps as 1.
// => 0.01% = (1 / 10^4) * 100
pub const FEE_PRECISION: u16 = 10_000u16;
// Maximum total commission in bps that can be charged on any supported pool by Dexter
// It is currently 10%
const MAX_TOTAL_FEE_BPS: u16 = 1_000u16;
// Maximum total protocol fee as % of the commission fee that can be charged on any supported pool by Dexter
const MAX_PROTOCOL_FEE_PERCENT: u16 = 100u16;

/// ## Description - This struct describes the Fee configuration supported by a particular pool type.
#[cw_serde]
pub struct FeeInfo {
    pub total_fee_bps: u16,
    pub protocol_fee_percent: u16,
}

impl FeeInfo {
    /// This method is used to check fee bps.
    pub fn valid_fee_info(&self) -> bool {
        self.total_fee_bps <= MAX_TOTAL_FEE_BPS
            && self.protocol_fee_percent <= MAX_PROTOCOL_FEE_PERCENT
    }

    // Returns the number of tokens charged as protocol fee
    pub fn calculate_total_fee_breakup(&self, total_fee: Uint128) -> Uint128 {
        let protocol_fee: Uint128 =
            total_fee * Decimal::from_ratio(self.protocol_fee_percent, Uint128::from(100u128));

        protocol_fee
    }
}

#[cw_serde]
pub struct NativeAssetPrecisionInfo {
    pub denom: String,
    pub precision: u8,
}

// ----------------x----------------x----------------x----------------x----------------x----------------
// ----------------x----------------x    Generic struct Types      x----------------x-------------------
// ----------------x----------------x----------------x----------------x----------------x----------------

/// ## Description - This struct describes the main control config of Vault.
#[cw_serde]
pub struct Config {
    /// The admin address that controls settings for factory, pools and tokenomics contracts
    pub owner: Addr,
    /// Additional allowed addresses to create/manage pools. If empty, only owner can create/manage pools
    pub whitelisted_addresses: Vec<Addr>,
    /// The Contract ID that is used for instantiating LP tokens for new pools
    pub lp_token_code_id: Option<u64>,
    /// The contract address to which protocol fees are sent
    pub fee_collector: Option<Addr>,
    /// Which auto-stake feature is enabled for the pool
    /// Multistaking allows for staking of LP tokens with N-different rewards in a single contract.
    /// If none, it will disable auto-staking feature
    pub auto_stake_impl: AutoStakeImpl,
    /// Fee required for creating a new pool.
    /// Ideally, it is charged in the base currency of the chain but can be changed to governance token later
    pub pool_creation_fee: PoolCreationFee,
    /// The next pool ID to be used for creating new pools
    pub next_pool_id: Uint128,
    /// The global pause status for the vault. This overrides the pause status of any pool type or pool id.
    pub paused: PauseInfo,
}

#[cw_serde]
pub enum AllowPoolInstantiation {
    Everyone,
    OnlyWhitelistedAddresses,
    Nobody,
}

impl Display for AllowPoolInstantiation {
    fn fmt(&self, fmt: &mut Formatter) -> Result {
        match self {
            AllowPoolInstantiation::Everyone => fmt.write_str("everyone"),
            AllowPoolInstantiation::OnlyWhitelistedAddresses => {
                fmt.write_str("only-whitelisted-addresses")
            }
            AllowPoolInstantiation::Nobody => fmt.write_str("nobody"),
        }
    }
}
/// This struct stores a pool type's configuration.
#[cw_serde]
pub struct PoolTypeConfig {
    /// ID of contract which is used to create pools of this type
    pub code_id: u64,
    /// The pools type (provided in a [`PoolType`])
    pub pool_type: PoolType,
    pub default_fee_info: FeeInfo,
    /// Controls whether the pool can be created by anyone or only by whitelisted addresses (if any) or not at all
    pub allow_instantiation: AllowPoolInstantiation,
    /// The pause status for this pool type. This overrides the pause status of any pool id of this type.
    pub paused: PauseInfo,
}

/// ## Description - This is an intermediate struct for storing the pool config during pool creation and used in reply of submessage.
#[cw_serde]
pub struct TmpPoolInfo {
    /// ID of contract which is used to create pools of this type
    pub code_id: u64,
    /// ID of this pool
    pub pool_id: Uint128,
    /// Address of the LP Token Contract
    pub lp_token_addr: Option<Addr>,
    /// Fee charged by the pool for swaps
    pub fee_info: FeeInfo,
    /// Assets and their respective balances
    pub assets: Vec<Asset>,
    /// Native asset precisions
    pub native_asset_precisions: Vec<NativeAssetPrecisionInfo>,
    /// The pools type (provided in a [`PoolType`])
    pub pool_type: PoolType,
    /// Object of type [`Binary`] which contains any custom params required by the Pool instance for its initialization.
    pub init_params: Option<Binary>,
}

/// This struct stores a pool type's configuration.
#[cw_serde]
pub struct PoolInfo {
    /// ID of this pool
    pub pool_id: Uint128,
    /// Address of the Pool Contract    
    pub pool_addr: Addr,
    /// Address of the LP Token Contract    
    pub lp_token_addr: Addr,
    /// Fee charged by the pool for swaps
    pub fee_info: FeeInfo,
    /// Assets and their respective balances
    pub assets: Vec<Asset>,
    /// The pools type (provided in a [`PoolType`])
    pub pool_type: PoolType,
    /// Pause status for this pool
    pub paused: PauseInfo,
}

#[cw_serde]
#[derive(Default)]
pub struct PauseInfo {
    /// True if swaps are paused
    pub swap: bool,
    /// True if deposits are paused
    pub deposit: bool,
    // We aren't allowing pause for withdrawals as of now.
    // We allow pause of imbalanced withdraws to protect LPs from being drained by malicious actors
    // in case any token supply is compromised.
    pub imbalanced_withdraw: bool,
}

#[cw_serde]
pub enum PoolCreationFee {
    Disabled,
    Enabled {
        fee: Asset
    }
}

impl Default for PoolCreationFee {
    fn default() -> Self {
        PoolCreationFee::Disabled
    }
}

impl Display for PauseInfo {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        f.write_str(format!("swap: {}, deposit: {}", self.swap, self.deposit).as_str())
    }
}

#[cw_serde]
pub struct SingleSwapRequest {
    pub pool_id: Uint128,
    pub asset_in: AssetInfo,
    pub asset_out: AssetInfo,
    pub swap_type: SwapType,
    pub amount: Uint128,
}

// ----------------x----------------x----------------x----------------x----------------x----------------
// ----------------x----------------x    Instantiate, Execute Msgs and Queries      x----------------x--
// ----------------x----------------x----------------x----------------x----------------x----------------

#[cw_serde]
pub enum AutoStakeImpl {
    //  This means that auto-staking is disabled
    None,
    // This will enable auto-staking feature for staking of LP tokens with N-different rewards in a single contract
    Multistaking {
        contract_addr: Addr,
    }
}

impl Display for AutoStakeImpl {
    fn fmt(&self, fmt: &mut Formatter) -> Result {
        match &self {
            AutoStakeImpl::None => fmt.write_str("none"),
            AutoStakeImpl::Multistaking { contract_addr } => {
                fmt.write_str(format!("multistaking: {}", contract_addr).as_str())
            }
        }
    }
}

/// This struct describes the Msg used to instantiate in this contract.
#[cw_serde]
pub struct InstantiateMsg {
    pub owner: String,
    /// IDs and configs of contracts that are allowed to instantiate pools
    pub pool_configs: Vec<PoolTypeConfig>,
    /// This ID is optional but mandatory to create any pool.
    /// It is kept optional during instantiation to allow for the case where the contract is instantiated
    /// without any LP token contract and then later on, the LP token contract is stored 
    /// in the contract's state and then used to create pools
    pub lp_token_code_id: Option<u64>,
    pub fee_collector: Option<String>,
    pub pool_creation_fee: PoolCreationFee,
    /// Specifies which auto-stake implementation has to be used.
    pub auto_stake_impl: AutoStakeImpl
}

#[cw_serde]
pub enum PauseInfoUpdateType {
    PoolId(Uint128),
    PoolType(PoolType)
}

/// This struct describes the functions that can be executed in this contract.
#[cw_serde]
pub enum ExecuteMsg {
    // Receives LP Tokens when removing Liquidity
    Receive(Cw20ReceiveMsg),
    /// Executable only by `config.owner`. Facilitates updating parameters like `config.fee_collector`,
    /// `config.lp_token_code_id`, etc.
    UpdateConfig {
        lp_token_code_id: Option<u64>,
        fee_collector: Option<String>,
        // Fee required for creating a new pool.
        pool_creation_fee: Option<PoolCreationFee>,
        auto_stake_impl: Option<AutoStakeImpl>,
        paused: Option<PauseInfo>,
    },
    AddAddressToWhitelist { 
        address: String 
    },
    RemoveAddressFromWhitelist { 
        address: String 
    },
    /// Allows updating pause info of pools to whitelisted addresses.
    /// Pools can be paused based on a know pool_id or pool_type.
    UpdatePauseInfo {
        update_type: PauseInfoUpdateType,
        pause_info: PauseInfo,
    },
    ///  Executable only by `config.owner`.
    /// Facilitates enabling / disabling new pool instances creation (`pool_config.is_disabled`) ,
    /// and updating Fee (` pool_config.fee_info`) for new pool instances
    UpdatePoolTypeConfig {
        pool_type: PoolType,
        allow_instantiation: Option<AllowPoolInstantiation>,
        new_fee_info: Option<FeeInfo>,
        paused: Option<PauseInfo>,
    },
    ///  Adds a new pool with a new [`PoolType`] Key.                                                                       
    AddToRegistry {
        new_pool_type_config: PoolTypeConfig,
    },
    /// Creates a new pool with the specified parameters in the `asset_infos` variable.                               
    CreatePoolInstance {
        pool_type: PoolType,
        asset_infos: Vec<AssetInfo>,
        native_asset_precisions: Vec<NativeAssetPrecisionInfo>,
        fee_info: Option<FeeInfo>,
        init_params: Option<Binary>,
    },
    /// Updates the pool config for a pool with the specified `pool_id`.
    /// This can be used to update the fee, pause info, etc. for a pool.
    UpdatePoolConfig {
        pool_id: Uint128,
        fee_info: Option<FeeInfo>,
        paused: Option<PauseInfo>,
    },
    /// Updates the pool params for a pool with the specified `pool_id`.
    UpdatePoolParams {
        pool_id: Uint128,
        params: Binary,
    },

    // Entry point for a user to Join a pool supported by the Vault. User can join by providing the pool id and
    // either the number of assets to be provided or the LP tokens to be minted to the user (as defined by the Pool Contract).                        |
    JoinPool {
        pool_id: Uint128,
        recipient: Option<String>,
        assets: Option<Vec<Asset>>,
        min_lp_to_receive: Option<Uint128>,
        auto_stake: Option<bool>,
    },
    // Entry point for a swap tx between offer and ask assets. The swap request details are passed in
    // [`SingleSwapRequest`] Type parameter.
    Swap {
        swap_request: SingleSwapRequest,
        recipient: Option<String>,
        min_receive: Option<Uint128>,
        max_spend: Option<Uint128>,
    },
    /// ProposeNewOwner creates an offer for a new owner. The validity period of the offer is set in the `expires_in` variable.
    ProposeNewOwner {
        new_owner: String,
        expires_in: u64,
    },
    /// DropOwnershipProposal removes the existing offer for the new owner.
    DropOwnershipProposal {},
    /// Used to claim(approve) new owner proposal, thus changing contract's owner
    ClaimOwnership {},
}

/// ## Description
/// This struct describes a CW20 hook message.
#[cw_serde]
pub enum Cw20HookMsg {
    /// Withdrawing liquidity from the pool
    ExitPool {
        pool_id: Uint128,
        recipient: Option<String>,
        exit_type: ExitType,
    },
}

/// This struct describes the ways one can choose to exit from a pool.
#[cw_serde]
pub enum ExitType {
    /// Provide this to convey that only this much LP tokens should be burned,
    /// irrespective of how much assets you will get back.
    /// It accepts an optional `min_assets_out` parameter for slippage control.
    /// If the parameter is provided and the assets being given out by burning
    /// `lp_to_burn` LP tokens is less than `min_assets_out`, then the tx will fail.
    /// Since this works via a CW20 hook, you need to send exactly `lp_to_burn`
    /// LP tokens, otherwise the tx will fail.
    ExactLpBurn {
        lp_to_burn: Uint128,
        min_assets_out: Option<Vec<Asset>>,
    },
    /// Provide this to convey that you want exactly these assets out, irrespective of how much LP
    /// tokens need to be burned for that.
    /// It accepts an optional `max_lp_to_burn` parameter for slippage control.
    /// If the parameter is provided and the LP token that get burned for getting
    /// the `assets_out` is more than `max_lp_to_burn`, then the tx will fail.
    /// Since this works via a CW20 hook, you need to send at least `max_lp_to_burn`
    /// LP tokens, otherwise the tx will fail. If you send more tokens, they will be
    /// returned back.
    ExactAssetsOut {
        assets_out: Vec<Asset>,
        max_lp_to_burn: Option<Uint128>,
    }
}

/// Returns the [`PoolType`]'s Configuration settings  in custom [`PoolConfigResponse`] struct

#[cw_serde]
#[derive(QueryResponses)]
pub enum QueryMsg {
    /// Config returns controls settings that specified in custom [`ConfigResponse`] struct
    #[returns[ConfigResponse]]
    Config {},
    /// Return PoolConfig
    #[returns(PoolTypeConfigResponse)]
    QueryRegistry { pool_type: PoolType },
    /// Returns the info of all the pools matching the given pagination params
    #[returns(Vec<PoolInfoResponse>)]
    Pools { start_after: Option<Uint128>, limit: Option<u32> },
    /// Returns the current stored state of the Pool in custom [`PoolInfoResponse`] struct
    #[returns(PoolInfoResponse)]
    GetPoolById { pool_id: Uint128 },
    /// Returns the current stored state of the Pool in custom [`PoolInfoResponse`] struct
    #[returns(PoolInfoResponse)]
    GetPoolByAddress { pool_addr: String },
    /// Returns the current stored state of the Pool in custom [`PoolInfoResponse`] struct
    #[returns(PoolInfoResponse)]
    GetPoolByLpTokenAddress { lp_token_addr: String },
}

/// ## Description -  This struct describes a migration message.
#[cw_serde]
pub enum MigrateMsg {

    V1_1 {
        updated_pool_type_configs: Vec<PoolTypeConfig>,
    }
}

// ----------------x----------------x----------------x----------------x----------------x----------------
// ----------------x----------------x    Response Types      x----------------x----------------x--------
// ----------------x----------------x----------------x----------------x----------------x----------------

/// ## Description -  A custom struct for each query response that returns controls settings of contract.
pub type ConfigResponse = Config;

#[cw_serde]
pub struct AssetFeeBreakup {
    pub asset_info: AssetInfo,
    pub total_fee: Uint128,
    pub protocol_fee: Uint128,
}

pub type PoolTypeConfigResponse = Option<PoolTypeConfig>;

/// ## Description -  A custom struct for query response that returns the
/// current stored state of a Pool Instance identified by either pool_id or pool_address.
/// Parameters -::-
/// `pool_id` - The ID of the pool instance
/// `pool_address` - The address of the pool instance
/// lp_token_address - The address of the LP token contract
/// assets - The current asset balances of the pool
/// pool_type - The type of the pool
pub type PoolInfoResponse = PoolInfo;