mito-protocol 0.2.7-fixed-docs

A package for interacting with the Mito Protocol
Documentation
use std::collections::BTreeMap;

use cosmwasm_std::{BankQuery, Coin, DepsMut, QueryRequest, StdError, SupplyResponse, Timestamp, Uint128};
use injective_cosmwasm::InjectiveQueryWrapper;
use injective_math::FPDecimal;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use wynd_utils::Curve;

use crate::{
    vault::{AmmInstantiateMsg, InstantiateVaultMsg},
    vesting_errors::ContractError,
};

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct FactoryInstantiateMsg {
    pub owner: String,
    pub launchpad_code_id: u64,
    pub master_address: String,
    pub mito_treasury_address: String,
    pub default_staked_to_subscription: BTreeMap<Uint128, Uint128>,
    pub launch_fee: Coin,
    pub launchpads_quote_denom: String,
    pub quote_decimals: u8,
    pub mito_treasury_fee_basis_points: u16,
    pub vesting_code_id: u64,
}

pub fn validate_denom(denom: &str, deps: &DepsMut<InjectiveQueryWrapper>) -> Result<(), StdError> {
    if denom.is_empty() {
        return Err(StdError::generic_err("denom cannot be empty".to_string()));
    }

    let supply: SupplyResponse = deps.querier.query(&QueryRequest::Bank(BankQuery::Supply { denom: denom.to_string() }))?;

    if supply.amount.amount.is_zero() {
        return Err(StdError::generic_err(format!("denom {} doesn't exist or has 0 supply", denom)));
    }

    Ok(())
}

pub fn validate_staked_to_subscription(staked_to_subscription: &BTreeMap<Uint128, Uint128>) -> Result<(), StdError> {
    if staked_to_subscription.is_empty() {
        return Err(StdError::generic_err(
            "'staked_to_subscription' must contain at least one key-value pair".to_string(),
        ));
    }

    let mut previous_subscription_allowance = Uint128::zero();

    staked_to_subscription.iter().try_for_each(|(_, subscription_allowance)| {
        if subscription_allowance <= &previous_subscription_allowance {
            return Err(StdError::generic_err(
                "subscription allowance must be greater than previous allowance".to_string(),
            ));
        }

        previous_subscription_allowance = subscription_allowance.to_owned();

        Ok(())
    })?;

    Ok(())
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct AmmLaunchConfig {
    pub msg: Box<AmmInstantiateMsg>,
    pub code_id: u64,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub enum FactoryExecuteMsg {
    RegisterVaultInMaster {
        instantiate_vault_msg: Box<InstantiateVaultMsg>,
        vault_code_id: u64,
        vault_label: String,
    },
    UpdateConfig {
        owner: Option<String>,
        launchpad_code_id: Option<u64>,
        vesting_code_id: Option<u64>,
        launch_fee: Option<Coin>,
        master_address: Option<String>,
        mito_treasury_address: Option<String>,
        mito_treasury_fee_basis_points: Option<u16>,
        default_staked_to_subscription: Option<BTreeMap<Uint128, Uint128>>,
        launchpads_quote_denom: Option<String>,
        quote_decimals: Option<u8>,
    },
    DeployLaunchpad {
        project_owner: String,
        project_token_denom: String,
        hard_cap: Option<Uint128>,
        use_whitelist: bool,
        target_usd_subscription_incl_vault: FPDecimal,
        quote_price_set_once_before_start_in_seconds: u64,
        quote_pyth_pricefeed_id: String,
        oracle_stale_time: u64,
        vesting_config: Option<FactoryVestingConfig>,
        amm_launch_config: Option<AmmLaunchConfig>,
        staked_to_subscription_override: Option<BTreeMap<Uint128, Uint128>>,
    },
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub enum Schedule {
    /// Vests linearly from `0` to `total`.
    SaturatingLinear,
    /// Vests by linearly interpolating between the provided
    /// (seconds, amount) points. The first amount must be zero and
    /// the last amount the total vesting amount. `seconds` are
    /// seconds since the vest start time.
    ///
    /// There is a problem in the underlying Curve library that
    /// doesn't allow zero start values, so the first value of
    /// `seconds` must be > 1. To start at a particular time (if you
    /// need that level of precision), subtract one from the true
    /// start time, and make the first `seconds` value `1`.
    ///
    /// <https://github.com/cosmorama/wynddao/pull/4>
    PiecewiseLinear(Vec<(u64, Uint128)>),
}

impl Schedule {
    /// The vesting schedule tracks vested(t), so for a curve to be
    /// valid:
    ///
    /// 1. it must start at 0,
    /// 2. it must end at total,
    /// 3. it must never decrease.
    ///
    /// Piecewise curves must have at least two steps. One step would
    /// be a constant vest (why would you want this?).
    ///
    /// A schedule is valid if `total` is zero: nothing will ever be
    /// paid out. Consumers should consider validating that `total` is
    /// non-zero.
    pub fn into_curve(self, total: Uint128, duration_seconds: u64) -> Result<Curve, ContractError> {
        let c = match self {
            Schedule::SaturatingLinear => Curve::saturating_linear((0, 0), (duration_seconds, total.u128())),
            Schedule::PiecewiseLinear(steps) => {
                if steps.len() < 2 {
                    return Err(ContractError::ConstantVest);
                }
                Curve::PiecewiseLinear(wynd_utils::PiecewiseLinear { steps })
            }
        };
        c.validate_monotonic_increasing()?; // => max >= curve(t) \forall t
        let range = c.range();
        if range != (0, total.u128()) {
            return Err(ContractError::VestRange {
                min: Uint128::new(range.0),
                max: Uint128::new(range.1),
            });
        }
        Ok(c)
    }
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub enum RelativeSchedule {
    /// Vests linearly from `0` to `total`.
    SaturatingLinear,
    /// Vests by linearly interpolating between the provided
    /// (seconds, relative_amount_bps) points. The first relative amount must be zero and
    /// the last amount must be 10,000. `seconds` are
    /// seconds since the vest start time.
    ///
    /// There is a problem in the underlying Curve library that
    /// doesn't allow zero start values, so the first value of
    /// `seconds` must be > 1. To start at a particular time (if you
    /// need that level of precision), subtract one from the true
    /// start time, and make the first `seconds` value `1`.
    ///
    /// <https://github.com/cosmorama/wynddao/pull/4>
    PiecewiseLinear(Vec<(u64, u16)>),
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct VestingPlan {
    pub vesting_duration_seconds: u64,
    pub schedule: RelativeSchedule,
    pub vesting_start_delay_seconds: u64,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct FactoryVestingConfig {
    pub project_owner_quote: Option<VestingPlan>,
    pub project_owner_lp_tokens: Option<VestingPlan>,
    pub users_project_token: Option<VestingPlan>,
}

impl FactoryVestingConfig {
    pub fn into_vesting_config(self, vesting_code_id: u64) -> VestingConfig {
        VestingConfig {
            project_owner_quote: self.project_owner_quote,
            project_owner_lp_tokens: self.project_owner_lp_tokens,
            users_project_token: self.users_project_token,
            code_id: vesting_code_id,
        }
    }
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct VestingConfig {
    pub project_owner_quote: Option<VestingPlan>,
    pub project_owner_lp_tokens: Option<VestingPlan>,
    pub users_project_token: Option<VestingPlan>,
    pub code_id: u64,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct InstantiateMsg {
    pub project_owner: String,
    pub project_token_denom: String,
    pub quote_denom: String,
    pub hard_cap: Option<Uint128>,
    pub amm_launch_config: Option<AmmLaunchConfig>,
    pub vesting_config: Option<VestingConfig>,
    pub use_whitelist: bool,
    pub staked_to_subscription: BTreeMap<Uint128, Uint128>,
    pub mito_treasury_address: String,
    pub master_address: String,
    pub target_usd_subscription_incl_vault: FPDecimal,
    pub quote_price_set_once_before_start_in_seconds: u64,
    pub quote_pyth_pricefeed_id: String,
    pub oracle_stale_time: u64,
    pub quote_decimals: u8,
    pub mito_treasury_fee_basis_points: u16,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct MultipliedAddress {
    pub address: String,
    pub weight: FPDecimal,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub enum ExecuteMsg {
    UpdateOwner {
        new_owner: String,
    },
    AddAddressesToWhitelist {
        addresses: Vec<MultipliedAddress>,
    },
    RemoveAddressesFromWhitelist {
        addresses: Vec<String>,
        should_revoke_subscription: bool,
    },
    StartIdo {
        start_timestamp: Timestamp,
        end_timestamp: Timestamp,
    },
    CancelIdo {},
    SetQuotePrice {},
    Subscribe {},
    Finalize {},
    Claim {},
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct MigrateMsg {}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct FactoryMigrateMsg {}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub enum FactoryQueryMsg {
    Config {},
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub enum LaunchpadQueryMsg {
    Config {},
    StakedAmount { address: String, max_delegations: u16 },
    MaxSubscriptionAmount { address: String },
    CurrentSubscriptionAmount { address: String },
    TotalSubscriptionAmount {},
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct IdoTimestamps {
    pub start: Timestamp,
    pub end: Timestamp,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct LaunchpadConfigResponse {
    pub project_owner: String,
    pub ido_timestamps: Option<IdoTimestamps>,
    pub hard_cap: Option<Uint128>,
    pub use_whitelist: bool,
    pub amm_launch_config: Option<AmmLaunchConfig>,
    pub vesting_config: Option<VestingConfig>,
    pub mito_treasury_address: String,
    pub master_address: String,
    pub target_usd_subscription_incl_vault: FPDecimal,
    pub staked_to_subscription: BTreeMap<Uint128, Uint128>,
    pub quote_price_set_once_before_start_in_seconds: u64,
    pub quote_pyth_pricefeed_id: String,
    pub quote_decimals: u8,
    pub oracle_stale_time: u64,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct LaunchpadAmountResponse {
    pub amount: Uint128,
}