mito-protocol 0.2.7-fixed-docs

A package for interacting with the Mito Protocol
Documentation
use std::str::FromStr;

use cosmwasm_std::{to_json_binary, Binary, Reply, SubMsgResponse, SubMsgResult};
use enumset::enum_set;
use injective_cosmwasm::{MarketId, OracleType};
use injective_math::FPDecimal;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use crate::vault::{
    AmmInstantiateMsg, AmmOrderType, DerivativeInstantiateMsg, DerivativeRedemptionType, PricingStrategy, SpotInstantiateMsg, SpotRedemptionType,
};

pub const MOCKED_OWNER: &str = "owner";
pub const MOCKED_OWNER_VALID: &str = "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku";
pub const MOCKED_MASTER_ADDRESS: &str = "inj1gfawuv6fslzjlfa4v7exv27mk6rpfeyv823eu2";
pub const MOCKED_MARKET_ID: &str = "0x01edfab47f124748dc89998eb33144af734484ba07099014594321729a0ca16b";
pub const MOCKED_DERIV_MARKET_ID: &str = "0x427aee334987c52fa7b567b2662bdbb68614e48c000000000000000000000000";
pub const MOCKED_USER: &str = "inj1995xnrrtnmtdgjmx0g937vf28dwefhkhy6gy5e";

pub fn mock_cpmm_instantiate_msg(owner: String, master_address: String, market_id: String) -> AmmInstantiateMsg {
    AmmInstantiateMsg {
        config_owner: owner.to_owned(),
        market_id: MarketId::new(market_id).unwrap(),
        master_address,
        order_density: 10u8,
        max_invariant_sensitivity_bps: FPDecimal::from_str("0.1").unwrap(),
        max_price_sensitivity_bps: FPDecimal::from_str("0.1").unwrap(),
        pricing_strategy: PricingStrategy::ConstantPricingWithTickSize(FPDecimal::must_from_str("0.00000000000001")),
        base_decimals: 18u8,
        quote_decimals: 6u8,
        fee_bps: 0u32,
        notional_value_cap: FPDecimal::from(100_000_000_000_000_000_000u128),
        first_subscriber_address: None,
        order_type: AmmOrderType::PostOnly,
    }
}

pub fn mock_scpmm_instantiate_msg(owner: String, master_address: String, market_id: String) -> AmmInstantiateMsg {
    AmmInstantiateMsg {
        config_owner: owner.to_owned(),
        market_id: MarketId::new(market_id).unwrap(),
        master_address,
        order_density: 10u8,
        max_invariant_sensitivity_bps: FPDecimal::from_str("0.1").unwrap(),
        max_price_sensitivity_bps: FPDecimal::from_str("0.1").unwrap(),
        pricing_strategy: PricingStrategy::SmoothingPricingWithRelativePriceRange {
            bid_range: FPDecimal::must_from_str("0.1"),
            ask_range: FPDecimal::must_from_str("0.1"),
        },
        base_decimals: 18u8,
        quote_decimals: 6u8,
        notional_value_cap: FPDecimal::from(100_000_000_000_000_000_000u128),
        fee_bps: 30u32,
        first_subscriber_address: None,
        order_type: AmmOrderType::PostOnly,
    }
}

pub fn mock_spot_instantiate_msg(owner: String, master_address: String, market_id: String) -> SpotInstantiateMsg {
    SpotInstantiateMsg {
        market_id: MarketId::new(market_id).unwrap(),
        order_density: 8,
        reservation_price_sensitivity_ratio: FPDecimal::must_from_str("0.916"),
        reservation_spread_sensitivity_ratio: FPDecimal::ONE,
        max_active_capital_utilization_ratio: FPDecimal::ONE,
        head_change_tolerance_ratio: FPDecimal::ONE,
        head_to_tail_deviation_ratio: FPDecimal::must_from_str("0.05"),
        min_volatility_ratio: FPDecimal::must_from_str("0.002"),
        signed_min_head_to_fair_price_deviation_ratio: FPDecimal::must_from_str("0.01"),
        signed_min_head_to_tob_deviation_ratio: FPDecimal::must_from_str("-0.01"),
        default_mid_price_volatility_ratio: FPDecimal::must_from_str("0.005"),
        target_base_weight: FPDecimal::ONE,
        master_address,
        config_owner: owner.to_owned(),
        oracle_type: OracleType::PriceFeed,
        allowed_redemption_types: enum_set!(SpotRedemptionType::FixedBaseAndQuote),
        base_decimals: 18,
        quote_decimals: 6,
        base_oracle_symbol: "inj".to_string(),
        quote_oracle_symbol: "usdt".to_string(),
        notional_value_cap: FPDecimal::from(999_000_000_000_000_000_000_000_000u128),
        oracle_stale_time: 75,
        min_oracle_volatility_sample_size: 5,
        emergency_oracle_volatility_sample_size: 6,
        oracle_volatility_max_age: 100,
    }
}

pub fn mock_derivative_instantiate_msg(owner: String, master_address: String, market_id: String) -> DerivativeInstantiateMsg {
    DerivativeInstantiateMsg {
        market_id: MarketId::new(market_id).unwrap(),
        leverage: FPDecimal::TWO,
        order_density: 3,
        reservation_price_sensitivity_ratio: FPDecimal::must_from_str("0.1"),
        reservation_spread_sensitivity_ratio: FPDecimal::must_from_str("0.2"),
        max_active_capital_utilization_ratio: FPDecimal::must_from_str("0.8"),
        signed_min_head_to_fair_price_deviation_ratio: FPDecimal::must_from_str("0.1"),
        signed_min_head_to_tob_deviation_ratio: FPDecimal::must_from_str("0.1"),
        head_change_tolerance_ratio: FPDecimal::must_from_str("0.4"),
        min_proximity_to_liquidation: FPDecimal::must_from_str("1.4"),
        min_oracle_volatility_sample_size: 5,
        emergency_oracle_volatility_sample_size: 6,
        oracle_volatility_max_age: 100,
        default_mid_price_volatility_ratio: FPDecimal::must_from_str("0.88"),
        min_volatility_ratio: FPDecimal::must_from_str("0.001"),
        master_address,
        config_owner: owner.to_owned(),
        head_to_tail_deviation_ratio: FPDecimal::must_from_str("0.1"),
        allowed_redemption_types: enum_set!(DerivativeRedemptionType::QuoteOnly | DerivativeRedemptionType::PositionAndQuote),
        position_pnl_penalty: FPDecimal::must_from_str("0.01"),
        notional_value_cap: FPDecimal::from(999_000_000_000_000_000_000u128),
        oracle_stale_time: 60 * 60 * 6,
    }
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct MockedMsgInstantiateContractResponse {
    pub contract_address: String,
    pub data: Option<Binary>,
}

fn encode_bytes(data: Vec<u8>) -> Vec<u8> {
    let mut encoded_data = Vec::new();

    // Field number (1) shifted left by 3 and OR-ed with wire type (2 for length-delimited)
    let field_tag: u8 = (1 << 3) | 2;
    encoded_data.push(field_tag);

    // Length of the data as a varint
    let mut len = data.len();
    while len >= 0x80 {
        encoded_data.push((len as u8) | 0x80);
        len >>= 7;
    }
    encoded_data.push(len as u8);

    // Data itself
    encoded_data.extend(data);

    encoded_data
}

pub fn wrap_as_contract_reply(mut bin_vec: Vec<u8>, reply_id: u64) -> Reply {
    bin_vec = encode_bytes(bin_vec);
    let as_binary = Binary::from(bin_vec);

    Reply {
        id: reply_id,
        result: SubMsgResult::Ok(SubMsgResponse {
            events: vec![],
            data: Some(as_binary),
        }),
    }
}

pub fn mock_instantiate_reply_msg(contract_addr: &str, reply_id: u64) -> Reply {
    let mut bin_vec = to_json_binary(&contract_addr.to_string()).unwrap().as_slice().to_vec();

    // remove encoded double quotes from beginning and end
    bin_vec.remove(0);
    bin_vec.pop();

    wrap_as_contract_reply(bin_vec, reply_id)
}