use std::fmt::{self, Debug};
use cosmwasm_std::{Addr, Coin, CosmosMsg, StdError, StdResult, SubMsg, Timestamp, Uint128};
use enumset::{EnumSet, EnumSetType};
use injective_cosmwasm::exchange::privileged_action::PositionTransferAction;
use injective_cosmwasm::{
Deposit, DerivativeOrder, EffectivePosition, InjectiveMsgWrapper, MarketId, OracleType, OracleVolatilityResponse, SpotOrder, SubaccountId,
TrimmedDerivativeLimitOrder, TrimmedSpotLimitOrder,
};
use injective_math::FPDecimal;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::master::RegistrationMode;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub enum InstantiateVaultMsg {
Amm(AmmInstantiateMsg),
Spot(SpotInstantiateMsg),
Derivative(DerivativeInstantiateMsg),
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub enum PricingStrategy {
ConstantPricingWithTickSize(FPDecimal), SmoothingPricingWithRelativePriceRange {
bid_range: FPDecimal, ask_range: FPDecimal, },
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub enum AmmOrderType {
PostOnly,
Vanilla,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct AmmInstantiateMsg {
pub config_owner: String,
pub market_id: MarketId,
pub master_address: String,
pub order_density: u8,
pub max_invariant_sensitivity_bps: FPDecimal,
pub max_price_sensitivity_bps: FPDecimal,
pub pricing_strategy: PricingStrategy,
pub base_decimals: u8,
pub quote_decimals: u8,
pub fee_bps: u32,
pub notional_value_cap: FPDecimal,
pub first_subscriber_address: Option<String>,
pub order_type: AmmOrderType,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct SpotInstantiateMsg {
pub config_owner: String,
pub market_id: MarketId,
pub order_density: u8,
pub reservation_price_sensitivity_ratio: FPDecimal,
pub reservation_spread_sensitivity_ratio: FPDecimal,
pub max_active_capital_utilization_ratio: FPDecimal,
pub head_change_tolerance_ratio: FPDecimal,
pub head_to_tail_deviation_ratio: FPDecimal,
pub min_volatility_ratio: FPDecimal,
pub signed_min_head_to_fair_price_deviation_ratio: FPDecimal,
pub signed_min_head_to_tob_deviation_ratio: FPDecimal,
pub target_base_weight: FPDecimal,
pub min_oracle_volatility_sample_size: u32,
pub emergency_oracle_volatility_sample_size: u32,
pub oracle_volatility_max_age: u64,
pub default_mid_price_volatility_ratio: FPDecimal,
pub oracle_type: OracleType,
pub allowed_redemption_types: EnumSet<SpotRedemptionType>,
pub base_decimals: u8,
pub quote_decimals: u8,
pub base_oracle_symbol: String,
pub quote_oracle_symbol: String,
pub notional_value_cap: FPDecimal,
pub oracle_stale_time: u64,
pub master_address: String,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct DerivativeInstantiateMsg {
pub config_owner: String,
pub market_id: MarketId,
pub leverage: FPDecimal,
pub order_density: u8,
pub signed_min_head_to_fair_price_deviation_ratio: FPDecimal,
pub signed_min_head_to_tob_deviation_ratio: FPDecimal,
pub reservation_price_sensitivity_ratio: FPDecimal,
pub reservation_spread_sensitivity_ratio: FPDecimal,
pub max_active_capital_utilization_ratio: FPDecimal,
pub head_change_tolerance_ratio: FPDecimal,
pub head_to_tail_deviation_ratio: FPDecimal,
pub min_proximity_to_liquidation: FPDecimal,
pub min_oracle_volatility_sample_size: u32,
pub emergency_oracle_volatility_sample_size: u32,
pub oracle_volatility_max_age: u64,
pub default_mid_price_volatility_ratio: FPDecimal,
pub min_volatility_ratio: FPDecimal,
pub allowed_redemption_types: EnumSet<DerivativeRedemptionType>,
pub position_pnl_penalty: FPDecimal,
pub notional_value_cap: FPDecimal,
pub oracle_stale_time: u64,
pub master_address: String,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub enum OffchainVaultType {
Spot {
oracle_type: OracleType,
base_oracle_symbol: String,
quote_oracle_symbol: String,
base_decimals: u8,
quote_decimals: u8,
},
Derivative {
position_pnl_penalty: FPDecimal,
},
}
impl EventStringAttribute for OffchainVaultType {
fn to_event_string_attr(&self) -> String {
match self {
Self::Spot {
oracle_type,
base_oracle_symbol,
quote_oracle_symbol,
base_decimals,
quote_decimals,
} => format!(
"Spot {{ oracle_type: {}, base_oracle_symbol: {}, quote_oracle_symbol: {}, base_decimals: {}, quote_decimals: {} }}",
oracle_type.to_event_string_attr(),
base_oracle_symbol,
quote_oracle_symbol,
base_decimals,
quote_decimals
),
Self::Derivative { position_pnl_penalty } => format!("Derivative {{ position_pnl_penalty: {} }}", position_pnl_penalty,),
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct OffchainInstantiateMsg {
pub admin: String,
pub vault_type: OffchainVaultType,
pub market_id: MarketId,
pub oracle_stale_time: u64,
pub pending_redemption_timeout: u64,
pub notional_value_cap: FPDecimal,
pub inj_reward_commission_bps: u16,
pub withdrawal_admin_fee_bps: u16,
pub derivative_max_position_pnl_penalty: Option<FPDecimal>,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum OffchainExecuteMsg {
AdminExecuteMessage {
injective_message: Box<CosmosMsg<InjectiveMsgWrapper>>,
},
TransferAdminOwnership {
new_admin: String,
},
UpdateVaultConfig {
vault_type: Option<OffchainVaultType>,
oracle_stale_time: Option<u64>,
notional_value_cap: Option<FPDecimal>,
},
DistributeAvailableInjRewards {},
SubscribeToVault {},
QueueRedemption {},
TriggerRedemption {
redeemer: Addr,
},
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct OffchainConfigResponse {
pub admin: String,
pub vault_type: OffchainVaultType,
pub market_id: String,
pub vault_subaccount_id: String,
pub oracle_stale_time: String,
pub notional_value_cap: String,
pub inj_reward_commission_bps: String,
pub withdrawal_admin_fee_bps: String,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum OffchainQueryMsg {
Config {},
PendingRedemption { user_address: String },
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum SudoMsg {
BeginBlocker {},
Deregister {},
Deactivate {},
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct InstantSubscription {
pub total_funds_supplied: Vec<Coin>,
pub trader_address: Addr,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum BaseVaultExecuteMsg<T> {
RegisterForMaster {
master_vault_subaccount_id: SubaccountId,
instant_subscription_option: Option<InstantSubscription>,
},
TransferOwnership {
new_owner: String,
},
ForwardedMasterMessage(MasterMessage<T>),
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct BaseVaultMessageWrapper<T> {
pub base: BaseVaultExecuteMsg<T>,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct MasterMessage<T> {
pub lp_tokens: Option<Uint128>,
pub total_funds_supplied: Vec<Coin>,
pub trader_subaccount_id: SubaccountId,
pub msg: T,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum SpotRedeemSubscribeMsg {
Subscribe {},
Redeem { redemption_type: SpotRedemptionType },
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum AmmRedeemSubscribeMsg {
Subscribe { slippage: Slippage },
Redeem { redemption_type: SpotRedemptionType },
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
#[allow(clippy::large_enum_variant)]
pub enum AmmExecuteMsg {
Base(BaseVaultExecuteMsg<AmmRedeemSubscribeMsg>),
UpdateVaultConfig {
order_density: Option<u8>,
max_invariant_sensitivity_bps: Option<FPDecimal>,
max_price_sensitivity_bps: Option<FPDecimal>,
pricing_strategy: Option<PricingStrategy>,
notional_value_cap: Option<FPDecimal>,
fee_bps: Option<u32>,
order_type: Option<AmmOrderType>,
},
MarketMake {},
EmergencyPause {},
EmergencyUnpause {
is_instant_market_making: bool,
},
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
#[allow(clippy::large_enum_variant)]
pub enum SpotExecuteMsg {
Base(BaseVaultExecuteMsg<SpotRedeemSubscribeMsg>),
UpdateVaultConfig {
market_id: Option<MarketId>,
order_density: Option<u8>,
reservation_price_sensitivity_ratio: Option<FPDecimal>,
reservation_spread_sensitivity_ratio: Option<FPDecimal>,
max_active_capital_utilization_ratio: Option<FPDecimal>,
head_change_tolerance_ratio: Option<FPDecimal>,
head_to_tail_deviation_ratio: Option<FPDecimal>,
signed_min_head_to_fair_price_deviation_ratio: Option<FPDecimal>,
signed_min_head_to_tob_deviation_ratio: Option<FPDecimal>,
target_base_weight: Option<FPDecimal>,
oracle_type: Option<OracleType>,
default_mid_price_volatility_ratio: Option<FPDecimal>,
allowed_redemption_types: Option<EnumSet<SpotRedemptionType>>,
notional_value_cap: Option<FPDecimal>,
oracle_stale_time: Option<u64>,
last_valid_mark_price: Option<FPDecimal>,
min_oracle_volatility_sample_size: Option<u32>,
emergency_oracle_volatility_sample_size: Option<u32>,
min_volatility_ratio: Option<FPDecimal>,
oracle_volatility_max_age: Option<u64>,
base_oracle_symbol: Option<String>,
quote_oracle_symbol: Option<String>,
},
MarketMake {},
EmergencyPause {},
EmergencyUnpause {
is_instant_market_making: bool,
},
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum DerivativeRedeemSubscribeMsg {
Subscribe {
slippage: Slippage,
},
Redeem {
redemption_type: DerivativeRedemptionType,
slippage: Option<Slippage>,
},
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
#[allow(clippy::large_enum_variant)]
pub enum DerivativeExecuteMsg {
Base(BaseVaultExecuteMsg<DerivativeRedeemSubscribeMsg>),
UpdateVaultConfig {
market_id: Option<MarketId>,
leverage: Option<FPDecimal>,
order_density: Option<u8>,
signed_min_head_to_fair_price_deviation_ratio: Option<FPDecimal>,
signed_min_head_to_tob_deviation_ratio: Option<FPDecimal>,
reservation_price_sensitivity_ratio: Option<FPDecimal>,
reservation_spread_sensitivity_ratio: Option<FPDecimal>,
max_active_capital_utilization_ratio: Option<FPDecimal>,
head_change_tolerance_ratio: Option<FPDecimal>,
head_to_tail_deviation_ratio: Option<FPDecimal>,
min_proximity_to_liquidation: Option<FPDecimal>,
min_oracle_volatility_sample_size: Option<u32>,
emergency_oracle_volatility_sample_size: Option<u32>,
default_mid_price_volatility_ratio: Option<FPDecimal>,
min_volatility_ratio: Option<FPDecimal>,
last_valid_mark_price: Option<FPDecimal>,
allowed_redemption_types: Option<EnumSet<DerivativeRedemptionType>>,
notional_value_cap: Option<FPDecimal>,
oracle_stale_time: Option<u64>,
oracle_volatility_max_age: Option<u64>,
},
BeginBlockerWithoutLiquidationCheck {},
MarketMake {},
EmergencyPause {},
EmergencyUnpause {
is_instant_market_making: bool,
},
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum CommonVaultQueryMsg {
GetTotalLpSupply {},
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum BaseVaultQueryMsg {
Config {},
GetMarketId {},
GetTotalLpSupply {},
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum DerivativeQueryMsg {
Base(BaseVaultQueryMsg),
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum SpotQueryMsg {
Base(BaseVaultQueryMsg),
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum Slippage {
MaxPenalty(FPDecimal),
}
impl Slippage {
pub fn validate(&self) -> StdResult<()> {
match self {
Slippage::MaxPenalty(value) => {
if *value < FPDecimal::ZERO || *value > FPDecimal::ONE {
Err(StdError::generic_err(format!("Slippage must be between 0 and 1, got {value}")))
} else {
Ok(())
}
}
}
}
}
impl Default for Slippage {
fn default() -> Self {
Slippage::MaxPenalty(FPDecimal::ZERO)
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct Vault {
pub address: Addr,
pub master_subaccount_id: SubaccountId,
}
impl Vault {
pub fn address(&self) -> &Addr {
&self.address
}
pub fn master_subaccount_id(&self) -> &SubaccountId {
&self.master_subaccount_id
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct TokensToMint {
pub master: Option<Uint128>,
pub trader: Option<Uint128>,
}
impl TokensToMint {
pub fn is_empty(&self) -> bool {
self.trader.unwrap_or_default().is_zero() && self.master.unwrap_or_default().is_zero()
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct ForwardedActionResponse {
pub tokens_to_mint: Option<TokensToMint>,
pub tokens_to_burn: Option<Uint128>,
pub privileged_position_transfer: Option<PositionTransferAction>,
pub messages: Vec<CosmosMsg<InjectiveMsgWrapper>>,
pub submessages: Vec<SubMsg<InjectiveMsgWrapper>>,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct MarketIdResponse {
pub market_id: MarketId,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct TotalSupplyResponse {
pub total_supply: Uint128,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct RequestRedemptionDataResponse {
pub unlocks_at: Option<Timestamp>,
pub min_expires_at: Option<Timestamp>,
}
#[derive(Serialize, Deserialize, Debug, JsonSchema, EnumSetType)]
pub enum VaultType {
Amm,
SpotAsmm,
DerivativeAsmm,
SpotOffchain,
DerivativeOffchain,
}
impl VaultType {
pub fn is_spot(self) -> bool {
matches!(self, VaultType::SpotAsmm | VaultType::SpotOffchain | VaultType::Amm)
}
pub fn is_derivative(self) -> bool {
matches!(self, VaultType::DerivativeAsmm | VaultType::DerivativeOffchain)
}
}
#[derive(Serialize, Deserialize, Debug, JsonSchema, EnumSetType)]
pub enum SpotRedemptionType {
FixedBaseAndQuote,
}
#[derive(Serialize, Deserialize, Debug, JsonSchema, EnumSetType)]
pub enum DerivativeRedemptionType {
QuoteOnly,
PositionAndQuote,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub enum RedemptionType {
SpotRedemptionType(SpotRedemptionType),
DerivativeRedemptionType(DerivativeRedemptionType),
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct MigrateMsg {}
pub trait EventStringAttribute {
fn to_event_string_attr(&self) -> String;
}
impl EventStringAttribute for String {
fn to_event_string_attr(&self) -> String {
self.as_str().to_string()
}
}
impl EventStringAttribute for Addr {
fn to_event_string_attr(&self) -> String {
self.as_str().to_string()
}
}
impl EventStringAttribute for Vec<Coin> {
fn to_event_string_attr(&self) -> String {
"[".to_owned() + &self.iter().map(|coin| coin.to_string()).collect::<Vec<String>>().join(",") + "]"
}
}
impl EventStringAttribute for MarketId {
fn to_event_string_attr(&self) -> String {
self.as_str().to_string()
}
}
impl EventStringAttribute for bool {
fn to_event_string_attr(&self) -> String {
self.to_string()
}
}
impl EventStringAttribute for FPDecimal {
fn to_event_string_attr(&self) -> String {
self.to_string()
}
}
impl EventStringAttribute for RegistrationMode {
fn to_event_string_attr(&self) -> String {
match self {
RegistrationMode::Permissionless(_) => "Permissionless".to_string(),
RegistrationMode::Restricted(_) => "Restricted".to_string(),
}
}
}
impl EventStringAttribute for AmmOrderType {
fn to_event_string_attr(&self) -> String {
match self {
AmmOrderType::PostOnly => "PostOnly".to_string(),
AmmOrderType::Vanilla => "Vanilla".to_string(),
}
}
}
impl EventStringAttribute for PricingStrategy {
fn to_event_string_attr(&self) -> String {
match self {
PricingStrategy::ConstantPricingWithTickSize(price_tick_size) => format!("ConstantPricingWithTickSize({})", price_tick_size),
PricingStrategy::SmoothingPricingWithRelativePriceRange { bid_range, ask_range } => {
format!("SmoothingPricingWithRelativePriceRange({},{})", bid_range, ask_range)
}
}
}
}
impl EventStringAttribute for Uint128 {
fn to_event_string_attr(&self) -> String {
self.to_string()
}
}
impl EventStringAttribute for u8 {
fn to_event_string_attr(&self) -> String {
format!("{self}")
}
}
impl EventStringAttribute for u32 {
fn to_event_string_attr(&self) -> String {
format!("{self}")
}
}
impl EventStringAttribute for u64 {
fn to_event_string_attr(&self) -> String {
format!("{self}")
}
}
impl EventStringAttribute for EnumSet<SpotRedemptionType> {
fn to_event_string_attr(&self) -> String {
let mut values: Vec<String> = vec![];
self.into_iter().for_each(|value| values.push((value as i32).to_string()));
values.join(",")
}
}
impl EventStringAttribute for EnumSet<DerivativeRedemptionType> {
fn to_event_string_attr(&self) -> String {
let mut values: Vec<String> = vec![];
self.into_iter().for_each(|value| values.push((value as i32).to_string()));
values.join(",")
}
}
impl EventStringAttribute for OracleType {
fn to_event_string_attr(&self) -> String {
(*self as i32).to_string()
}
}
pub const EVENT_LP_BALANCE_CHANGED: &str = "lp_balance_changed";
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct DerivativeExecutionVaultResponse {
pub fair_price: Option<FPDecimal>,
pub mm_logic_response: Option<DerivativeMmLogicResponse>,
pub tob_buy_price: Option<FPDecimal>,
pub tob_sell_price: Option<FPDecimal>,
pub open_orders: Vec<TrimmedDerivativeLimitOrder>,
pub deposit: Deposit,
pub position: Option<EffectivePosition>,
pub oracle_volatility: Option<OracleVolatilityResponse>,
pub final_volatility: Option<FPDecimal>,
pub should_check_close_to_liquidation: bool,
pub oracle_data: OracleData,
pub buy_orders_to_open: Vec<DerivativeOrder>,
pub sell_orders_to_open: Vec<DerivativeOrder>,
pub new_buy_tail: Option<FPDecimal>,
pub new_sell_tail: Option<FPDecimal>,
pub adjusted_head_prices: Option<AdjustedHeadPrices>,
}
impl fmt::Display for DerivativeExecutionVaultResponse {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"DerivativeExecutionVaultResponse {{\n\
\tfair_price: {},\n\
\tmm_logic_response: {},\n\
\tposition: {},\n\
\ttob_buy_price: {},\n\
\ttob_sell_price: {},\n\
\tfinal_volatility: {},\n\
\toracle_data: {},\n\
\tnew_buy_tail: {},\n\
\tnew_sell_tail: {}\n\
}}",
self.fair_price.as_ref().map(|fp| fp.to_string()).unwrap_or_else(|| "None".to_string()),
self.mm_logic_response
.as_ref()
.map(|l| l.to_string())
.unwrap_or_else(|| "None".to_string()),
self.position.as_ref().map(|p| format!("{:?}", p)).unwrap_or_else(|| "None".to_string()),
self.tob_buy_price.as_ref().map(|fp| fp.to_string()).unwrap_or_else(|| "None".to_string()),
self.tob_sell_price
.as_ref()
.map(|fp| fp.to_string())
.unwrap_or_else(|| "None".to_string()),
self.final_volatility
.as_ref()
.map(|fp| fp.to_string())
.unwrap_or_else(|| "None".to_string()),
self.oracle_data,
self.new_buy_tail.as_ref().map(|fp| fp.to_string()).unwrap_or_else(|| "None".to_string()),
self.new_sell_tail.as_ref().map(|fp| fp.to_string()).unwrap_or_else(|| "None".to_string())
)
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct AdjustedHeadPrices {
pub dist_from_reservation_price: FPDecimal,
pub proposed_buy_head: FPDecimal,
pub proposed_sell_head: FPDecimal,
pub after_fair_price_adjustment_buy_head: FPDecimal,
pub after_fair_price_adjustment_sell_head: FPDecimal,
pub after_tob_adjustment_buy_head: FPDecimal,
pub after_tob_adjustment_sell_head: FPDecimal,
pub final_after_self_match_adjustment_buy_head: FPDecimal,
pub final_after_self_match_adjustment_sell_head: FPDecimal,
}
impl fmt::Display for AdjustedHeadPrices {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"AdjustedHeadPrices {{\n\
\t dist_from_reservation_price: {},\n\
\t proposed_buy_head: {},\n\
\t proposed_sell_head: {},\n\
\t after_fair_price_adjustment_buy_head: {},\n\
\t after_fair_price_adjustment_sell_head: {},\n\
\t after_tob_adjustment_buy_head: {},\n\
\t after_tob_adjustment_sell_head: {},\n\
\t final_after_self_match_adjustment_buy_head: {}\n\
\t final_after_self_match_adjustment_sell_head: {}\n\
\t}}\
",
self.dist_from_reservation_price,
self.proposed_buy_head,
self.proposed_sell_head,
self.after_fair_price_adjustment_buy_head,
self.after_fair_price_adjustment_sell_head,
self.after_tob_adjustment_buy_head,
self.after_tob_adjustment_sell_head,
self.final_after_self_match_adjustment_buy_head,
self.final_after_self_match_adjustment_sell_head,
)
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct OracleData {
pub has_invalid_oracle_value: Option<bool>,
pub has_oracle_volatility_insufficient_samples: Option<bool>,
pub last_valid_mark_price: FPDecimal,
pub mark_price: Option<FPDecimal>,
}
impl fmt::Display for OracleData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"OracleData {{\n\
\t has_invalid_oracle_value: {},\n\
\t has_oracle_volatility_insufficient_samples: {},\n\
\t last_valid_mark_price: {},\n\
\t mark_price: {}\n\
\t}}\
",
self.has_invalid_oracle_value
.as_ref()
.map(|i| i.to_string())
.unwrap_or_else(|| "None".to_string()),
self.has_oracle_volatility_insufficient_samples
.as_ref()
.map(|i| i.to_string())
.unwrap_or_else(|| "None".to_string()),
self.last_valid_mark_price,
self.mark_price.as_ref().map(|fp| fp.to_string()).unwrap_or_else(|| "None".to_string())
)
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct SpotExecutionVaultResponse {
pub fair_price: Option<FPDecimal>,
pub mm_logic_response: Option<SpotMmLogicResponse>,
pub tob_buy_price: Option<FPDecimal>,
pub tob_sell_price: Option<FPDecimal>,
pub open_orders: Vec<TrimmedSpotLimitOrder>,
pub base_deposit: Deposit,
pub quote_deposit: Deposit,
pub oracle_volatility: Option<OracleVolatilityResponse>,
pub final_volatility: Option<FPDecimal>,
pub oracle_data: OracleData,
pub buy_orders_to_open: Vec<SpotOrder>,
pub sell_orders_to_open: Vec<SpotOrder>,
pub new_buy_tail: Option<FPDecimal>,
pub new_sell_tail: Option<FPDecimal>,
pub adjusted_head_prices: Option<AdjustedHeadPrices>,
}
impl fmt::Display for SpotExecutionVaultResponse {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"SpotExecutionVaultResponse {{\n\
\tfair_price: {},\n\
\tmm_logic_response: {},\n\
\ttob_buy_price: {},\n\
\ttob_sell_price: {},\n\
\tfinal_volatility: {},\n\
\toracle_data: {},\n\
\tnew_buy_tail: {},\n\
\tnew_sell_tail: {}\n\
\tadjusted_head_prices: {}\n\
\t}\
}\
",
self.fair_price.as_ref().map(|fp| fp.to_string()).unwrap_or_else(|| "None".to_string()),
self.mm_logic_response
.as_ref()
.map(|l| l.to_string())
.unwrap_or_else(|| "None".to_string()),
self.tob_buy_price.as_ref().map(|fp| fp.to_string()).unwrap_or_else(|| "None".to_string()),
self.tob_sell_price
.as_ref()
.map(|fp| fp.to_string())
.unwrap_or_else(|| "None".to_string()),
self.final_volatility
.as_ref()
.map(|fp| fp.to_string())
.unwrap_or_else(|| "None".to_string()),
self.oracle_data,
self.new_buy_tail.as_ref().map(|fp| fp.to_string()).unwrap_or_else(|| "None".to_string()),
self.new_sell_tail.as_ref().map(|fp| fp.to_string()).unwrap_or_else(|| "None".to_string()),
self.adjusted_head_prices
.as_ref()
.map(|fp| fp.to_string())
.unwrap_or_else(|| "None".to_string())
)
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct SpotMmLogicResponse {
pub inventory_balance_data: InventoryBalanceData,
pub reservation_price: FPDecimal,
pub old_buy_head: Option<FPDecimal>,
pub new_buy_head: FPDecimal,
pub old_sell_head: Option<FPDecimal>,
pub new_sell_head: FPDecimal,
pub should_take_action: bool,
}
impl fmt::Display for SpotMmLogicResponse {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"SpotMmLogicResponse {{\n\
\t inventory_balance_data: {},\n\
\t reservation_price: {},\n\
\t old_buy_head: {},\n\
\t new_buy_head: {},\n\
\t old_sell_head: {},\n\
\t new_sell_head: {},\n\
\t should_take_action: {}\n\
\t}}\
",
self.inventory_balance_data,
self.reservation_price,
self.old_buy_head.as_ref().map(|fp| fp.to_string()).unwrap_or_else(|| "None".to_string()),
self.new_buy_head,
self.old_sell_head.as_ref().map(|fp| fp.to_string()).unwrap_or_else(|| "None".to_string()),
self.new_sell_head,
self.should_take_action
)
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct DerivativeMmLogicResponse {
pub inventory_imbalance_ratio: FPDecimal,
pub reservation_price: FPDecimal,
pub old_buy_head: Option<FPDecimal>,
pub new_buy_head: FPDecimal,
pub old_sell_head: Option<FPDecimal>,
pub new_sell_head: FPDecimal,
pub should_take_action: bool,
}
impl fmt::Display for DerivativeMmLogicResponse {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"DerivativeMmLogicResponse {{\n\
\t inventory_imbalance_ratio: {},\n\
\t reservation_price: {},\n\
\t old_buy_head: {},\n\
\t new_buy_head: {},\n\
\t old_sell_head: {},\n\
\t new_sell_head: {},\n\
\t should_take_action: {}\n\
\t}}\
",
self.inventory_imbalance_ratio,
self.reservation_price,
self.old_buy_head.as_ref().map(|fp| fp.to_string()).unwrap_or_else(|| "None".to_string()),
self.new_buy_head,
self.old_sell_head.as_ref().map(|fp| fp.to_string()).unwrap_or_else(|| "None".to_string()),
self.new_sell_head,
self.should_take_action
)
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct InventoryBalanceData {
pub imbalance_ratio: FPDecimal,
pub base_notional: FPDecimal,
pub quote_notional: FPDecimal,
pub total_notional: FPDecimal,
pub notional_difference: FPDecimal,
pub fair_price: FPDecimal,
}
impl fmt::Display for InventoryBalanceData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"InventoryBalanceData {{\n\
\t imbalance_ratio: {},\n\
\t base_notional: {},\n\
\t quote_notional: {},\n\
\t total_notional: {},\n\
\t notional_difference: {},\n\
\t fair_price: {}\n\
\t }}\
",
self.imbalance_ratio, self.base_notional, self.quote_notional, self.total_notional, self.notional_difference, self.fair_price
)
}
}