Merge pull request #234 from blockworks-foundation/cj/ioc_fees
Extra fees for IOC orders
This commit is contained in:
commit
a97b40a521
|
@ -64,6 +64,7 @@ pub fn perp_create_market(
|
||||||
impact_quantity: i64,
|
impact_quantity: i64,
|
||||||
group_insurance_fund: bool,
|
group_insurance_fund: bool,
|
||||||
trusted_market: bool,
|
trusted_market: bool,
|
||||||
|
fee_penalty: f32,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut perp_market = ctx.accounts.perp_market.load_init()?;
|
let mut perp_market = ctx.accounts.perp_market.load_init()?;
|
||||||
*perp_market = PerpMarket {
|
*perp_market = PerpMarket {
|
||||||
|
@ -103,7 +104,8 @@ pub fn perp_create_market(
|
||||||
padding0: Default::default(),
|
padding0: Default::default(),
|
||||||
padding1: Default::default(),
|
padding1: Default::default(),
|
||||||
padding2: Default::default(),
|
padding2: Default::default(),
|
||||||
reserved: [0; 112],
|
fee_penalty,
|
||||||
|
reserved: [0; 108],
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut bids = ctx.accounts.bids.load_init()?;
|
let mut bids = ctx.accounts.bids.load_init()?;
|
||||||
|
|
|
@ -35,6 +35,7 @@ pub fn perp_edit_market(
|
||||||
impact_quantity_opt: Option<i64>,
|
impact_quantity_opt: Option<i64>,
|
||||||
group_insurance_fund_opt: Option<bool>,
|
group_insurance_fund_opt: Option<bool>,
|
||||||
trusted_market_opt: Option<bool>,
|
trusted_market_opt: Option<bool>,
|
||||||
|
fee_penalty_opt: Option<f32>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut perp_market = ctx.accounts.perp_market.load_mut()?;
|
let mut perp_market = ctx.accounts.perp_market.load_mut()?;
|
||||||
|
|
||||||
|
@ -91,6 +92,9 @@ pub fn perp_edit_market(
|
||||||
if let Some(impact_quantity) = impact_quantity_opt {
|
if let Some(impact_quantity) = impact_quantity_opt {
|
||||||
perp_market.impact_quantity = impact_quantity;
|
perp_market.impact_quantity = impact_quantity;
|
||||||
}
|
}
|
||||||
|
if let Some(fee_penalty) = fee_penalty_opt {
|
||||||
|
perp_market.fee_penalty = fee_penalty;
|
||||||
|
}
|
||||||
|
|
||||||
// unchanged -
|
// unchanged -
|
||||||
// long_funding
|
// long_funding
|
||||||
|
|
|
@ -393,6 +393,7 @@ pub mod mango_v4 {
|
||||||
impact_quantity: i64,
|
impact_quantity: i64,
|
||||||
group_insurance_fund: bool,
|
group_insurance_fund: bool,
|
||||||
trusted_market: bool,
|
trusted_market: bool,
|
||||||
|
fee_penalty: f32,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
instructions::perp_create_market(
|
instructions::perp_create_market(
|
||||||
ctx,
|
ctx,
|
||||||
|
@ -414,6 +415,7 @@ pub mod mango_v4 {
|
||||||
impact_quantity,
|
impact_quantity,
|
||||||
group_insurance_fund,
|
group_insurance_fund,
|
||||||
trusted_market,
|
trusted_market,
|
||||||
|
fee_penalty,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -435,6 +437,7 @@ pub mod mango_v4 {
|
||||||
impact_quantity_opt: Option<i64>,
|
impact_quantity_opt: Option<i64>,
|
||||||
group_insurance_fund_opt: Option<bool>,
|
group_insurance_fund_opt: Option<bool>,
|
||||||
trusted_market_opt: Option<bool>,
|
trusted_market_opt: Option<bool>,
|
||||||
|
fee_penalty_opt: Option<f32>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
instructions::perp_edit_market(
|
instructions::perp_edit_market(
|
||||||
ctx,
|
ctx,
|
||||||
|
@ -453,6 +456,7 @@ pub mod mango_v4 {
|
||||||
impact_quantity_opt,
|
impact_quantity_opt,
|
||||||
group_insurance_fund_opt,
|
group_insurance_fund_opt,
|
||||||
trusted_market_opt,
|
trusted_market_opt,
|
||||||
|
fee_penalty_opt,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -400,8 +400,7 @@ pub use account_seeds;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::state::{OracleConfig, PerpMarket};
|
use crate::state::PerpMarket;
|
||||||
use anchor_lang::prelude::Pubkey;
|
|
||||||
use fixed::types::I80F48;
|
use fixed::types::I80F48;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
|
@ -416,52 +415,9 @@ mod tests {
|
||||||
pos
|
pos
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_perp_market() -> PerpMarket {
|
|
||||||
return PerpMarket {
|
|
||||||
group: Pubkey::new_unique(),
|
|
||||||
perp_market_index: 0,
|
|
||||||
group_insurance_fund: 0,
|
|
||||||
trusted_market: 0,
|
|
||||||
name: Default::default(),
|
|
||||||
oracle: Pubkey::new_unique(),
|
|
||||||
oracle_config: OracleConfig {
|
|
||||||
conf_filter: I80F48::ZERO,
|
|
||||||
},
|
|
||||||
bids: Pubkey::new_unique(),
|
|
||||||
asks: Pubkey::new_unique(),
|
|
||||||
event_queue: Pubkey::new_unique(),
|
|
||||||
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),
|
|
||||||
liquidation_fee: I80F48::ZERO,
|
|
||||||
maker_fee: I80F48::ZERO,
|
|
||||||
taker_fee: I80F48::ZERO,
|
|
||||||
min_funding: I80F48::ZERO,
|
|
||||||
max_funding: I80F48::ZERO,
|
|
||||||
impact_quantity: 0,
|
|
||||||
long_funding: I80F48::ZERO,
|
|
||||||
short_funding: I80F48::ZERO,
|
|
||||||
funding_last_updated: 0,
|
|
||||||
open_interest: 0,
|
|
||||||
seq_num: 0,
|
|
||||||
fees_accrued: I80F48::ZERO,
|
|
||||||
fees_settled: I80F48::ZERO,
|
|
||||||
bump: 0,
|
|
||||||
base_decimals: 0,
|
|
||||||
reserved: [0; 112],
|
|
||||||
padding0: Default::default(),
|
|
||||||
padding1: Default::default(),
|
|
||||||
padding2: Default::default(),
|
|
||||||
registration_time: 0,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_quote_entry_long_increasing_from_zero() {
|
fn test_quote_entry_long_increasing_from_zero() {
|
||||||
let mut market = create_perp_market();
|
let mut market = PerpMarket::default_for_tests();
|
||||||
let mut pos = create_perp_position(0, 0, 0);
|
let mut pos = create_perp_position(0, 0, 0);
|
||||||
// Go long 10 @ 10
|
// Go long 10 @ 10
|
||||||
pos.change_base_and_quote_positions(&mut market, 10, I80F48::from(-100));
|
pos.change_base_and_quote_positions(&mut market, 10, I80F48::from(-100));
|
||||||
|
@ -472,7 +428,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_quote_entry_short_increasing_from_zero() {
|
fn test_quote_entry_short_increasing_from_zero() {
|
||||||
let mut market = create_perp_market();
|
let mut market = PerpMarket::default_for_tests();
|
||||||
let mut pos = create_perp_position(0, 0, 0);
|
let mut pos = create_perp_position(0, 0, 0);
|
||||||
// Go short 10 @ 10
|
// Go short 10 @ 10
|
||||||
pos.change_base_and_quote_positions(&mut market, -10, I80F48::from(100));
|
pos.change_base_and_quote_positions(&mut market, -10, I80F48::from(100));
|
||||||
|
@ -483,7 +439,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_quote_entry_long_increasing_from_long() {
|
fn test_quote_entry_long_increasing_from_long() {
|
||||||
let mut market = create_perp_market();
|
let mut market = PerpMarket::default_for_tests();
|
||||||
let mut pos = create_perp_position(10, -100, -100);
|
let mut pos = create_perp_position(10, -100, -100);
|
||||||
// Go long 10 @ 30
|
// Go long 10 @ 30
|
||||||
pos.change_base_and_quote_positions(&mut market, 10, I80F48::from(-300));
|
pos.change_base_and_quote_positions(&mut market, 10, I80F48::from(-300));
|
||||||
|
@ -494,7 +450,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_quote_entry_short_increasing_from_short() {
|
fn test_quote_entry_short_increasing_from_short() {
|
||||||
let mut market = create_perp_market();
|
let mut market = PerpMarket::default_for_tests();
|
||||||
let mut pos = create_perp_position(-10, 100, 100);
|
let mut pos = create_perp_position(-10, 100, 100);
|
||||||
// Go short 10 @ 10
|
// Go short 10 @ 10
|
||||||
pos.change_base_and_quote_positions(&mut market, -10, I80F48::from(300));
|
pos.change_base_and_quote_positions(&mut market, -10, I80F48::from(300));
|
||||||
|
@ -505,7 +461,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_quote_entry_long_decreasing_from_short() {
|
fn test_quote_entry_long_decreasing_from_short() {
|
||||||
let mut market = create_perp_market();
|
let mut market = PerpMarket::default_for_tests();
|
||||||
let mut pos = create_perp_position(-10, 100, 100);
|
let mut pos = create_perp_position(-10, 100, 100);
|
||||||
// Go long 5 @ 50
|
// Go long 5 @ 50
|
||||||
pos.change_base_and_quote_positions(&mut market, 5, I80F48::from(-250));
|
pos.change_base_and_quote_positions(&mut market, 5, I80F48::from(-250));
|
||||||
|
@ -516,7 +472,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_quote_entry_short_decreasing_from_long() {
|
fn test_quote_entry_short_decreasing_from_long() {
|
||||||
let mut market = create_perp_market();
|
let mut market = PerpMarket::default_for_tests();
|
||||||
let mut pos = create_perp_position(10, -100, -100);
|
let mut pos = create_perp_position(10, -100, -100);
|
||||||
// Go short 5 @ 50
|
// Go short 5 @ 50
|
||||||
pos.change_base_and_quote_positions(&mut market, -5, I80F48::from(250));
|
pos.change_base_and_quote_positions(&mut market, -5, I80F48::from(250));
|
||||||
|
@ -527,7 +483,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_quote_entry_long_close_with_short() {
|
fn test_quote_entry_long_close_with_short() {
|
||||||
let mut market = create_perp_market();
|
let mut market = PerpMarket::default_for_tests();
|
||||||
let mut pos = create_perp_position(10, -100, -100);
|
let mut pos = create_perp_position(10, -100, -100);
|
||||||
// Go short 10 @ 50
|
// Go short 10 @ 50
|
||||||
pos.change_base_and_quote_positions(&mut market, -10, I80F48::from(250));
|
pos.change_base_and_quote_positions(&mut market, -10, I80F48::from(250));
|
||||||
|
@ -538,7 +494,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_quote_entry_short_close_with_long() {
|
fn test_quote_entry_short_close_with_long() {
|
||||||
let mut market = create_perp_market();
|
let mut market = PerpMarket::default_for_tests();
|
||||||
let mut pos = create_perp_position(-10, 100, 100);
|
let mut pos = create_perp_position(-10, 100, 100);
|
||||||
// Go long 10 @ 50
|
// Go long 10 @ 50
|
||||||
pos.change_base_and_quote_positions(&mut market, 10, I80F48::from(-250));
|
pos.change_base_and_quote_positions(&mut market, 10, I80F48::from(-250));
|
||||||
|
@ -549,7 +505,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_quote_entry_long_close_short_with_overflow() {
|
fn test_quote_entry_long_close_short_with_overflow() {
|
||||||
let mut market = create_perp_market();
|
let mut market = PerpMarket::default_for_tests();
|
||||||
let mut pos = create_perp_position(10, -100, -100);
|
let mut pos = create_perp_position(10, -100, -100);
|
||||||
// Go short 15 @ 20
|
// Go short 15 @ 20
|
||||||
pos.change_base_and_quote_positions(&mut market, -15, I80F48::from(300));
|
pos.change_base_and_quote_positions(&mut market, -15, I80F48::from(300));
|
||||||
|
@ -560,7 +516,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_quote_entry_short_close_long_with_overflow() {
|
fn test_quote_entry_short_close_long_with_overflow() {
|
||||||
let mut market = create_perp_market();
|
let mut market = PerpMarket::default_for_tests();
|
||||||
let mut pos = create_perp_position(-10, 100, 100);
|
let mut pos = create_perp_position(-10, 100, 100);
|
||||||
// Go short 15 @ 20
|
// Go short 15 @ 20
|
||||||
pos.change_base_and_quote_positions(&mut market, 15, I80F48::from(-300));
|
pos.change_base_and_quote_positions(&mut market, 15, I80F48::from(-300));
|
||||||
|
@ -571,7 +527,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_quote_entry_break_even_price() {
|
fn test_quote_entry_break_even_price() {
|
||||||
let mut market = create_perp_market();
|
let mut market = PerpMarket::default_for_tests();
|
||||||
let mut pos = create_perp_position(0, 0, 0);
|
let mut pos = create_perp_position(0, 0, 0);
|
||||||
// Buy 11 @ 10,000
|
// Buy 11 @ 10,000
|
||||||
pos.change_base_and_quote_positions(&mut market, 11, I80F48::from(-11 * 10_000));
|
pos.change_base_and_quote_positions(&mut market, 11, I80F48::from(-11 * 10_000));
|
||||||
|
@ -585,7 +541,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_quote_entry_multiple_and_reversed_changes_return_entry_to_zero() {
|
fn test_quote_entry_multiple_and_reversed_changes_return_entry_to_zero() {
|
||||||
let mut market = create_perp_market();
|
let mut market = PerpMarket::default_for_tests();
|
||||||
let mut pos = create_perp_position(0, 0, 0);
|
let mut pos = create_perp_position(0, 0, 0);
|
||||||
|
|
||||||
// Generate array of random trades
|
// Generate array of random trades
|
||||||
|
|
|
@ -377,6 +377,11 @@ impl<'a> Book<'a> {
|
||||||
apply_fees(market, mango_account, total_quote_lots_taken)?;
|
apply_fees(market, mango_account, total_quote_lots_taken)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IOC orders have a fee penalty applied regardless of match
|
||||||
|
if order_type == OrderType::ImmediateOrCancel {
|
||||||
|
apply_penalty(market, mango_account)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -460,12 +465,24 @@ fn apply_fees(
|
||||||
// risks that fees_accrued is settled to 0 before they apply. It going negative
|
// risks that fees_accrued is settled to 0 before they apply. It going negative
|
||||||
// breaks assumptions.
|
// breaks assumptions.
|
||||||
// The maker fees apply to the maker's account only when the fill event is consumed.
|
// The maker fees apply to the maker's account only when the fill event is consumed.
|
||||||
let maker_fees = taker_quote_native * market.maker_fee;
|
let maker_fees = cm!(taker_quote_native * market.maker_fee);
|
||||||
|
|
||||||
|
let taker_fees = cm!(taker_quote_native * market.taker_fee);
|
||||||
|
|
||||||
let taker_fees = taker_quote_native * market.taker_fee;
|
|
||||||
let perp_account = mango_account.perp_position_mut(market.perp_market_index)?;
|
let perp_account = mango_account.perp_position_mut(market.perp_market_index)?;
|
||||||
perp_account.change_quote_position(-taker_fees);
|
perp_account.change_quote_position(-taker_fees);
|
||||||
market.fees_accrued += taker_fees + maker_fees;
|
cm!(market.fees_accrued += taker_fees + maker_fees);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Applies a fixed penalty fee to the account, and update the market's fees_accrued
|
||||||
|
fn apply_penalty(market: &mut PerpMarket, mango_account: &mut MangoAccountRefMut) -> Result<()> {
|
||||||
|
let perp_account = mango_account.perp_position_mut(market.perp_market_index)?;
|
||||||
|
let fee_penalty = I80F48::from_num(market.fee_penalty);
|
||||||
|
|
||||||
|
perp_account.change_quote_position(-fee_penalty);
|
||||||
|
cm!(market.fees_accrued += fee_penalty);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -375,4 +375,111 @@ mod tests {
|
||||||
match_quote - match_quote * market.taker_fee
|
match_quote - match_quote * market.taker_fee
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fee_penalty_applied_only_on_limit_order() -> Result<()> {
|
||||||
|
let (mut market, oracle_price, mut event_queue, bids, asks) = test_setup(1000.0);
|
||||||
|
let mut book = Book {
|
||||||
|
bids: bids.borrow_mut(),
|
||||||
|
asks: asks.borrow_mut(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let buffer = MangoAccount::default_for_tests().try_to_vec().unwrap();
|
||||||
|
let mut account = MangoAccountValue::from_bytes(&buffer).unwrap();
|
||||||
|
let taker_pk = Pubkey::new_unique();
|
||||||
|
let now_ts = 1000000;
|
||||||
|
|
||||||
|
market.base_lot_size = 1;
|
||||||
|
market.quote_lot_size = 1;
|
||||||
|
market.taker_fee = I80F48::from_num(0.01);
|
||||||
|
market.fee_penalty = 5.0;
|
||||||
|
account.ensure_perp_position(market.perp_market_index, 0)?;
|
||||||
|
|
||||||
|
// Passive order
|
||||||
|
book.new_order(
|
||||||
|
Side::Ask,
|
||||||
|
&mut market,
|
||||||
|
&mut event_queue,
|
||||||
|
oracle_price,
|
||||||
|
&mut account.borrow_mut(),
|
||||||
|
&taker_pk,
|
||||||
|
1000,
|
||||||
|
2,
|
||||||
|
i64::MAX,
|
||||||
|
OrderType::Limit,
|
||||||
|
0,
|
||||||
|
43,
|
||||||
|
now_ts,
|
||||||
|
u8::MAX,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Partial taker
|
||||||
|
book.new_order(
|
||||||
|
Side::Bid,
|
||||||
|
&mut market,
|
||||||
|
&mut event_queue,
|
||||||
|
oracle_price,
|
||||||
|
&mut account.borrow_mut(),
|
||||||
|
&taker_pk,
|
||||||
|
1000,
|
||||||
|
1,
|
||||||
|
i64::MAX,
|
||||||
|
OrderType::Limit,
|
||||||
|
0,
|
||||||
|
43,
|
||||||
|
now_ts,
|
||||||
|
u8::MAX,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let pos = account.perp_position(market.perp_market_index)?;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
pos.quote_position_native().round(),
|
||||||
|
I80F48::from_num(-10),
|
||||||
|
"Regular fees applied on limit order"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
market.fees_accrued.round(),
|
||||||
|
I80F48::from_num(10),
|
||||||
|
"Fees moved to market"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Full taker
|
||||||
|
book.new_order(
|
||||||
|
Side::Bid,
|
||||||
|
&mut market,
|
||||||
|
&mut event_queue,
|
||||||
|
oracle_price,
|
||||||
|
&mut account.borrow_mut(),
|
||||||
|
&taker_pk,
|
||||||
|
1000,
|
||||||
|
1,
|
||||||
|
i64::MAX,
|
||||||
|
OrderType::ImmediateOrCancel,
|
||||||
|
0,
|
||||||
|
43,
|
||||||
|
now_ts,
|
||||||
|
u8::MAX,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let pos = account.perp_position(market.perp_market_index)?;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
pos.quote_position_native().round(),
|
||||||
|
I80F48::from_num(-25), // -10 - 5
|
||||||
|
"Regular fees + fixed penalty applied on IOC order"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
market.fees_accrued.round(),
|
||||||
|
I80F48::from_num(25), // 10 + 5
|
||||||
|
"Fees moved to market"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,12 +99,30 @@ pub struct PerpMarket {
|
||||||
/// Fees settled in native quote currency
|
/// Fees settled in native quote currency
|
||||||
pub fees_settled: I80F48,
|
pub fees_settled: I80F48,
|
||||||
|
|
||||||
pub reserved: [u8; 112],
|
pub fee_penalty: f32,
|
||||||
|
|
||||||
|
pub reserved: [u8; 108],
|
||||||
}
|
}
|
||||||
|
|
||||||
const_assert_eq!(
|
const_assert_eq!(
|
||||||
size_of::<PerpMarket>(),
|
size_of::<PerpMarket>(),
|
||||||
32 + 2 + 2 + 4 + 16 + 32 + 16 + 32 * 3 + 8 * 2 + 16 * 12 + 8 * 2 + 8 * 2 + 16 + 2 + 6 + 8 + 112
|
32 + 2
|
||||||
|
+ 2
|
||||||
|
+ 4
|
||||||
|
+ 16
|
||||||
|
+ 32
|
||||||
|
+ 16
|
||||||
|
+ 32 * 3
|
||||||
|
+ 8 * 2
|
||||||
|
+ 16 * 12
|
||||||
|
+ 8 * 2
|
||||||
|
+ 8 * 2
|
||||||
|
+ 16
|
||||||
|
+ 2
|
||||||
|
+ 6
|
||||||
|
+ 8
|
||||||
|
+ 4
|
||||||
|
+ 108
|
||||||
);
|
);
|
||||||
const_assert_eq!(size_of::<PerpMarket>() % 8, 0);
|
const_assert_eq!(size_of::<PerpMarket>() % 8, 0);
|
||||||
|
|
||||||
|
@ -225,4 +243,49 @@ impl PerpMarket {
|
||||||
self.short_funding += socialized_loss;
|
self.short_funding += socialized_loss;
|
||||||
Ok(socialized_loss)
|
Ok(socialized_loss)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates default market for tests
|
||||||
|
pub fn default_for_tests() -> PerpMarket {
|
||||||
|
PerpMarket {
|
||||||
|
group: Pubkey::new_unique(),
|
||||||
|
perp_market_index: 0,
|
||||||
|
name: Default::default(),
|
||||||
|
oracle: Pubkey::new_unique(),
|
||||||
|
oracle_config: OracleConfig {
|
||||||
|
conf_filter: I80F48::ZERO,
|
||||||
|
},
|
||||||
|
bids: Pubkey::new_unique(),
|
||||||
|
asks: Pubkey::new_unique(),
|
||||||
|
event_queue: Pubkey::new_unique(),
|
||||||
|
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),
|
||||||
|
liquidation_fee: I80F48::ZERO,
|
||||||
|
maker_fee: I80F48::ZERO,
|
||||||
|
taker_fee: I80F48::ZERO,
|
||||||
|
min_funding: I80F48::ZERO,
|
||||||
|
max_funding: I80F48::ZERO,
|
||||||
|
impact_quantity: 0,
|
||||||
|
long_funding: I80F48::ZERO,
|
||||||
|
short_funding: I80F48::ZERO,
|
||||||
|
funding_last_updated: 0,
|
||||||
|
open_interest: 0,
|
||||||
|
seq_num: 0,
|
||||||
|
fees_accrued: I80F48::ZERO,
|
||||||
|
fees_settled: I80F48::ZERO,
|
||||||
|
bump: 0,
|
||||||
|
base_decimals: 0,
|
||||||
|
reserved: [0; 108],
|
||||||
|
padding0: Default::default(),
|
||||||
|
padding1: Default::default(),
|
||||||
|
padding2: Default::default(),
|
||||||
|
registration_time: 0,
|
||||||
|
fee_penalty: 0.0,
|
||||||
|
trusted_market: 0,
|
||||||
|
group_insurance_fund: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2143,6 +2143,7 @@ pub struct PerpCreateMarketInstruction {
|
||||||
pub taker_fee: f32,
|
pub taker_fee: f32,
|
||||||
pub group_insurance_fund: bool,
|
pub group_insurance_fund: bool,
|
||||||
pub trusted_market: bool,
|
pub trusted_market: bool,
|
||||||
|
pub fee_penalty: f32,
|
||||||
}
|
}
|
||||||
impl PerpCreateMarketInstruction {
|
impl PerpCreateMarketInstruction {
|
||||||
pub async fn with_new_book_and_queue(
|
pub async fn with_new_book_and_queue(
|
||||||
|
@ -2195,6 +2196,7 @@ impl ClientInstruction for PerpCreateMarketInstruction {
|
||||||
base_decimals: self.base_decimals,
|
base_decimals: self.base_decimals,
|
||||||
group_insurance_fund: self.group_insurance_fund,
|
group_insurance_fund: self.group_insurance_fund,
|
||||||
trusted_market: self.trusted_market,
|
trusted_market: self.trusted_market,
|
||||||
|
fee_penalty: self.fee_penalty,
|
||||||
};
|
};
|
||||||
|
|
||||||
let perp_market = Pubkey::find_program_address(
|
let perp_market = Pubkey::find_program_address(
|
||||||
|
|
|
@ -1330,6 +1330,7 @@ export class MangoClient {
|
||||||
liquidationFee: number,
|
liquidationFee: number,
|
||||||
makerFee: number,
|
makerFee: number,
|
||||||
takerFee: number,
|
takerFee: number,
|
||||||
|
feePenalty: number,
|
||||||
minFunding: number,
|
minFunding: number,
|
||||||
maxFunding: number,
|
maxFunding: number,
|
||||||
impactQuantity: number,
|
impactQuantity: number,
|
||||||
|
@ -1364,6 +1365,7 @@ export class MangoClient {
|
||||||
new BN(impactQuantity),
|
new BN(impactQuantity),
|
||||||
groupInsuranceFund,
|
groupInsuranceFund,
|
||||||
trustedMarket,
|
trustedMarket,
|
||||||
|
feePenalty
|
||||||
)
|
)
|
||||||
.accounts({
|
.accounts({
|
||||||
group: group.publicKey,
|
group: group.publicKey,
|
||||||
|
@ -1430,6 +1432,7 @@ export class MangoClient {
|
||||||
liquidationFee: number,
|
liquidationFee: number,
|
||||||
makerFee: number,
|
makerFee: number,
|
||||||
takerFee: number,
|
takerFee: number,
|
||||||
|
feePenalty: number,
|
||||||
minFunding: number,
|
minFunding: number,
|
||||||
maxFunding: number,
|
maxFunding: number,
|
||||||
impactQuantity: number,
|
impactQuantity: number,
|
||||||
|
@ -1459,6 +1462,7 @@ export class MangoClient {
|
||||||
new BN(impactQuantity),
|
new BN(impactQuantity),
|
||||||
groupInsuranceFund,
|
groupInsuranceFund,
|
||||||
trustedMarket,
|
trustedMarket,
|
||||||
|
feePenalty
|
||||||
)
|
)
|
||||||
.accounts({
|
.accounts({
|
||||||
group: group.publicKey,
|
group: group.publicKey,
|
||||||
|
|
|
@ -2315,6 +2315,10 @@ export type MangoV4 = {
|
||||||
{
|
{
|
||||||
"name": "trustedMarket",
|
"name": "trustedMarket",
|
||||||
"type": "bool"
|
"type": "bool"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "feePenalty",
|
||||||
|
"type": "f32"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -2429,6 +2433,12 @@ export type MangoV4 = {
|
||||||
"type": {
|
"type": {
|
||||||
"option": "bool"
|
"option": "bool"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "feePenaltyOpt",
|
||||||
|
"type": {
|
||||||
|
"option": "f32"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -4014,12 +4024,16 @@ export type MangoV4 = {
|
||||||
"defined": "I80F48"
|
"defined": "I80F48"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "feePenalty",
|
||||||
|
"type": "f32"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "reserved",
|
"name": "reserved",
|
||||||
"type": {
|
"type": {
|
||||||
"array": [
|
"array": [
|
||||||
"u8",
|
"u8",
|
||||||
112
|
108
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8402,6 +8416,10 @@ export const IDL: MangoV4 = {
|
||||||
{
|
{
|
||||||
"name": "trustedMarket",
|
"name": "trustedMarket",
|
||||||
"type": "bool"
|
"type": "bool"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "feePenalty",
|
||||||
|
"type": "f32"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -8516,6 +8534,12 @@ export const IDL: MangoV4 = {
|
||||||
"type": {
|
"type": {
|
||||||
"option": "bool"
|
"option": "bool"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "feePenaltyOpt",
|
||||||
|
"type": {
|
||||||
|
"option": "f32"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -10101,12 +10125,16 @@ export const IDL: MangoV4 = {
|
||||||
"defined": "I80F48"
|
"defined": "I80F48"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "feePenalty",
|
||||||
|
"type": "f32"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "reserved",
|
"name": "reserved",
|
||||||
"type": {
|
"type": {
|
||||||
"array": [
|
"array": [
|
||||||
"u8",
|
"u8",
|
||||||
112
|
108
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue