Perp: Allow setting pnl asset weights (#391)

This replaces the previous distinction between trusted and untrusted
markets, they are equivalent to setting the asset weights to 1 or 0
instead.

This way, we can weigh positive pnl in the trusted case at less than 1
which is more correct from a risk point of view and allows for more
flexibility when it comes to liquidation.

Co-authored-by: microwavedcola1 <microwavedcola@gmail.com>
This commit is contained in:
Christian Kamm 2023-01-16 16:49:09 +01:00 committed by GitHub
parent da1dfb2c3c
commit ec99376a8f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 593 additions and 456 deletions

View File

@ -436,8 +436,22 @@ mod tests {
let oo1key = oo1.pubkey;
oo1.data().native_pc_total = 20;
let mut perp1 = mock_perp_market(group, oracle2.pubkey, oracle2_price, 9, 0.2, 0.1);
let mut perp2 = mock_perp_market(group, oracle1.pubkey, oracle1_price, 8, 0.2, 0.1);
let mut perp1 = mock_perp_market(
group,
oracle2.pubkey,
oracle2_price,
9,
(0.2, 0.1),
(0.05, 0.02),
);
let mut perp2 = mock_perp_market(
group,
oracle1.pubkey,
oracle1_price,
8,
(0.2, 0.1),
(0.05, 0.02),
);
let oracle1_account_info = oracle1.as_account_info();
let oracle2_account_info = oracle2.as_account_info();

View File

@ -209,10 +209,12 @@ pub(crate) struct Serum3Reserved {
#[derive(Clone, AnchorDeserialize, AnchorSerialize, Debug)]
pub struct PerpInfo {
pub perp_market_index: PerpMarketIndex,
pub maint_asset_weight: I80F48,
pub init_asset_weight: I80F48,
pub maint_liab_weight: I80F48,
pub init_liab_weight: I80F48,
pub maint_base_asset_weight: I80F48,
pub init_base_asset_weight: I80F48,
pub maint_base_liab_weight: I80F48,
pub init_base_liab_weight: I80F48,
pub maint_pnl_asset_weight: I80F48,
pub init_pnl_asset_weight: I80F48,
pub base_lot_size: i64,
pub base_lots: i64,
pub bids_base_lots: i64,
@ -221,7 +223,6 @@ pub struct PerpInfo {
pub quote: I80F48,
pub prices: Prices,
pub has_open_orders: bool,
pub trusted_market: bool,
}
impl PerpInfo {
@ -237,10 +238,12 @@ impl PerpInfo {
Ok(Self {
perp_market_index: perp_market.perp_market_index,
init_asset_weight: perp_market.init_asset_weight,
init_liab_weight: perp_market.init_liab_weight,
maint_asset_weight: perp_market.maint_asset_weight,
maint_liab_weight: perp_market.maint_liab_weight,
init_base_asset_weight: perp_market.init_base_asset_weight,
init_base_liab_weight: perp_market.init_base_liab_weight,
maint_base_asset_weight: perp_market.maint_base_asset_weight,
maint_base_liab_weight: perp_market.maint_base_liab_weight,
init_pnl_asset_weight: perp_market.init_pnl_asset_weight,
maint_pnl_asset_weight: perp_market.maint_pnl_asset_weight,
base_lot_size: perp_market.base_lot_size,
base_lots,
bids_base_lots: perp_position.bids_base_lots,
@ -248,14 +251,15 @@ impl PerpInfo {
quote: quote_current,
prices,
has_open_orders: perp_position.has_open_orders(),
trusted_market: perp_market.trusted_market(),
})
}
/// Total health contribution from perp balances
///
/// Due to isolation of perp markets, users may never borrow against perp
/// positions in untrusted without settling first: perp health is capped at zero.
/// For fully isolated perp markets, users may never borrow against unsettled
/// positive perp pnl, there pnl_asset_weight == 0 and there can't be positive
/// health contributions from these perp market. We sometimes call these markets
/// "untrusted markets".
///
/// Users need to settle their perp pnl with other perp market participants
/// in order to realize their gains if they want to use them as collateral.
@ -264,32 +268,43 @@ impl PerpInfo {
/// zero (if users could borrow against their perp balances they might now
/// be bankrupt) or suddenly increase a lot (if users could borrow against perp
/// balances they could now borrow other assets).
///
/// Other markets may be liquid enough that we have enough confidence to allow
/// users to borrow against unsettled positive pnl to some extend. In these cases,
/// the pnl asset weights would be >0.
#[inline(always)]
pub fn health_contribution(&self, health_type: HealthType) -> I80F48 {
let c = self.uncapped_health_contribution(health_type);
let contribution = self.unweighted_health_contribution(health_type);
if self.trusted_market {
c
if contribution > 0 {
let asset_weight = match health_type {
HealthType::Init => self.init_pnl_asset_weight,
HealthType::Maint => self.maint_pnl_asset_weight,
};
cm!(asset_weight * contribution)
} else {
c.min(I80F48::ZERO)
contribution
}
}
#[inline(always)]
pub fn uncapped_health_contribution(&self, health_type: HealthType) -> I80F48 {
pub fn unweighted_health_contribution(&self, health_type: HealthType) -> I80F48 {
let order_execution_case = |orders_base_lots: i64, order_price: I80F48| {
let net_base_native =
I80F48::from(cm!((self.base_lots + orders_base_lots) * self.base_lot_size));
let (weight, base_price) = match (health_type, net_base_native.is_negative()) {
(HealthType::Init, true) => (self.init_liab_weight, self.prices.liab(health_type)),
(HealthType::Init, true) => {
(self.init_base_liab_weight, self.prices.liab(health_type))
}
(HealthType::Init, false) => {
(self.init_asset_weight, self.prices.asset(health_type))
(self.init_base_asset_weight, self.prices.asset(health_type))
}
(HealthType::Maint, true) => {
(self.maint_liab_weight, self.prices.liab(health_type))
(self.maint_base_liab_weight, self.prices.liab(health_type))
}
(HealthType::Maint, false) => {
(self.maint_asset_weight, self.prices.asset(health_type))
(self.maint_base_asset_weight, self.prices.asset(health_type))
}
};
// Total value of the order-execution adjusted base position
@ -437,10 +452,10 @@ impl HealthCache {
self.perp_infos.iter().any(|p| p.base_lots != 0)
}
pub fn has_perp_positive_trusted_pnl_without_base_position(&self) -> bool {
pub fn has_perp_positive_maint_pnl_without_base_position(&self) -> bool {
self.perp_infos
.iter()
.any(|p| p.trusted_market && p.base_lots == 0 && p.quote > 0)
.any(|p| p.maint_pnl_asset_weight > 0 && p.base_lots == 0 && p.quote > 0)
}
pub fn has_perp_negative_pnl(&self) -> bool {
@ -473,7 +488,7 @@ impl HealthCache {
pub fn has_phase2_liquidatable(&self) -> bool {
self.has_spot_assets() && self.has_spot_borrows()
|| self.has_perp_base_positions()
|| self.has_perp_positive_trusted_pnl_without_base_position()
|| self.has_perp_positive_maint_pnl_without_base_position()
}
pub fn require_after_phase2_liquidation(&self) -> Result<()> {
@ -487,7 +502,7 @@ impl HealthCache {
MangoError::HasLiquidatablePerpBasePosition
);
require!(
!self.has_perp_positive_trusted_pnl_without_base_position(),
!self.has_perp_positive_maint_pnl_without_base_position(),
MangoError::HasLiquidatableTrustedPerpPnl
);
Ok(())
@ -636,12 +651,8 @@ impl HealthCache {
}
for perp_info in self.perp_infos.iter() {
if perp_info.trusted_market {
let positive_contrib = perp_info
.uncapped_health_contribution(health_type)
.max(I80F48::ZERO);
cm!(health += positive_contrib);
}
let positive_contrib = perp_info.health_contribution(health_type).max(I80F48::ZERO);
cm!(health += positive_contrib);
}
health
}
@ -842,7 +853,7 @@ mod tests {
oo1.data().native_coin_free = 3;
oo1.data().referrer_rebates_accrued = 2;
let mut perp1 = mock_perp_market(group, oracle2.pubkey, 5.0, 9, 0.2, 0.1);
let mut perp1 = mock_perp_market(group, oracle2.pubkey, 5.0, 9, (0.2, 0.1), (0.05, 0.02));
let perpaccount = account.ensure_perp_position(9, 1).unwrap().0;
perpaccount.record_trade(perp1.data(), 3, -I80F48::from(310u16));
perpaccount.bids_base_lots = 7;
@ -966,7 +977,7 @@ mod tests {
oo2.data().native_pc_total = testcase.oo_1_3.0;
oo2.data().native_coin_total = testcase.oo_1_3.1;
let mut perp1 = mock_perp_market(group, oracle2.pubkey, 5.0, 9, 0.2, 0.1);
let mut perp1 = mock_perp_market(group, oracle2.pubkey, 5.0, 9, (0.2, 0.1), (0.05, 0.02));
let perpaccount = account.ensure_perp_position(9, 1).unwrap().0;
perpaccount.record_trade(
perp1.data(),
@ -1033,27 +1044,27 @@ mod tests {
..Default::default()
},
TestHealth1Case {
// 2
// 2: weighted positive perp pnl
perp1: (-1, 100, 0, 0),
expected_health: 0.0,
expected_health: 0.95 * (100.0 - 1.2 * 1.0 * base_lots_to_quote),
..Default::default()
},
TestHealth1Case {
// 3
// 3: negative perp pnl is not weighted
perp1: (1, -100, 0, 0),
expected_health: -100.0 + 0.8 * 1.0 * base_lots_to_quote,
..Default::default()
},
TestHealth1Case {
// 4
// 4: perp health
perp1: (10, 100, 0, 0),
expected_health: 0.0,
expected_health: 0.95 * (100.0 + 0.8 * 10.0 * base_lots_to_quote),
..Default::default()
},
TestHealth1Case {
// 5
// 5: perp health
perp1: (30, -100, 0, 0),
expected_health: 0.0,
expected_health: 0.95 * (-100.0 + 0.8 * 30.0 * base_lots_to_quote),
..Default::default()
},
TestHealth1Case { // 6, reserved oo funds

View File

@ -310,12 +310,13 @@ impl HealthCache {
let prices = &perp_info.prices;
let base_lot_size = I80F48::from(perp_info.base_lot_size);
// If the price is sufficiently good then health will just increase from trading
// TODO: This is not actually correct, since perp health for untrusted markets can't go above 0
// If the price is sufficiently good then health will just increase from trading.
// It's ok to ignore the pnl_asset_weight here because we'll jump out early if this
// slope is >=0, and the extra asset weight would just decrease it.
let final_health_slope = if direction == 1 {
perp_info.init_asset_weight * prices.asset(health_type) - price
perp_info.init_base_asset_weight * prices.asset(health_type) - price
} else {
price - perp_info.init_liab_weight * prices.liab(health_type)
price - perp_info.init_base_liab_weight * prices.liab(health_type)
};
if final_health_slope >= 0 {
return Ok(i64::MAX);
@ -374,8 +375,7 @@ impl HealthCache {
let perp_info = &start_cache.perp_infos[perp_info_index];
let start_health_uncapped = start_health
- perp_info.health_contribution(HealthType::Init)
+ perp_info.uncapped_health_contribution(HealthType::Init);
+ perp_info.unweighted_health_contribution(HealthType::Init);
// We add 1 here because health is computed for truncated base_lots and we want to guarantee
// zero_health_ratio <= 0.
let zero_health_amount = case1_start_i80f48
@ -938,10 +938,12 @@ mod tests {
let base_lot_size = 100;
let default_perp_info = |x| PerpInfo {
perp_market_index: 0,
maint_asset_weight: I80F48::from_num(1.0 - x),
init_asset_weight: I80F48::from_num(1.0 - x),
maint_liab_weight: I80F48::from_num(1.0 + x),
init_liab_weight: I80F48::from_num(1.0 + x),
maint_base_asset_weight: I80F48::from_num(1.0 - x),
init_base_asset_weight: I80F48::from_num(1.0 - x),
maint_base_liab_weight: I80F48::from_num(1.0 + x),
init_base_liab_weight: I80F48::from_num(1.0 + x),
maint_pnl_asset_weight: I80F48::from_num(0.6),
init_pnl_asset_weight: I80F48::from_num(0.6),
base_lot_size,
base_lots: 0,
bids_base_lots: 0,
@ -949,7 +951,6 @@ mod tests {
quote: I80F48::ZERO,
prices: Prices::new_single_price(I80F48::from_num(2.0)),
has_open_orders: false,
trusted_market: false,
};
let health_cache = HealthCache {
@ -1088,7 +1089,7 @@ mod tests {
)
.unwrap();
let mut perp1 = mock_perp_market(group, oracle1.pubkey, 1.0, 9, 0.2, 0.1);
let mut perp1 = mock_perp_market(group, oracle1.pubkey, 1.0, 9, (0.2, 0.1), (0.05, 0.02));
perp1.data().long_funding = I80F48::from_num(10.1);
let perpaccount = account.ensure_perp_position(9, 1).unwrap().0;
perpaccount.record_trade(perp1.data(), 10, I80F48::from(-110));
@ -1126,8 +1127,8 @@ mod tests {
let mut oo1 = TestAccount::<OpenOrders>::new_zeroed();
let mut perp1 = mock_perp_market(group, oracle1.pubkey, 1.0, 9, 0.2, 0.1);
let mut perp2 = mock_perp_market(group, oracle2.pubkey, 5.0, 8, 0.2, 0.1);
let mut perp1 = mock_perp_market(group, oracle1.pubkey, 1.0, 9, (0.2, 0.1), (0.05, 0.02));
let mut perp2 = mock_perp_market(group, oracle2.pubkey, 5.0, 8, (0.2, 0.1), (0.05, 0.02));
let oracle1_account_info = oracle1.as_account_info();
let oracle2_account_info = oracle2.as_account_info();
@ -1180,7 +1181,7 @@ mod tests {
)
.unwrap();
let mut perp1 = mock_perp_market(group, oracle1.pubkey, 1.0, 9, 0.2, 0.1);
let mut perp1 = mock_perp_market(group, oracle1.pubkey, 1.0, 9, (0.2, 0.1), (0.05, 0.02));
perp1.data().stable_price_model.stable_price = 0.5;
let perpaccount = account3.ensure_perp_position(9, 1).unwrap().0;
perpaccount.record_trade(perp1.data(), 10, I80F48::from(-100));

View File

@ -108,17 +108,19 @@ pub fn mock_perp_market(
oracle: Pubkey,
price: f64,
market_index: PerpMarketIndex,
init_weights: f64,
maint_weights: f64,
base_weights: (f64, f64),
pnl_weights: (f64, f64),
) -> TestAccount<PerpMarket> {
let mut pm = TestAccount::<PerpMarket>::new_zeroed();
pm.data().group = group;
pm.data().oracle = oracle;
pm.data().perp_market_index = market_index;
pm.data().init_asset_weight = I80F48::from_num(1.0 - init_weights);
pm.data().init_liab_weight = I80F48::from_num(1.0 + init_weights);
pm.data().maint_asset_weight = I80F48::from_num(1.0 - maint_weights);
pm.data().maint_liab_weight = I80F48::from_num(1.0 + maint_weights);
pm.data().init_base_asset_weight = I80F48::from_num(1.0 - base_weights.0);
pm.data().init_base_liab_weight = I80F48::from_num(1.0 + base_weights.0);
pm.data().maint_base_asset_weight = I80F48::from_num(1.0 - base_weights.1);
pm.data().maint_base_liab_weight = I80F48::from_num(1.0 + base_weights.1);
pm.data().init_pnl_asset_weight = I80F48::from_num(1.0 - pnl_weights.0);
pm.data().maint_pnl_asset_weight = I80F48::from_num(1.0 - pnl_weights.1);
pm.data().quote_lot_size = 100;
pm.data().base_lot_size = 10;
pm.data().stable_price_model.reset_to_price(price, 0);

View File

@ -56,10 +56,12 @@ pub fn perp_create_market(
base_decimals: u8,
quote_lot_size: i64,
base_lot_size: i64,
maint_asset_weight: f32,
init_asset_weight: f32,
maint_liab_weight: f32,
init_liab_weight: f32,
maint_base_asset_weight: f32,
init_base_asset_weight: f32,
maint_base_liab_weight: f32,
init_base_liab_weight: f32,
maint_pnl_asset_weight: f32,
init_pnl_asset_weight: f32,
liquidation_fee: f32,
maker_fee: f32,
taker_fee: f32,
@ -67,7 +69,6 @@ pub fn perp_create_market(
max_funding: f32,
impact_quantity: i64,
group_insurance_fund: bool,
trusted_market: bool,
fee_penalty: f32,
settle_fee_flat: f32,
settle_fee_amount_threshold: f32,
@ -93,7 +94,7 @@ pub fn perp_create_market(
group: ctx.accounts.group.key(),
settle_token_index,
perp_market_index,
trusted_market: u8::from(trusted_market),
blocked1: 0,
group_insurance_fund: u8::from(group_insurance_fund),
bump: *ctx.bumps.get("perp_market").ok_or(MangoError::SomeError)?,
base_decimals,
@ -106,10 +107,10 @@ pub fn perp_create_market(
stable_price_model: StablePriceModel::default(),
quote_lot_size,
base_lot_size,
maint_asset_weight: I80F48::from_num(maint_asset_weight),
init_asset_weight: I80F48::from_num(init_asset_weight),
maint_liab_weight: I80F48::from_num(maint_liab_weight),
init_liab_weight: I80F48::from_num(init_liab_weight),
maint_base_asset_weight: I80F48::from_num(maint_base_asset_weight),
init_base_asset_weight: I80F48::from_num(init_base_asset_weight),
maint_base_liab_weight: I80F48::from_num(maint_base_liab_weight),
init_base_liab_weight: I80F48::from_num(init_base_liab_weight),
open_interest: 0,
seq_num: 0,
registration_time: now_ts,
@ -132,7 +133,10 @@ pub fn perp_create_market(
padding3: Default::default(),
settle_pnl_limit_window_size_ts,
reduce_only: 0,
reserved: [0; 1943],
padding4: Default::default(),
maint_pnl_asset_weight: I80F48::from_num(maint_pnl_asset_weight),
init_pnl_asset_weight: I80F48::from_num(init_pnl_asset_weight),
reserved: [0; 1904],
};
let oracle_price =

View File

@ -28,10 +28,12 @@ pub fn perp_edit_market(
oracle_opt: Option<Pubkey>,
oracle_config_opt: Option<OracleConfigParams>,
base_decimals_opt: Option<u8>,
maint_asset_weight_opt: Option<f32>,
init_asset_weight_opt: Option<f32>,
maint_liab_weight_opt: Option<f32>,
init_liab_weight_opt: Option<f32>,
maint_base_asset_weight_opt: Option<f32>,
init_base_asset_weight_opt: Option<f32>,
maint_base_liab_weight_opt: Option<f32>,
init_base_liab_weight_opt: Option<f32>,
maint_pnl_asset_weight_opt: Option<f32>,
init_pnl_asset_weight_opt: Option<f32>,
liquidation_fee_opt: Option<f32>,
maker_fee_opt: Option<f32>,
taker_fee_opt: Option<f32>,
@ -39,7 +41,6 @@ pub fn perp_edit_market(
max_funding_opt: Option<f32>,
impact_quantity_opt: Option<i64>,
group_insurance_fund_opt: Option<bool>,
trusted_market_opt: Option<bool>,
fee_penalty_opt: Option<f32>,
settle_fee_flat_opt: Option<f32>,
settle_fee_amount_threshold_opt: Option<f32>,
@ -82,17 +83,23 @@ pub fn perp_edit_market(
// quote_lot_size
// base_lot_size
if let Some(maint_asset_weight) = maint_asset_weight_opt {
perp_market.maint_asset_weight = I80F48::from_num(maint_asset_weight);
if let Some(maint_base_asset_weight) = maint_base_asset_weight_opt {
perp_market.maint_base_asset_weight = I80F48::from_num(maint_base_asset_weight);
}
if let Some(init_asset_weight) = init_asset_weight_opt {
perp_market.init_asset_weight = I80F48::from_num(init_asset_weight);
if let Some(init_base_asset_weight) = init_base_asset_weight_opt {
perp_market.init_base_asset_weight = I80F48::from_num(init_base_asset_weight);
}
if let Some(maint_liab_weight) = maint_liab_weight_opt {
perp_market.maint_liab_weight = I80F48::from_num(maint_liab_weight);
if let Some(maint_base_liab_weight) = maint_base_liab_weight_opt {
perp_market.maint_base_liab_weight = I80F48::from_num(maint_base_liab_weight);
}
if let Some(init_liab_weight) = init_liab_weight_opt {
perp_market.init_liab_weight = I80F48::from_num(init_liab_weight);
if let Some(init_base_liab_weight) = init_base_liab_weight_opt {
perp_market.init_base_liab_weight = I80F48::from_num(init_base_liab_weight);
}
if let Some(maint_pnl_asset_weight) = maint_pnl_asset_weight_opt {
perp_market.maint_pnl_asset_weight = I80F48::from_num(maint_pnl_asset_weight);
}
if let Some(init_pnl_asset_weight) = init_pnl_asset_weight_opt {
perp_market.init_pnl_asset_weight = I80F48::from_num(init_pnl_asset_weight);
}
if let Some(liquidation_fee) = liquidation_fee_opt {
perp_market.liquidation_fee = I80F48::from_num(liquidation_fee);
@ -140,9 +147,6 @@ pub fn perp_edit_market(
if let Some(group_insurance_fund) = group_insurance_fund_opt {
perp_market.set_elligible_for_group_insurance_fund(group_insurance_fund);
}
if let Some(trusted_market) = trusted_market_opt {
perp_market.trusted_market = u8::from(trusted_market);
}
if let Some(settle_fee_flat) = settle_fee_flat_opt {
perp_market.settle_fee_flat = settle_fee_flat;

View File

@ -99,63 +99,62 @@ pub fn perp_liq_base_position(
// Take over the liqee's base in exchange for quote
require_msg!(liqee_base_lots != 0, "liqee base position is zero");
let (base_transfer, quote_transfer) =
if liqee_base_lots > 0 {
require_msg!(
max_base_transfer > 0,
"max_base_transfer must be positive when liqee's base_position is positive"
);
let (base_transfer, quote_transfer) = if liqee_base_lots > 0 {
require_msg!(
max_base_transfer > 0,
"max_base_transfer must be positive when liqee's base_position is positive"
);
// health gets reduced by `base * price * perp_init_asset_weight`
// and increased by `base * price * (1 - liq_fee) * quote_init_asset_weight`
let quote_init_asset_weight = I80F48::ONE;
let fee_factor = cm!(I80F48::ONE - perp_market.liquidation_fee);
let health_per_lot = cm!(price_per_lot
* (-perp_market.init_asset_weight + quote_init_asset_weight * fee_factor));
// health gets reduced by `base * price * perp_init_asset_weight`
// and increased by `base * price * (1 - liq_fee) * quote_init_asset_weight`
let quote_init_asset_weight = I80F48::ONE;
let fee_factor = cm!(I80F48::ONE - perp_market.liquidation_fee);
let health_per_lot = cm!(price_per_lot
* (-perp_market.init_base_asset_weight + quote_init_asset_weight * fee_factor));
// number of lots to transfer to bring health to zero, rounded up
let base_transfer_for_zero: i64 = cm!(-liqee_init_health / health_per_lot)
.checked_ceil()
.unwrap()
.checked_to_num()
.unwrap();
// number of lots to transfer to bring health to zero, rounded up
let base_transfer_for_zero: i64 = cm!(-liqee_init_health / health_per_lot)
.checked_ceil()
.unwrap()
.checked_to_num()
.unwrap();
let base_transfer = base_transfer_for_zero
.min(liqee_base_lots)
.min(max_base_transfer)
.max(0);
let quote_transfer = cm!(-I80F48::from(base_transfer) * price_per_lot * fee_factor);
let base_transfer = base_transfer_for_zero
.min(liqee_base_lots)
.min(max_base_transfer)
.max(0);
let quote_transfer = cm!(-I80F48::from(base_transfer) * price_per_lot * fee_factor);
(base_transfer, quote_transfer) // base > 0, quote < 0
} else {
// liqee_base_lots < 0
require_msg!(
max_base_transfer < 0,
"max_base_transfer must be negative when liqee's base_position is positive"
);
(base_transfer, quote_transfer) // base > 0, quote < 0
} else {
// liqee_base_lots < 0
require_msg!(
max_base_transfer < 0,
"max_base_transfer must be negative when liqee's base_position is positive"
);
// health gets increased by `base * price * perp_init_liab_weight`
// and reduced by `base * price * (1 + liq_fee) * quote_init_liab_weight`
let quote_init_liab_weight = I80F48::ONE;
let fee_factor = cm!(I80F48::ONE + perp_market.liquidation_fee);
let health_per_lot = cm!(price_per_lot
* (perp_market.init_liab_weight - quote_init_liab_weight * fee_factor));
// health gets increased by `base * price * perp_init_liab_weight`
// and reduced by `base * price * (1 + liq_fee) * quote_init_liab_weight`
let quote_init_liab_weight = I80F48::ONE;
let fee_factor = cm!(I80F48::ONE + perp_market.liquidation_fee);
let health_per_lot = cm!(price_per_lot
* (perp_market.init_base_liab_weight - quote_init_liab_weight * fee_factor));
// (negative) number of lots to transfer to bring health to zero, rounded away from zero
let base_transfer_for_zero: i64 = cm!(liqee_init_health / health_per_lot)
.checked_floor()
.unwrap()
.checked_to_num()
.unwrap();
// (negative) number of lots to transfer to bring health to zero, rounded away from zero
let base_transfer_for_zero: i64 = cm!(liqee_init_health / health_per_lot)
.checked_floor()
.unwrap()
.checked_to_num()
.unwrap();
let base_transfer = base_transfer_for_zero
.max(liqee_base_lots)
.max(max_base_transfer)
.min(0);
let quote_transfer = cm!(-I80F48::from(base_transfer) * price_per_lot * fee_factor);
let base_transfer = base_transfer_for_zero
.max(liqee_base_lots)
.max(max_base_transfer)
.min(0);
let quote_transfer = cm!(-I80F48::from(base_transfer) * price_per_lot * fee_factor);
(base_transfer, quote_transfer) // base < 0, quote > 0
};
(base_transfer, quote_transfer) // base < 0, quote > 0
};
// Execute the transfer. This is essentially a forced trade and updates the
// liqee and liqors entry and break even prices.

View File

@ -434,10 +434,12 @@ pub mod mango_v4 {
base_decimals: u8,
quote_lot_size: i64,
base_lot_size: i64,
maint_asset_weight: f32,
init_asset_weight: f32,
maint_liab_weight: f32,
init_liab_weight: f32,
maint_base_asset_weight: f32,
init_base_asset_weight: f32,
maint_base_liab_weight: f32,
init_base_liab_weight: f32,
maint_pnl_asset_weight: f32,
init_pnl_asset_weight: f32,
liquidation_fee: f32,
maker_fee: f32,
taker_fee: f32,
@ -445,7 +447,6 @@ pub mod mango_v4 {
max_funding: f32,
impact_quantity: i64,
group_insurance_fund: bool,
trusted_market: bool,
fee_penalty: f32,
settle_fee_flat: f32,
settle_fee_amount_threshold: f32,
@ -463,10 +464,12 @@ pub mod mango_v4 {
base_decimals,
quote_lot_size,
base_lot_size,
maint_asset_weight,
init_asset_weight,
maint_liab_weight,
init_liab_weight,
maint_base_asset_weight,
init_base_asset_weight,
maint_base_liab_weight,
init_base_liab_weight,
maint_pnl_asset_weight,
init_pnl_asset_weight,
liquidation_fee,
maker_fee,
taker_fee,
@ -474,7 +477,6 @@ pub mod mango_v4 {
max_funding,
impact_quantity,
group_insurance_fund,
trusted_market,
fee_penalty,
settle_fee_flat,
settle_fee_amount_threshold,
@ -490,10 +492,12 @@ pub mod mango_v4 {
oracle_opt: Option<Pubkey>,
oracle_config_opt: Option<OracleConfigParams>,
base_decimals_opt: Option<u8>,
maint_asset_weight_opt: Option<f32>,
init_asset_weight_opt: Option<f32>,
maint_liab_weight_opt: Option<f32>,
init_liab_weight_opt: Option<f32>,
maint_base_asset_weight_opt: Option<f32>,
init_base_asset_weight_opt: Option<f32>,
maint_base_liab_weight_opt: Option<f32>,
init_base_liab_weight_opt: Option<f32>,
maint_pnl_asset_weight_opt: Option<f32>,
init_pnl_asset_weight_opt: Option<f32>,
liquidation_fee_opt: Option<f32>,
maker_fee_opt: Option<f32>,
taker_fee_opt: Option<f32>,
@ -501,7 +505,6 @@ pub mod mango_v4 {
max_funding_opt: Option<f32>,
impact_quantity_opt: Option<i64>,
group_insurance_fund_opt: Option<bool>,
trusted_market_opt: Option<bool>,
fee_penalty_opt: Option<f32>,
settle_fee_flat_opt: Option<f32>,
settle_fee_amount_threshold_opt: Option<f32>,
@ -518,10 +521,12 @@ pub mod mango_v4 {
oracle_opt,
oracle_config_opt,
base_decimals_opt,
maint_asset_weight_opt,
init_asset_weight_opt,
maint_liab_weight_opt,
init_liab_weight_opt,
maint_base_asset_weight_opt,
init_base_asset_weight_opt,
maint_base_liab_weight_opt,
init_base_liab_weight_opt,
maint_pnl_asset_weight_opt,
init_pnl_asset_weight_opt,
liquidation_fee_opt,
maker_fee_opt,
taker_fee_opt,
@ -529,7 +534,6 @@ pub mod mango_v4 {
max_funding_opt,
impact_quantity_opt,
group_insurance_fund_opt,
trusted_market_opt,
fee_penalty_opt,
settle_fee_flat_opt,
settle_fee_amount_threshold_opt,

View File

@ -88,10 +88,10 @@ mod tests {
let mut perp_market = PerpMarket::zeroed();
perp_market.quote_lot_size = 1;
perp_market.base_lot_size = 1;
perp_market.maint_asset_weight = I80F48::ONE;
perp_market.maint_liab_weight = I80F48::ONE;
perp_market.init_asset_weight = I80F48::ONE;
perp_market.init_liab_weight = I80F48::ONE;
perp_market.maint_base_asset_weight = I80F48::ONE;
perp_market.maint_base_liab_weight = I80F48::ONE;
perp_market.init_base_asset_weight = I80F48::ONE;
perp_market.init_base_liab_weight = I80F48::ONE;
(perp_market, oracle_price, event_queue, book)
}

View File

@ -26,8 +26,8 @@ pub struct PerpMarket {
/// Lookup indices
pub perp_market_index: PerpMarketIndex,
/// May this market contribute positive values to health?
pub trusted_market: u8,
// Used to store trusted_market here
pub blocked1: u8,
/// Is this market covered by the group insurance fund?
pub group_insurance_fund: u8,
@ -56,10 +56,10 @@ pub struct PerpMarket {
// These weights apply to the base asset, the quote token is always assumed to be
// the health-reference token and have 1 for price and weights
pub maint_asset_weight: I80F48,
pub init_asset_weight: I80F48,
pub maint_liab_weight: I80F48,
pub init_liab_weight: I80F48,
pub maint_base_asset_weight: I80F48,
pub init_base_asset_weight: I80F48,
pub maint_base_liab_weight: I80F48,
pub init_base_liab_weight: I80F48,
pub open_interest: i64,
@ -114,8 +114,12 @@ pub struct PerpMarket {
pub settle_pnl_limit_window_size_ts: u64,
pub reduce_only: u8,
pub padding4: [u8; 7],
pub reserved: [u8; 1943],
pub maint_pnl_asset_weight: I80F48,
pub init_pnl_asset_weight: I80F48,
pub reserved: [u8; 1904],
}
const_assert_eq!(
@ -149,7 +153,9 @@ const_assert_eq!(
+ 8
+ 8
+ 1
+ 1943
+ 7
+ 2 * 16
+ 1904
);
const_assert_eq!(size_of::<PerpMarket>(), 2808);
const_assert_eq!(size_of::<PerpMarket>() % 8, 0);
@ -173,10 +179,6 @@ impl PerpMarket {
self.group_insurance_fund = u8::from(v);
}
pub fn trusted_market(&self) -> bool {
self.trusted_market == 1
}
pub fn settle_pnl_limit_factor(&self) -> I80F48 {
I80F48::from_num(self.settle_pnl_limit_factor)
}
@ -288,8 +290,8 @@ impl PerpMarket {
oracle_price: I80F48,
) -> bool {
match side {
Side::Bid => native_price <= cm!(self.maint_liab_weight * oracle_price),
Side::Ask => native_price >= cm!(self.maint_asset_weight * oracle_price),
Side::Bid => native_price <= cm!(self.maint_base_liab_weight * oracle_price),
Side::Ask => native_price >= cm!(self.maint_base_asset_weight * oracle_price),
}
}
@ -319,7 +321,7 @@ impl PerpMarket {
group: Pubkey::new_unique(),
settle_token_index: 0,
perp_market_index: 0,
trusted_market: 0,
blocked1: 0,
group_insurance_fund: 0,
bump: 0,
base_decimals: 0,
@ -336,10 +338,10 @@ impl PerpMarket {
stable_price_model: StablePriceModel::default(),
quote_lot_size: 1,
base_lot_size: 1,
maint_asset_weight: I80F48::from(1),
init_asset_weight: I80F48::from(1),
maint_liab_weight: I80F48::from(1),
init_liab_weight: I80F48::from(1),
maint_base_asset_weight: I80F48::from(1),
init_base_asset_weight: I80F48::from(1),
maint_base_liab_weight: I80F48::from(1),
init_base_liab_weight: I80F48::from(1),
open_interest: 0,
seq_num: 0,
registration_time: 0,
@ -362,7 +364,10 @@ impl PerpMarket {
padding3: Default::default(),
settle_pnl_limit_window_size_ts: 24 * 60 * 60,
reduce_only: 0,
reserved: [0; 1943],
padding4: Default::default(),
maint_pnl_asset_weight: I80F48::ONE,
init_pnl_asset_weight: I80F48::ONE,
reserved: [0; 1904],
}
}
}

View File

@ -2543,15 +2543,16 @@ pub struct PerpCreateMarketInstruction {
pub base_decimals: u8,
pub quote_lot_size: i64,
pub base_lot_size: i64,
pub maint_asset_weight: f32,
pub init_asset_weight: f32,
pub maint_liab_weight: f32,
pub init_liab_weight: f32,
pub maint_base_asset_weight: f32,
pub init_base_asset_weight: f32,
pub maint_base_liab_weight: f32,
pub init_base_liab_weight: f32,
pub maint_pnl_asset_weight: f32,
pub init_pnl_asset_weight: f32,
pub liquidation_fee: f32,
pub maker_fee: f32,
pub taker_fee: f32,
pub group_insurance_fund: bool,
pub trusted_market: bool,
pub fee_penalty: f32,
pub settle_fee_flat: f32,
pub settle_fee_amount_threshold: f32,
@ -2599,10 +2600,12 @@ impl ClientInstruction for PerpCreateMarketInstruction {
perp_market_index: self.perp_market_index,
quote_lot_size: self.quote_lot_size,
base_lot_size: self.base_lot_size,
maint_asset_weight: self.maint_asset_weight,
init_asset_weight: self.init_asset_weight,
maint_liab_weight: self.maint_liab_weight,
init_liab_weight: self.init_liab_weight,
maint_base_asset_weight: self.maint_base_asset_weight,
init_base_asset_weight: self.init_base_asset_weight,
maint_base_liab_weight: self.maint_base_liab_weight,
init_base_liab_weight: self.init_base_liab_weight,
maint_pnl_asset_weight: self.maint_pnl_asset_weight,
init_pnl_asset_weight: self.init_pnl_asset_weight,
liquidation_fee: self.liquidation_fee,
maker_fee: self.maker_fee,
taker_fee: self.taker_fee,
@ -2611,7 +2614,6 @@ impl ClientInstruction for PerpCreateMarketInstruction {
impact_quantity: 100,
base_decimals: self.base_decimals,
group_insurance_fund: self.group_insurance_fund,
trusted_market: self.trusted_market,
fee_penalty: self.fee_penalty,
settle_fee_flat: self.settle_fee_flat,
settle_fee_amount_threshold: self.settle_fee_amount_threshold,
@ -2656,10 +2658,12 @@ fn perp_edit_instruction_default() -> mango_v4::instruction::PerpEditMarket {
oracle_opt: None,
oracle_config_opt: None,
base_decimals_opt: None,
maint_asset_weight_opt: None,
init_asset_weight_opt: None,
maint_liab_weight_opt: None,
init_liab_weight_opt: None,
maint_base_asset_weight_opt: None,
init_base_asset_weight_opt: None,
maint_base_liab_weight_opt: None,
init_base_liab_weight_opt: None,
maint_pnl_asset_weight_opt: None,
init_pnl_asset_weight_opt: None,
liquidation_fee_opt: None,
maker_fee_opt: None,
taker_fee_opt: None,
@ -2667,7 +2671,6 @@ fn perp_edit_instruction_default() -> mango_v4::instruction::PerpEditMarket {
max_funding_opt: None,
impact_quantity_opt: None,
group_insurance_fund_opt: None,
trusted_market_opt: None,
fee_penalty_opt: None,
settle_fee_flat_opt: None,
settle_fee_amount_threshold_opt: None,

View File

@ -215,10 +215,10 @@ async fn test_health_compute_perp() -> Result<(), TransportError> {
perp_market_index: perp_market_index as PerpMarketIndex,
quote_lot_size: 10,
base_lot_size: 100,
maint_asset_weight: 0.975,
init_asset_weight: 0.95,
maint_liab_weight: 1.025,
init_liab_weight: 1.05,
maint_base_asset_weight: 0.975,
init_base_asset_weight: 0.95,
maint_base_liab_weight: 1.025,
init_base_liab_weight: 1.05,
liquidation_fee: 0.012,
maker_fee: 0.0002,
taker_fee: 0.000,

View File

@ -56,10 +56,10 @@ async fn test_liq_perps_force_cancel() -> Result<(), TransportError> {
perp_market_index: 0,
quote_lot_size: 10,
base_lot_size: 100,
maint_asset_weight: 0.8,
init_asset_weight: 0.6,
maint_liab_weight: 1.2,
init_liab_weight: 1.4,
maint_base_asset_weight: 0.8,
init_base_asset_weight: 0.6,
maint_base_liab_weight: 1.2,
init_base_liab_weight: 1.4,
liquidation_fee: 0.05,
maker_fee: 0.0,
taker_fee: 0.0,
@ -261,10 +261,10 @@ async fn test_liq_perps_base_position_and_bankruptcy() -> Result<(), TransportEr
perp_market_index: 0,
quote_lot_size: 10,
base_lot_size: 100,
maint_asset_weight: 0.8,
init_asset_weight: 0.6,
maint_liab_weight: 1.2,
init_liab_weight: 1.4,
maint_base_asset_weight: 0.8,
init_base_asset_weight: 0.6,
maint_base_liab_weight: 1.2,
init_base_liab_weight: 1.4,
liquidation_fee: 0.05,
maker_fee: 0.0,
taker_fee: 0.0,
@ -843,10 +843,10 @@ async fn test_liq_perps_bankruptcy() -> Result<(), TransportError> {
perp_market_index,
quote_lot_size: 1,
base_lot_size: 100,
maint_asset_weight: 0.8,
init_asset_weight: 0.6,
maint_liab_weight: 1.2,
init_liab_weight: 1.4,
maint_base_asset_weight: 0.8,
init_base_asset_weight: 0.6,
maint_base_liab_weight: 1.2,
init_base_liab_weight: 1.4,
liquidation_fee: 0.05,
maker_fee: 0.0,
taker_fee: 0.0,

View File

@ -76,10 +76,10 @@ async fn test_perp_fixed() -> Result<(), TransportError> {
perp_market_index: 0,
quote_lot_size: 10,
base_lot_size: 100,
maint_asset_weight: 0.975,
init_asset_weight: 0.95,
maint_liab_weight: 1.025,
init_liab_weight: 1.05,
maint_base_asset_weight: 0.975,
init_base_asset_weight: 0.95,
maint_base_liab_weight: 1.025,
init_base_liab_weight: 1.05,
liquidation_fee: 0.012,
maker_fee: -0.0001,
taker_fee: 0.0002,
@ -520,10 +520,10 @@ async fn test_perp_oracle_peg() -> Result<(), TransportError> {
perp_market_index: 0,
quote_lot_size: 10,
base_lot_size: 10000,
maint_asset_weight: 0.975,
init_asset_weight: 0.95,
maint_liab_weight: 1.025,
init_liab_weight: 1.05,
maint_base_asset_weight: 0.975,
init_base_asset_weight: 0.95,
maint_base_liab_weight: 1.025,
init_base_liab_weight: 1.05,
liquidation_fee: 0.012,
maker_fee: -0.0001,
taker_fee: 0.0002,

View File

@ -73,10 +73,10 @@ async fn test_perp_settle_pnl() -> Result<(), TransportError> {
perp_market_index: 0,
quote_lot_size: 10,
base_lot_size: 100,
maint_asset_weight: 0.975,
init_asset_weight: 0.95,
maint_liab_weight: 1.025,
init_liab_weight: 1.05,
maint_base_asset_weight: 0.975,
init_base_asset_weight: 0.95,
maint_base_liab_weight: 1.025,
init_base_liab_weight: 1.05,
liquidation_fee: 0.012,
maker_fee: 0.0002,
taker_fee: 0.000,
@ -103,10 +103,10 @@ async fn test_perp_settle_pnl() -> Result<(), TransportError> {
perp_market_index: 1,
quote_lot_size: 10,
base_lot_size: 100,
maint_asset_weight: 0.975,
init_asset_weight: 0.95,
maint_liab_weight: 1.025,
init_liab_weight: 1.05,
maint_base_asset_weight: 0.975,
init_base_asset_weight: 0.95,
maint_base_liab_weight: 1.025,
init_base_liab_weight: 1.05,
liquidation_fee: 0.012,
maker_fee: 0.0002,
taker_fee: 0.000,
@ -576,10 +576,10 @@ async fn test_perp_settle_pnl_fees() -> Result<(), TransportError> {
perp_market_index: 0,
quote_lot_size: 10,
base_lot_size: 100,
maint_asset_weight: 1.0,
init_asset_weight: 1.0,
maint_liab_weight: 1.0,
init_liab_weight: 1.0,
maint_base_asset_weight: 1.0,
init_base_asset_weight: 1.0,
maint_base_liab_weight: 1.0,
init_base_liab_weight: 1.0,
liquidation_fee: 0.0,
maker_fee: 0.0,
taker_fee: 0.0,
@ -848,10 +848,10 @@ async fn test_perp_pnl_settle_limit() -> Result<(), TransportError> {
perp_market_index: 0,
quote_lot_size: 10,
base_lot_size: 100,
maint_asset_weight: 0.975,
init_asset_weight: 0.95,
maint_liab_weight: 1.025,
init_liab_weight: 1.05,
maint_base_asset_weight: 0.975,
init_base_asset_weight: 0.95,
maint_base_liab_weight: 1.025,
init_base_liab_weight: 1.05,
liquidation_fee: 0.012,
maker_fee: 0.0,
taker_fee: 0.0,

View File

@ -152,10 +152,10 @@ async fn test_perp_settle_fees() -> Result<(), TransportError> {
perp_market_index: 0,
quote_lot_size: 10,
base_lot_size: 100,
maint_asset_weight: 0.975,
init_asset_weight: 0.95,
maint_liab_weight: 1.025,
init_liab_weight: 1.05,
maint_base_asset_weight: 0.975,
init_base_asset_weight: 0.95,
maint_base_liab_weight: 1.025,
init_base_liab_weight: 1.05,
liquidation_fee: 0.012,
maker_fee: 0.0002,
taker_fee: 0.000,
@ -182,10 +182,10 @@ async fn test_perp_settle_fees() -> Result<(), TransportError> {
perp_market_index: 1,
quote_lot_size: 10,
base_lot_size: 100,
maint_asset_weight: 0.975,
init_asset_weight: 0.95,
maint_liab_weight: 1.025,
init_liab_weight: 1.05,
maint_base_asset_weight: 0.975,
init_base_asset_weight: 0.95,
maint_base_liab_weight: 1.025,
init_base_liab_weight: 1.05,
liquidation_fee: 0.012,
maker_fee: 0.0002,
taker_fee: 0.000,

View File

@ -251,10 +251,10 @@ async fn test_perp_reduce_only() -> Result<(), TransportError> {
perp_market_index: 0,
quote_lot_size: 10,
base_lot_size: 100,
maint_asset_weight: 0.975,
init_asset_weight: 0.95,
maint_liab_weight: 1.025,
init_liab_weight: 1.05,
maint_base_asset_weight: 0.975,
init_base_asset_weight: 0.95,
maint_base_liab_weight: 1.025,
init_base_liab_weight: 1.05,
liquidation_fee: 0.012,
maker_fee: 0.0002,
taker_fee: 0.000,

View File

@ -31,17 +31,19 @@ function mockBankAndOracle(
function mockPerpMarket(
perpMarketIndex: number,
maintWeight: number,
initWeight: number,
maintBaseWeight: number,
initBaseWeight: number,
baseLotSize: number,
price: number,
): PerpMarket {
return {
perpMarketIndex,
maintAssetWeight: I80F48.fromNumber(1 - maintWeight),
initAssetWeight: I80F48.fromNumber(1 - initWeight),
maintLiabWeight: I80F48.fromNumber(1 + maintWeight),
initLiabWeight: I80F48.fromNumber(1 + initWeight),
maintBaseAssetWeight: I80F48.fromNumber(1 - maintBaseWeight),
initBaseAssetWeight: I80F48.fromNumber(1 - initBaseWeight),
maintBaseLiabWeight: I80F48.fromNumber(1 + maintBaseWeight),
initBaseLiabWeight: I80F48.fromNumber(1 + initBaseWeight),
maintPnlAssetWeight: I80F48.fromNumber(1 - 0.02),
initPnlAssetWeight: I80F48.fromNumber(1 - 0.05),
price: I80F48.fromNumber(price),
stablePriceModel: { stablePrice: price } as StablePriceModel,
quoteLotSize: new BN(100),
@ -231,7 +233,9 @@ describe('Health Cache', () => {
const hc = new HealthCache([ti1, ti2, ti3], [si1, si2], [pi1]);
const health = hc.health(HealthType.init).toNumber();
console.log(
` - case "${fixture.name}" health ${health.toFixed(3).padStart(10)}`,
` - case "${fixture.name}" health ${health
.toFixed(3)
.padStart(10)}, expected ${fixture.expectedHealth}`,
);
expect(health - fixture.expectedHealth).lessThan(0.0000001);
}
@ -276,18 +280,18 @@ describe('Health Cache', () => {
});
testFixture({
name: '2',
name: '2: weighted positive perp pnl',
token1: 0,
token2: 0,
token3: 0,
oo12: [0, 0],
oo13: [0, 0],
perp1: [-10, 100, 0, 0],
expectedHealth: 0,
perp1: [-1, 100, 0, 0],
expectedHealth: 0.95 * (100.0 - 1.2 * 1.0 * baseLotsToQuote),
});
testFixture({
name: '3',
name: '3: negative perp pnl is not weighted',
token1: 0,
token2: 0,
token3: 0,
@ -298,25 +302,25 @@ describe('Health Cache', () => {
});
testFixture({
name: '4',
name: '4: perp health',
token1: 0,
token2: 0,
token3: 0,
oo12: [0, 0],
oo13: [0, 0],
perp1: [10, 100, 0, 0],
expectedHealth: 0,
expectedHealth: 0.95 * (100.0 + 0.8 * 10.0 * baseLotsToQuote),
});
testFixture({
name: '5',
name: '5: perp health',
token1: 0,
token2: 0,
token3: 0,
oo12: [0, 0],
oo13: [0, 0],
perp1: [30, -100, 0, 0],
expectedHealth: 0,
expectedHealth: 0.95 * (-100.0 + 0.8 * 30.0 * baseLotsToQuote),
});
testFixture({
@ -326,7 +330,7 @@ describe('Health Cache', () => {
token3: -10,
oo12: [1, 1],
oo13: [1, 1],
perp1: [30, -100, 0, 0],
perp1: [0, 0, 0, 0],
expectedHealth:
// tokens
-100.0 * 1.2 -

View File

@ -206,13 +206,11 @@ export class HealthCache {
health.iadd(contrib);
}
for (const perpInfo of this.perpInfos) {
if (perpInfo.trustedMarket) {
const positiveContrib = perpInfo
.uncappedHealthContribution(HealthType.maint)
.max(ZERO_I80F48());
// console.log(` - pi ${positiveContrib}`);
health.iadd(positiveContrib);
}
const positiveContrib = perpInfo
.healthContribution(HealthType.maint)
.max(ZERO_I80F48());
// console.log(` - pi ${positiveContrib}`);
health.iadd(positiveContrib);
}
return health;
}
@ -1052,8 +1050,12 @@ export class HealthCache {
// If the price is sufficiently good then health will just increase from trading
const finalHealthSlope =
direction == 1
? perpInfo.initAssetWeight.mul(prices.asset(HealthType.init)).sub(price)
: price.sub(perpInfo.initLiabWeight.mul(prices.liab(HealthType.init)));
? perpInfo.initBaseAssetWeight
.mul(prices.asset(HealthType.init))
.sub(price)
: price.sub(
perpInfo.initBaseLiabWeight.mul(prices.liab(HealthType.init)),
);
if (finalHealthSlope.gte(ZERO_I80F48())) {
return MAX_I80F48();
}
@ -1123,7 +1125,7 @@ export class HealthCache {
const perpInfo = startCache.perpInfos[perpInfoIndex];
const startHealthUncapped = startHealth
.sub(perpInfo.healthContribution(HealthType.init))
.add(perpInfo.uncappedHealthContribution(HealthType.init));
.add(perpInfo.unweightedHealthContribution(HealthType.init));
const zeroHealthAmount = case1Start
.sub(startHealthUncapped.div(finalHealthSlope).div(baseLotSize))
@ -1420,10 +1422,12 @@ export class Serum3Info {
export class PerpInfo {
constructor(
public perpMarketIndex: number,
public maintAssetWeight: I80F48,
public initAssetWeight: I80F48,
public maintLiabWeight: I80F48,
public initLiabWeight: I80F48,
public maintBaseAssetWeight: I80F48,
public initBaseAssetWeight: I80F48,
public maintBaseLiabWeight: I80F48,
public initBaseLiabWeight: I80F48,
public maintPnlAssetWeight: I80F48,
public initPnlAssetWeight: I80F48,
public baseLotSize: BN,
public baseLots: BN,
public bidsBaseLots: BN,
@ -1431,16 +1435,17 @@ export class PerpInfo {
public quote: I80F48,
public prices: Prices,
public hasOpenOrders: boolean,
public trustedMarket: boolean,
) {}
static fromDto(dto: PerpInfoDto): PerpInfo {
return new PerpInfo(
dto.perpMarketIndex,
I80F48.from(dto.maintAssetWeight),
I80F48.from(dto.initAssetWeight),
I80F48.from(dto.maintLiabWeight),
I80F48.from(dto.initLiabWeight),
I80F48.from(dto.maintBaseAssetWeight),
I80F48.from(dto.initBaseAssetWeight),
I80F48.from(dto.maintBaseLiabWeight),
I80F48.from(dto.initBaseLiabWeight),
I80F48.from(dto.maintPnlAssetWeight),
I80F48.from(dto.initPnlAssetWeight),
dto.baseLotSize,
dto.baseLots,
dto.bidsBaseLots,
@ -1451,7 +1456,6 @@ export class PerpInfo {
I80F48.from(dto.prices.stable),
),
dto.hasOpenOrders,
dto.trustedMarket,
);
}
@ -1473,10 +1477,12 @@ export class PerpInfo {
return new PerpInfo(
perpMarket.perpMarketIndex,
perpMarket.maintAssetWeight,
perpMarket.initAssetWeight,
perpMarket.maintLiabWeight,
perpMarket.initLiabWeight,
perpMarket.maintBaseAssetWeight,
perpMarket.initBaseAssetWeight,
perpMarket.maintBaseLiabWeight,
perpMarket.initBaseLiabWeight,
perpMarket.maintPnlAssetWeight,
perpMarket.initPnlAssetWeight,
perpMarket.baseLotSize,
baseLots,
perpPosition.bidsBaseLots,
@ -1487,17 +1493,22 @@ export class PerpInfo {
I80F48.fromNumber(perpMarket.stablePriceModel.stablePrice),
),
perpPosition.hasOpenOrders(),
perpMarket.trustedMarket,
);
}
healthContribution(healthType: HealthType | undefined): I80F48 {
return this.trustedMarket
? this.uncappedHealthContribution(healthType)
: this.uncappedHealthContribution(healthType).min(ZERO_I80F48());
const contrib = this.unweightedHealthContribution(healthType);
if (contrib.gt(ZERO_I80F48())) {
const assetWeight =
healthType == HealthType.init
? this.initPnlAssetWeight
: this.maintPnlAssetWeight;
return assetWeight.mul(contrib);
}
return contrib;
}
uncappedHealthContribution(healthType: HealthType | undefined): I80F48 {
unweightedHealthContribution(healthType: HealthType | undefined): I80F48 {
function orderExecutionCase(
pi: PerpInfo,
ordersBaseLots: BN,
@ -1510,18 +1521,18 @@ export class PerpInfo {
let weight, basePrice;
if (healthType == HealthType.init) {
if (netBaseNative.isNeg()) {
weight = pi.initLiabWeight;
weight = pi.initBaseLiabWeight;
basePrice = pi.prices.liab(healthType);
} else {
weight = pi.initAssetWeight;
weight = pi.initBaseAssetWeight;
basePrice = pi.prices.asset(healthType);
}
} else {
if (netBaseNative.isNeg()) {
weight = pi.maintLiabWeight;
weight = pi.maintBaseLiabWeight;
basePrice = pi.prices.liab(healthType);
} else {
weight = pi.maintAssetWeight;
weight = pi.maintBaseAssetWeight;
basePrice = pi.prices.asset(healthType);
}
}
@ -1557,10 +1568,12 @@ export class PerpInfo {
static emptyFromPerpMarket(perpMarket: PerpMarket): PerpInfo {
return new PerpInfo(
perpMarket.perpMarketIndex,
perpMarket.maintAssetWeight,
perpMarket.initAssetWeight,
perpMarket.maintLiabWeight,
perpMarket.initLiabWeight,
perpMarket.maintBaseAssetWeight,
perpMarket.initBaseAssetWeight,
perpMarket.maintBaseLiabWeight,
perpMarket.initBaseLiabWeight,
perpMarket.maintPnlAssetWeight,
perpMarket.initPnlAssetWeight,
perpMarket.baseLotSize,
new BN(0),
new BN(0),
@ -1571,7 +1584,6 @@ export class PerpInfo {
I80F48.fromNumber(perpMarket.stablePriceModel.stablePrice),
),
false,
perpMarket.trustedMarket,
);
}
@ -1580,7 +1592,7 @@ export class PerpInfo {
this.baseLots
}, quote: ${this.quote}, oraclePrice: ${
this.prices.oracle
}, uncapped health contribution ${this.uncappedHealthContribution(
}, uncapped health contribution ${this.unweightedHealthContribution(
HealthType.init,
)}`;
}
@ -1641,10 +1653,12 @@ export class Serum3InfoDto {
export class PerpInfoDto {
perpMarketIndex: number;
maintAssetWeight: I80F48Dto;
initAssetWeight: I80F48Dto;
maintLiabWeight: I80F48Dto;
initLiabWeight: I80F48Dto;
maintBaseAssetWeight: I80F48Dto;
initBaseAssetWeight: I80F48Dto;
maintBaseLiabWeight: I80F48Dto;
initBaseLiabWeight: I80F48Dto;
maintPnlAssetWeight: I80F48Dto;
initPnlAssetWeight: I80F48Dto;
public baseLotSize: BN;
public baseLots: BN;
public bidsBaseLots: BN;
@ -1652,5 +1666,4 @@ export class PerpInfoDto {
quote: I80F48Dto;
prices: { oracle: I80F48Dto; stable: I80F48Dto };
hasOpenOrders: boolean;
trustedMarket: boolean;
}

View File

@ -30,10 +30,10 @@ export type ParsedFillEvent = Modify<
export class PerpMarket {
public name: string;
public oracleConfig: OracleConfig;
public maintAssetWeight: I80F48;
public initAssetWeight: I80F48;
public maintLiabWeight: I80F48;
public initLiabWeight: I80F48;
public maintBaseAssetWeight: I80F48;
public initBaseAssetWeight: I80F48;
public maintBaseLiabWeight: I80F48;
public initBaseLiabWeight: I80F48;
public liquidationFee: I80F48;
public makerFee: I80F48;
public takerFee: I80F48;
@ -43,6 +43,9 @@ export class PerpMarket {
public shortFunding: I80F48;
public feesAccrued: I80F48;
public feesSettled: I80F48;
public maintPnlAssetWeight: I80F48;
public initPnlAssetWeight: I80F48;
public _price: I80F48;
public _uiPrice: number;
@ -59,7 +62,6 @@ export class PerpMarket {
group: PublicKey;
settleTokenIndex: number;
perpMarketIndex: number;
trustedMarket: number;
groupInsuranceFund: number;
baseDecimals: number;
name: number[];
@ -71,10 +73,10 @@ export class PerpMarket {
stablePriceModel: StablePriceModel;
quoteLotSize: BN;
baseLotSize: BN;
maintAssetWeight: I80F48Dto;
initAssetWeight: I80F48Dto;
maintLiabWeight: I80F48Dto;
initLiabWeight: I80F48Dto;
maintBaseAssetWeight: I80F48Dto;
initBaseAssetWeight: I80F48Dto;
maintBaseLiabWeight: I80F48Dto;
initBaseLiabWeight: I80F48Dto;
openInterest: BN;
seqNum: BN;
registrationTime: BN;
@ -96,6 +98,8 @@ export class PerpMarket {
settlePnlLimitFactor: number;
settlePnlLimitWindowSizeTs: BN;
reduceOnly: number;
maintPnlAssetWeight: I80F48Dto;
initPnlAssetWeight: I80F48Dto;
},
): PerpMarket {
return new PerpMarket(
@ -103,7 +107,6 @@ export class PerpMarket {
obj.group,
obj.settleTokenIndex as TokenIndex,
obj.perpMarketIndex as PerpMarketIndex,
obj.trustedMarket == 1,
obj.groupInsuranceFund == 1,
obj.baseDecimals,
obj.name,
@ -115,10 +118,10 @@ export class PerpMarket {
obj.stablePriceModel,
obj.quoteLotSize,
obj.baseLotSize,
obj.maintAssetWeight,
obj.initAssetWeight,
obj.maintLiabWeight,
obj.initLiabWeight,
obj.maintBaseAssetWeight,
obj.initBaseAssetWeight,
obj.maintBaseLiabWeight,
obj.initBaseLiabWeight,
obj.openInterest,
obj.seqNum,
obj.registrationTime,
@ -140,6 +143,8 @@ export class PerpMarket {
obj.settlePnlLimitFactor,
obj.settlePnlLimitWindowSizeTs,
obj.reduceOnly == 1,
obj.maintPnlAssetWeight,
obj.initPnlAssetWeight,
);
}
@ -148,7 +153,6 @@ export class PerpMarket {
public group: PublicKey,
public settleTokenIndex: TokenIndex,
public perpMarketIndex: PerpMarketIndex, // TODO rename to marketIndex?
public trustedMarket: boolean,
public groupInsuranceFund: boolean,
public baseDecimals: number,
name: number[],
@ -160,10 +164,10 @@ export class PerpMarket {
public stablePriceModel: StablePriceModel,
public quoteLotSize: BN,
public baseLotSize: BN,
maintAssetWeight: I80F48Dto,
initAssetWeight: I80F48Dto,
maintLiabWeight: I80F48Dto,
initLiabWeight: I80F48Dto,
maintBaseAssetWeight: I80F48Dto,
initBaseAssetWeight: I80F48Dto,
maintBaseLiabWeight: I80F48Dto,
initBaseLiabWeight: I80F48Dto,
public openInterest: BN,
public seqNum: BN,
public registrationTime: BN,
@ -185,16 +189,18 @@ export class PerpMarket {
public settlePnlLimitFactor: number,
public settlePnlLimitWindowSizeTs: BN,
public reduceOnly: boolean,
maintPnlAssetWeight: I80F48Dto,
initPnlAssetWeight: I80F48Dto,
) {
this.name = utf8.decode(new Uint8Array(name)).split('\x00')[0];
this.oracleConfig = {
confFilter: I80F48.from(oracleConfig.confFilter),
maxStalenessSlots: oracleConfig.maxStalenessSlots,
} as OracleConfig;
this.maintAssetWeight = I80F48.from(maintAssetWeight);
this.initAssetWeight = I80F48.from(initAssetWeight);
this.maintLiabWeight = I80F48.from(maintLiabWeight);
this.initLiabWeight = I80F48.from(initLiabWeight);
this.maintBaseAssetWeight = I80F48.from(maintBaseAssetWeight);
this.initBaseAssetWeight = I80F48.from(initBaseAssetWeight);
this.maintBaseLiabWeight = I80F48.from(maintBaseLiabWeight);
this.initBaseLiabWeight = I80F48.from(initBaseLiabWeight);
this.liquidationFee = I80F48.from(liquidationFee);
this.makerFee = I80F48.from(makerFee);
this.takerFee = I80F48.from(takerFee);
@ -204,6 +210,8 @@ export class PerpMarket {
this.shortFunding = I80F48.from(shortFunding);
this.feesAccrued = I80F48.from(feesAccrued);
this.feesSettled = I80F48.from(feesSettled);
this.maintPnlAssetWeight = I80F48.from(maintPnlAssetWeight);
this.initPnlAssetWeight = I80F48.from(initPnlAssetWeight);
this.priceLotsToUiConverter = new Big(10)
.pow(baseDecimals - QUOTE_DECIMALS)
@ -249,9 +257,9 @@ export class PerpMarket {
insidePriceLimit(side: PerpOrderSide, orderPrice: number): boolean {
return (
(side === PerpOrderSide.bid &&
orderPrice <= this.maintLiabWeight.toNumber() * this.uiPrice) ||
orderPrice <= this.maintBaseLiabWeight.toNumber() * this.uiPrice) ||
(side === PerpOrderSide.ask &&
orderPrice >= this.maintAssetWeight.toNumber() * this.uiPrice)
orderPrice >= this.maintBaseAssetWeight.toNumber() * this.uiPrice)
);
}
@ -486,13 +494,13 @@ export class PerpMarket {
'\n perpMarketIndex -' +
this.perpMarketIndex +
'\n maintAssetWeight -' +
this.maintAssetWeight.toString() +
this.maintBaseAssetWeight.toString() +
'\n initAssetWeight -' +
this.initAssetWeight.toString() +
this.initBaseAssetWeight.toString() +
'\n maintLiabWeight -' +
this.maintLiabWeight.toString() +
this.maintBaseLiabWeight.toString() +
'\n initLiabWeight -' +
this.initLiabWeight.toString() +
this.initBaseLiabWeight.toString() +
'\n liquidationFee -' +
this.liquidationFee.toString() +
'\n makerFee -' +

View File

@ -1521,10 +1521,12 @@ export class MangoClient {
baseDecimals: number,
quoteLotSize: number,
baseLotSize: number,
maintAssetWeight: number,
initAssetWeight: number,
maintLiabWeight: number,
initLiabWeight: number,
maintBaseAssetWeight: number,
initBaseAssetWeight: number,
maintBaseLiabWeight: number,
initBaseLiabWeight: number,
maintPnlAssetWeight: number,
initPnlAssetWeight: number,
liquidationFee: number,
makerFee: number,
takerFee: number,
@ -1533,7 +1535,6 @@ export class MangoClient {
maxFunding: number,
impactQuantity: number,
groupInsuranceFund: boolean,
trustedMarket: boolean,
settleFeeFlat: number,
settleFeeAmountThreshold: number,
settleFeeFractionLowHealth: number,
@ -1560,10 +1561,12 @@ export class MangoClient {
baseDecimals,
new BN(quoteLotSize),
new BN(baseLotSize),
maintAssetWeight,
initAssetWeight,
maintLiabWeight,
initLiabWeight,
maintBaseAssetWeight,
initBaseAssetWeight,
maintBaseLiabWeight,
initBaseLiabWeight,
maintPnlAssetWeight,
initPnlAssetWeight,
liquidationFee,
makerFee,
takerFee,
@ -1571,7 +1574,6 @@ export class MangoClient {
maxFunding,
new BN(impactQuantity),
groupInsuranceFund,
trustedMarket,
feePenalty,
settleFeeFlat,
settleFeeAmountThreshold,
@ -1642,10 +1644,12 @@ export class MangoClient {
params.oracle,
params.oracleConfig,
params.baseDecimals,
params.maintAssetWeight,
params.initAssetWeight,
params.maintLiabWeight,
params.initLiabWeight,
params.maintBaseAssetWeight,
params.initBaseAssetWeight,
params.maintBaseLiabWeight,
params.initBaseLiabWeight,
params.maintPnlAssetWeight,
params.initPnlAssetWeight,
params.liquidationFee,
params.makerFee,
params.takerFee,
@ -1653,7 +1657,6 @@ export class MangoClient {
params.maxFunding,
params.impactQuantity !== null ? new BN(params.impactQuantity) : null,
params.groupInsuranceFund,
params.trustedMarket,
params.feePenalty,
params.settleFeeFlat,
params.settleFeeAmountThreshold,

View File

@ -55,10 +55,12 @@ export interface PerpEditParams {
oracle: PublicKey | null;
oracleConfig: OracleConfigParams | null;
baseDecimals: number | null;
maintAssetWeight: number | null;
initAssetWeight: number | null;
maintLiabWeight: number | null;
initLiabWeight: number | null;
maintBaseAssetWeight: number | null;
initBaseAssetWeight: number | null;
maintBaseLiabWeight: number | null;
initBaseLiabWeight: number | null;
maintPnlAssetWeight: number | null;
initPnlAssetWeight: number | null;
liquidationFee: number | null;
makerFee: number | null;
takerFee: number | null;
@ -67,7 +69,6 @@ export interface PerpEditParams {
maxFunding: number | null;
impactQuantity: number | null;
groupInsuranceFund: boolean | null;
trustedMarket: boolean | null;
settleFeeFlat: number | null;
settleFeeAmountThreshold: number | null;
settleFeeFractionLowHealth: number | null;
@ -83,10 +84,12 @@ export const NullPerpEditParams: PerpEditParams = {
oracle: null,
oracleConfig: null,
baseDecimals: null,
maintAssetWeight: null,
initAssetWeight: null,
maintLiabWeight: null,
initLiabWeight: null,
maintBaseAssetWeight: null,
initBaseAssetWeight: null,
maintBaseLiabWeight: null,
initBaseLiabWeight: null,
maintPnlAssetWeight: null,
initPnlAssetWeight: null,
liquidationFee: null,
makerFee: null,
takerFee: null,
@ -95,7 +98,6 @@ export const NullPerpEditParams: PerpEditParams = {
maxFunding: null,
impactQuantity: null,
groupInsuranceFund: null,
trustedMarket: null,
settleFeeFlat: null,
settleFeeAmountThreshold: null,
settleFeeFractionLowHealth: null,

View File

@ -1,5 +1,5 @@
export type MangoV4 = {
"version": "0.2.0",
"version": "0.3.0",
"name": "mango_v4",
"instructions": [
{
@ -2508,19 +2508,27 @@ export type MangoV4 = {
"type": "i64"
},
{
"name": "maintAssetWeight",
"name": "maintBaseAssetWeight",
"type": "f32"
},
{
"name": "initAssetWeight",
"name": "initBaseAssetWeight",
"type": "f32"
},
{
"name": "maintLiabWeight",
"name": "maintBaseLiabWeight",
"type": "f32"
},
{
"name": "initLiabWeight",
"name": "initBaseLiabWeight",
"type": "f32"
},
{
"name": "maintPnlAssetWeight",
"type": "f32"
},
{
"name": "initPnlAssetWeight",
"type": "f32"
},
{
@ -2551,10 +2559,6 @@ export type MangoV4 = {
"name": "groupInsuranceFund",
"type": "bool"
},
{
"name": "trustedMarket",
"type": "bool"
},
{
"name": "feePenalty",
"type": "f32"
@ -2631,25 +2635,37 @@ export type MangoV4 = {
}
},
{
"name": "maintAssetWeightOpt",
"name": "maintBaseAssetWeightOpt",
"type": {
"option": "f32"
}
},
{
"name": "initAssetWeightOpt",
"name": "initBaseAssetWeightOpt",
"type": {
"option": "f32"
}
},
{
"name": "maintLiabWeightOpt",
"name": "maintBaseLiabWeightOpt",
"type": {
"option": "f32"
}
},
{
"name": "initLiabWeightOpt",
"name": "initBaseLiabWeightOpt",
"type": {
"option": "f32"
}
},
{
"name": "maintPnlAssetWeightOpt",
"type": {
"option": "f32"
}
},
{
"name": "initPnlAssetWeightOpt",
"type": {
"option": "f32"
}
@ -2696,12 +2712,6 @@ export type MangoV4 = {
"option": "bool"
}
},
{
"name": "trustedMarketOpt",
"type": {
"option": "bool"
}
},
{
"name": "feePenaltyOpt",
"type": {
@ -4308,10 +4318,7 @@ export type MangoV4 = {
"type": "u16"
},
{
"name": "trustedMarket",
"docs": [
"May this market contribute positive values to health?"
],
"name": "blocked1",
"type": "u8"
},
{
@ -4386,25 +4393,25 @@ export type MangoV4 = {
"type": "i64"
},
{
"name": "maintAssetWeight",
"name": "maintBaseAssetWeight",
"type": {
"defined": "I80F48"
}
},
{
"name": "initAssetWeight",
"name": "initBaseAssetWeight",
"type": {
"defined": "I80F48"
}
},
{
"name": "maintLiabWeight",
"name": "maintBaseLiabWeight",
"type": {
"defined": "I80F48"
}
},
{
"name": "initLiabWeight",
"name": "initBaseLiabWeight",
"type": {
"defined": "I80F48"
}
@ -4564,12 +4571,33 @@ export type MangoV4 = {
"name": "reduceOnly",
"type": "u8"
},
{
"name": "padding4",
"type": {
"array": [
"u8",
7
]
}
},
{
"name": "maintPnlAssetWeight",
"type": {
"defined": "I80F48"
}
},
{
"name": "initPnlAssetWeight",
"type": {
"defined": "I80F48"
}
},
{
"name": "reserved",
"type": {
"array": [
"u8",
1943
1904
]
}
}
@ -4869,25 +4897,37 @@ export type MangoV4 = {
"type": "u16"
},
{
"name": "maintAssetWeight",
"name": "maintBaseAssetWeight",
"type": {
"defined": "I80F48"
}
},
{
"name": "initAssetWeight",
"name": "initBaseAssetWeight",
"type": {
"defined": "I80F48"
}
},
{
"name": "maintLiabWeight",
"name": "maintBaseLiabWeight",
"type": {
"defined": "I80F48"
}
},
{
"name": "initLiabWeight",
"name": "initBaseLiabWeight",
"type": {
"defined": "I80F48"
}
},
{
"name": "maintPnlAssetWeight",
"type": {
"defined": "I80F48"
}
},
{
"name": "initPnlAssetWeight",
"type": {
"defined": "I80F48"
}
@ -4923,10 +4963,6 @@ export type MangoV4 = {
{
"name": "hasOpenOrders",
"type": "bool"
},
{
"name": "trustedMarket",
"type": "bool"
}
]
}
@ -7717,7 +7753,7 @@ export type MangoV4 = {
};
export const IDL: MangoV4 = {
"version": "0.2.0",
"version": "0.3.0",
"name": "mango_v4",
"instructions": [
{
@ -10226,19 +10262,27 @@ export const IDL: MangoV4 = {
"type": "i64"
},
{
"name": "maintAssetWeight",
"name": "maintBaseAssetWeight",
"type": "f32"
},
{
"name": "initAssetWeight",
"name": "initBaseAssetWeight",
"type": "f32"
},
{
"name": "maintLiabWeight",
"name": "maintBaseLiabWeight",
"type": "f32"
},
{
"name": "initLiabWeight",
"name": "initBaseLiabWeight",
"type": "f32"
},
{
"name": "maintPnlAssetWeight",
"type": "f32"
},
{
"name": "initPnlAssetWeight",
"type": "f32"
},
{
@ -10269,10 +10313,6 @@ export const IDL: MangoV4 = {
"name": "groupInsuranceFund",
"type": "bool"
},
{
"name": "trustedMarket",
"type": "bool"
},
{
"name": "feePenalty",
"type": "f32"
@ -10349,25 +10389,37 @@ export const IDL: MangoV4 = {
}
},
{
"name": "maintAssetWeightOpt",
"name": "maintBaseAssetWeightOpt",
"type": {
"option": "f32"
}
},
{
"name": "initAssetWeightOpt",
"name": "initBaseAssetWeightOpt",
"type": {
"option": "f32"
}
},
{
"name": "maintLiabWeightOpt",
"name": "maintBaseLiabWeightOpt",
"type": {
"option": "f32"
}
},
{
"name": "initLiabWeightOpt",
"name": "initBaseLiabWeightOpt",
"type": {
"option": "f32"
}
},
{
"name": "maintPnlAssetWeightOpt",
"type": {
"option": "f32"
}
},
{
"name": "initPnlAssetWeightOpt",
"type": {
"option": "f32"
}
@ -10414,12 +10466,6 @@ export const IDL: MangoV4 = {
"option": "bool"
}
},
{
"name": "trustedMarketOpt",
"type": {
"option": "bool"
}
},
{
"name": "feePenaltyOpt",
"type": {
@ -12026,10 +12072,7 @@ export const IDL: MangoV4 = {
"type": "u16"
},
{
"name": "trustedMarket",
"docs": [
"May this market contribute positive values to health?"
],
"name": "blocked1",
"type": "u8"
},
{
@ -12104,25 +12147,25 @@ export const IDL: MangoV4 = {
"type": "i64"
},
{
"name": "maintAssetWeight",
"name": "maintBaseAssetWeight",
"type": {
"defined": "I80F48"
}
},
{
"name": "initAssetWeight",
"name": "initBaseAssetWeight",
"type": {
"defined": "I80F48"
}
},
{
"name": "maintLiabWeight",
"name": "maintBaseLiabWeight",
"type": {
"defined": "I80F48"
}
},
{
"name": "initLiabWeight",
"name": "initBaseLiabWeight",
"type": {
"defined": "I80F48"
}
@ -12282,12 +12325,33 @@ export const IDL: MangoV4 = {
"name": "reduceOnly",
"type": "u8"
},
{
"name": "padding4",
"type": {
"array": [
"u8",
7
]
}
},
{
"name": "maintPnlAssetWeight",
"type": {
"defined": "I80F48"
}
},
{
"name": "initPnlAssetWeight",
"type": {
"defined": "I80F48"
}
},
{
"name": "reserved",
"type": {
"array": [
"u8",
1943
1904
]
}
}
@ -12587,25 +12651,37 @@ export const IDL: MangoV4 = {
"type": "u16"
},
{
"name": "maintAssetWeight",
"name": "maintBaseAssetWeight",
"type": {
"defined": "I80F48"
}
},
{
"name": "initAssetWeight",
"name": "initBaseAssetWeight",
"type": {
"defined": "I80F48"
}
},
{
"name": "maintLiabWeight",
"name": "maintBaseLiabWeight",
"type": {
"defined": "I80F48"
}
},
{
"name": "initLiabWeight",
"name": "initBaseLiabWeight",
"type": {
"defined": "I80F48"
}
},
{
"name": "maintPnlAssetWeight",
"type": {
"defined": "I80F48"
}
},
{
"name": "initPnlAssetWeight",
"type": {
"defined": "I80F48"
}
@ -12641,10 +12717,6 @@ export const IDL: MangoV4 = {
{
"name": "hasOpenOrders",
"type": "bool"
},
{
"name": "trustedMarket",
"type": "bool"
}
]
}

View File

@ -245,13 +245,14 @@ async function main() {
1.05,
0.012,
0.0002,
1,
1,
0.0,
0,
0.05,
0.05,
100,
true,
true,
1000,
1000000,
0.05,

View File

@ -424,6 +424,8 @@ async function registerPerpMarkets() {
0.95,
1.025,
1.05,
1,
1,
0.0125,
-0.0001,
0.0004,
@ -432,7 +434,6 @@ async function registerPerpMarkets() {
0.05,
100, // if btc is at 20k, this is 200$
true,
true,
1000, // solana tx fee is currently 50 native quote at a sol price of 10$
1000000,
0.01, // less than liquidationFee
@ -454,6 +455,8 @@ async function registerPerpMarkets() {
0.99, // 100x leverage
1.005,
1.01,
0,
0,
0.0025,
-0.0001,
0.0004,
@ -462,7 +465,6 @@ async function registerPerpMarkets() {
0.05,
1000, // if mngo price 1 cent, this is 10$
false,
false,
1000,
1000000,
0.001, // less than liquidationFee
@ -487,21 +489,6 @@ async function makePerpMarketReduceOnly() {
);
}
async function makePerpMarketUntrusted() {
const result = await buildAdminClient();
const client = result[0];
const admin = result[1];
const creator = result[2];
const group = await client.getGroupForCreator(creator.publicKey, GROUP_NUM);
const perpMarket = group.getPerpMarketByName('BTC-PERP');
await client.perpEditMarket(
group,
perpMarket.perpMarketIndex,
Builder(NullPerpEditParams).trustedMarket(false).build(),
);
}
async function createAndPopulateAlt() {
const result = await buildAdminClient();
const client = result[0];
@ -662,7 +649,6 @@ async function main() {
try {
// await registerPerpMarkets();
// await makePerpMarketReduceOnly();
// await makePerpMarketUntrusted();
} catch (error) {
console.log(error);
}

View File

@ -228,6 +228,8 @@ async function main() {
0.8,
1.1,
1.2,
1,
1,
0.05,
-0.001,
0.002,
@ -236,7 +238,6 @@ async function main() {
0.1,
10,
false,
false,
0,
0,
0,