diff --git a/programs/mango-v4/src/instructions/perp_settle_fees.rs b/programs/mango-v4/src/instructions/perp_settle_fees.rs index e13d79592..ba85cf834 100644 --- a/programs/mango-v4/src/instructions/perp_settle_fees.rs +++ b/programs/mango-v4/src/instructions/perp_settle_fees.rs @@ -58,7 +58,7 @@ pub fn perp_settle_fees(ctx: Context, max_settle_amount: I80F48) // Calculate PnL for each account let base_native = perp_position.base_position_native(&perp_market); - let pnl: I80F48 = cm!(perp_position.quote_position_native + base_native * oracle_price); + let pnl: I80F48 = cm!(perp_position.quote_position_native() + base_native * oracle_price); // Account perp position must have a loss to be able to settle against the fee account require!(pnl.is_negative(), MangoError::ProfitabilityMismatch); @@ -72,7 +72,7 @@ pub fn perp_settle_fees(ctx: Context, max_settle_amount: I80F48) .abs() .min(perp_market.fees_accrued.abs()) .min(max_settle_amount); - perp_position.quote_position_native = cm!(perp_position.quote_position_native + settlement); + perp_position.change_quote_position(settlement); perp_market.fees_accrued = cm!(perp_market.fees_accrued - settlement); // Update the account's net_settled with the new PnL diff --git a/programs/mango-v4/src/instructions/perp_settle_pnl.rs b/programs/mango-v4/src/instructions/perp_settle_pnl.rs index 14442267b..4ba00a158 100644 --- a/programs/mango-v4/src/instructions/perp_settle_pnl.rs +++ b/programs/mango-v4/src/instructions/perp_settle_pnl.rs @@ -64,8 +64,8 @@ pub fn perp_settle_pnl(ctx: Context, max_settle_amount: I80F48) - perp_market.oracle_price(&AccountInfoRef::borrow(ctx.accounts.oracle.as_ref())?)?; // Fetch perp positions for accounts - let mut a_perp_position = account_a.perp_position_mut(perp_market.perp_market_index)?; - let mut b_perp_position = account_b.perp_position_mut(perp_market.perp_market_index)?; + let a_perp_position = account_a.perp_position_mut(perp_market.perp_market_index)?; + let b_perp_position = account_b.perp_position_mut(perp_market.perp_market_index)?; // Settle funding before settling any PnL a_perp_position.settle_funding(&perp_market); @@ -74,8 +74,8 @@ pub fn perp_settle_pnl(ctx: Context, max_settle_amount: I80F48) - // Calculate PnL for each account let a_base_native = a_perp_position.base_position_native(&perp_market); let b_base_native = b_perp_position.base_position_native(&perp_market); - let a_pnl: I80F48 = cm!(a_perp_position.quote_position_native + a_base_native * oracle_price); - let b_pnl: I80F48 = cm!(b_perp_position.quote_position_native + b_base_native * oracle_price); + let a_pnl: I80F48 = cm!(a_perp_position.quote_position_native() + a_base_native * oracle_price); + let b_pnl: I80F48 = cm!(b_perp_position.quote_position_native() + b_base_native * oracle_price); // Account A must be profitable, and B must be unprofitable // PnL must be opposite signs for there to be a settlement @@ -84,8 +84,8 @@ pub fn perp_settle_pnl(ctx: Context, max_settle_amount: I80F48) - // Settle for the maximum possible capped to max_settle_amount let settlement = a_pnl.abs().min(b_pnl.abs()).min(max_settle_amount); - cm!(a_perp_position.quote_position_native -= settlement); - cm!(b_perp_position.quote_position_native += settlement); + a_perp_position.change_quote_position(-settlement); + b_perp_position.change_quote_position(settlement); // Update the account's net_settled with the new PnL let settlement_i64 = settlement.checked_to_num::().unwrap(); diff --git a/programs/mango-v4/src/logs.rs b/programs/mango-v4/src/logs.rs index a65187439..366651eda 100644 --- a/programs/mango-v4/src/logs.rs +++ b/programs/mango-v4/src/logs.rs @@ -18,8 +18,8 @@ pub fn emit_perp_balances( mango_group, mango_account, market_index, - base_position: pp.base_position_lots, - quote_position: pp.quote_position_native.to_bits(), + base_position: pp.base_position_lots(), + quote_position: pp.quote_position_native().to_bits(), long_settled_funding: pp.long_settled_funding.to_bits(), short_settled_funding: pp.short_settled_funding.to_bits(), price, diff --git a/programs/mango-v4/src/state/health.rs b/programs/mango-v4/src/state/health.rs index f01cf5d56..6eb11e414 100644 --- a/programs/mango-v4/src/state/health.rs +++ b/programs/mango-v4/src/state/health.rs @@ -498,14 +498,14 @@ impl PerpInfo { let base_info = &token_infos[base_index]; let base_lot_size = I80F48::from(perp_market.base_lot_size); - let base_lots = cm!(perp_position.base_position_lots + perp_position.taker_base_lots); + let base_lots = cm!(perp_position.base_position_lots() + perp_position.taker_base_lots); let unsettled_funding = perp_position.unsettled_funding(&perp_market); let taker_quote = I80F48::from(cm!( perp_position.taker_quote_lots * perp_market.quote_lot_size )); let quote_current = - cm!(perp_position.quote_position_native - unsettled_funding + taker_quote); + cm!(perp_position.quote_position_native() - unsettled_funding + taker_quote); // Two scenarios: // 1. The price goes low and all bids execute, converting to base. @@ -1226,8 +1226,7 @@ mod tests { let mut perp1 = mock_perp_market(group, 9, 4, 0.2, 0.1); let perpaccount = account.ensure_perp_position(9).unwrap().0; - perpaccount.base_position_lots = 3; - perpaccount.quote_position_native = -I80F48::from(310u16); + perpaccount.change_base_and_quote_positions(perp1.data(), 3, -I80F48::from(310u16)); perpaccount.bids_base_lots = 7; perpaccount.asks_base_lots = 11; perpaccount.taker_base_lots = 1; @@ -1398,8 +1397,11 @@ mod tests { let mut perp1 = mock_perp_market(group, 9, 4, 0.2, 0.1); let perpaccount = account.ensure_perp_position(9).unwrap().0; - perpaccount.base_position_lots = testcase.perp1.0; - perpaccount.quote_position_native = I80F48::from(testcase.perp1.1); + perpaccount.change_base_and_quote_positions( + perp1.data(), + testcase.perp1.0, + I80F48::from(testcase.perp1.1), + ); perpaccount.bids_base_lots = testcase.perp1.2; perpaccount.asks_base_lots = testcase.perp1.3; @@ -1708,8 +1710,7 @@ mod tests { let mut perp1 = mock_perp_market(group, 9, 1, 0.2, 0.1); perp1.data().long_funding = I80F48::from_num(10.1); let perpaccount = account.ensure_perp_position(9).unwrap().0; - perpaccount.base_position_lots = 10; // 100 base native - perpaccount.quote_position_native = I80F48::from(-110); + perpaccount.change_base_and_quote_positions(perp1.data(), 10, I80F48::from(-110)); perpaccount.long_settled_funding = I80F48::from_num(10.0); let ais = vec![ diff --git a/programs/mango-v4/src/state/mango_account.rs b/programs/mango-v4/src/state/mango_account.rs index 9d1c49859..b385bd858 100644 --- a/programs/mango-v4/src/state/mango_account.rs +++ b/programs/mango-v4/src/state/mango_account.rs @@ -712,10 +712,9 @@ impl< if raw_index_opt.is_none() { raw_index_opt = self.all_perp_positions().position(|p| !p.is_active()); if let Some(raw_index) = raw_index_opt { - *(self.perp_position_mut_by_raw_index(raw_index)) = PerpPosition { - market_index: perp_market_index, - ..Default::default() - }; + let perp_position = self.perp_position_mut_by_raw_index(raw_index); + *perp_position = PerpPosition::default(); + perp_position.market_index = perp_market_index; } } if let Some(raw_index) = raw_index_opt { @@ -796,18 +795,13 @@ impl< let side = fill.taker_side.invert_side(); let (base_change, quote_change) = fill.base_quote_change(side); - pa.change_base_and_entry_positions(perp_market, base_change, quote_change); - let quote = I80F48::from_num( - perp_market - .quote_lot_size - .checked_mul(quote_change) - .unwrap(), - ); - let fees = quote.abs() * fill.maker_fee; + let quote = cm!(I80F48::from(perp_market.quote_lot_size) * I80F48::from(quote_change)); + let fees = cm!(quote.abs() * fill.maker_fee); if !fill.market_fees_applied { - perp_market.fees_accrued += fees; + cm!(perp_market.fees_accrued += fees); } - pa.quote_position_native = pa.quote_position_native.checked_add(quote - fees).unwrap(); + let quote_change_native = cm!(quote - fees); + pa.change_base_and_quote_positions(perp_market, base_change, quote_change_native); if fill.maker_out { self.remove_perp_order(fill.maker_slot as usize, base_change.abs()) @@ -836,12 +830,11 @@ impl< let (base_change, quote_change) = fill.base_quote_change(fill.taker_side); pa.remove_taker_trade(base_change, quote_change); - pa.change_base_and_entry_positions(perp_market, base_change, quote_change); - let quote = I80F48::from_num(perp_market.quote_lot_size * quote_change); - // fees are assessed at time of trade; no need to assess fees here + let quote_change_native = + cm!(I80F48::from(perp_market.quote_lot_size) * I80F48::from(quote_change)); + pa.change_base_and_quote_positions(perp_market, base_change, quote_change_native); - pa.quote_position_native += quote; Ok(()) } diff --git a/programs/mango-v4/src/state/mango_account_components.rs b/programs/mango-v4/src/state/mango_account_components.rs index b4069bfbf..d5f249f3b 100644 --- a/programs/mango-v4/src/state/mango_account_components.rs +++ b/programs/mango-v4/src/state/mango_account_components.rs @@ -153,10 +153,10 @@ pub struct PerpPosition { pub padding: [u8; 6], /// Active position size, measured in base lots - pub base_position_lots: i64, + base_position_lots: i64, /// Active position in quote (conversation rate is that of the time the order was settled) /// measured in native quote - pub quote_position_native: I80F48, + quote_position_native: I80F48, /// Tracks what the position is to calculate average entry & break even price pub quote_entry_native: i64, @@ -240,8 +240,16 @@ impl PerpPosition { I80F48::from(cm!(self.base_position_lots * market.base_lot_size)) } + pub fn base_position_lots(&self) -> i64 { + self.base_position_lots + } + + pub fn quote_position_native(&self) -> I80F48 { + self.quote_position_native + } + /// This assumes settle_funding was already called - pub fn change_base_position(&mut self, perp_market: &mut PerpMarket, base_change: i64) { + fn change_base_position(&mut self, perp_market: &mut PerpMarket, base_change: i64) { let start = self.base_position_lots; self.base_position_lots += base_change; perp_market.open_interest += self.base_position_lots.abs() - start.abs(); @@ -271,25 +279,24 @@ impl PerpPosition { } /// Update the quote entry position - pub fn change_quote_entry(&mut self, base_change: i64, quote_change: i64) { + fn update_entry_price(&mut self, base_change: i64, quote_change_native: i64) { if base_change == 0 { return; } let old_position = self.base_position_lots; let is_increasing = old_position == 0 || old_position.signum() == base_change.signum(); - cm!(self.quote_running_native += quote_change); + cm!(self.quote_running_native += quote_change_native); match is_increasing { true => { - cm!(self.quote_entry_native += quote_change); + cm!(self.quote_entry_native += quote_change_native); } false => { let new_position = cm!(old_position + base_change); let changes_side = old_position.signum() == -new_position.signum(); self.quote_entry_native = if changes_side { - cm!( - ((new_position as f64) * (quote_change as f64) / (base_change as f64)) - .round() - ) as i64 + cm!(((new_position as f64) * (quote_change_native as f64) + / (base_change as f64)) + .round()) as i64 } else { let remaining_frac = (1f64 - (base_change.abs() as f64) / (old_position.abs() as f64)).max(0f64); @@ -301,14 +308,22 @@ impl PerpPosition { } /// Change the base and quote positions as the result of a trade - pub fn change_base_and_entry_positions( + pub fn change_base_and_quote_positions( &mut self, perp_market: &mut PerpMarket, base_change: i64, - quote_change: i64, + quote_change_native: I80F48, ) { - self.change_quote_entry(base_change, quote_change); + self.update_entry_price( + base_change, + quote_change_native.round().checked_to_num().unwrap(), + ); self.change_base_position(perp_market, base_change); + self.change_quote_position(quote_change_native); + } + + pub fn change_quote_position(&mut self, quote_change_native: I80F48) { + cm!(self.quote_position_native += quote_change_native); } /// Calculate the average entry price of the position @@ -439,7 +454,7 @@ mod tests { let mut market = create_perp_market(); let mut pos = create_perp_position(0, 0, 0); // Go long 10 @ 10 - pos.change_base_and_entry_positions(&mut market, 10, -100); + pos.change_base_and_quote_positions(&mut market, 10, I80F48::from(-100)); assert_eq!(pos.quote_entry_native, -100); assert_eq!(pos.quote_running_native, -100); assert_eq!(pos.avg_entry_price(), I80F48::from(10)); @@ -450,7 +465,7 @@ mod tests { let mut market = create_perp_market(); let mut pos = create_perp_position(0, 0, 0); // Go short 10 @ 10 - pos.change_base_and_entry_positions(&mut market, -10, 100); + pos.change_base_and_quote_positions(&mut market, -10, I80F48::from(100)); assert_eq!(pos.quote_entry_native, 100); assert_eq!(pos.quote_running_native, 100); assert_eq!(pos.avg_entry_price(), I80F48::from(10)); @@ -461,7 +476,7 @@ mod tests { let mut market = create_perp_market(); let mut pos = create_perp_position(10, -100, -100); // Go long 10 @ 30 - pos.change_base_and_entry_positions(&mut market, 10, -300); + pos.change_base_and_quote_positions(&mut market, 10, I80F48::from(-300)); assert_eq!(pos.quote_entry_native, -400); assert_eq!(pos.quote_running_native, -400); assert_eq!(pos.avg_entry_price(), I80F48::from(20)); @@ -472,7 +487,7 @@ mod tests { let mut market = create_perp_market(); let mut pos = create_perp_position(-10, 100, 100); // Go short 10 @ 10 - pos.change_base_and_entry_positions(&mut market, -10, 300); + pos.change_base_and_quote_positions(&mut market, -10, I80F48::from(300)); assert_eq!(pos.quote_entry_native, 400); assert_eq!(pos.quote_running_native, 400); assert_eq!(pos.avg_entry_price(), I80F48::from(20)); @@ -483,7 +498,7 @@ mod tests { let mut market = create_perp_market(); let mut pos = create_perp_position(-10, 100, 100); // Go long 5 @ 50 - pos.change_base_and_entry_positions(&mut market, 5, -250); + pos.change_base_and_quote_positions(&mut market, 5, I80F48::from(-250)); assert_eq!(pos.quote_entry_native, 50); assert_eq!(pos.quote_running_native, -150); assert_eq!(pos.avg_entry_price(), I80F48::from(10)); // Entry price remains the same when decreasing @@ -494,7 +509,7 @@ mod tests { let mut market = create_perp_market(); let mut pos = create_perp_position(10, -100, -100); // Go short 5 @ 50 - pos.change_base_and_entry_positions(&mut market, -5, 250); + pos.change_base_and_quote_positions(&mut market, -5, I80F48::from(250)); assert_eq!(pos.quote_entry_native, -50); assert_eq!(pos.quote_running_native, 150); assert_eq!(pos.avg_entry_price(), I80F48::from(10)); // Entry price remains the same when decreasing @@ -505,7 +520,7 @@ mod tests { let mut market = create_perp_market(); let mut pos = create_perp_position(10, -100, -100); // Go short 10 @ 50 - pos.change_base_and_entry_positions(&mut market, -10, 250); + pos.change_base_and_quote_positions(&mut market, -10, I80F48::from(250)); assert_eq!(pos.quote_entry_native, 0); assert_eq!(pos.quote_running_native, 150); assert_eq!(pos.avg_entry_price(), I80F48::from(0)); // Entry price zero when no position @@ -516,7 +531,7 @@ mod tests { let mut market = create_perp_market(); let mut pos = create_perp_position(-10, 100, 100); // Go long 10 @ 50 - pos.change_base_and_entry_positions(&mut market, 10, -250); + pos.change_base_and_quote_positions(&mut market, 10, I80F48::from(-250)); assert_eq!(pos.quote_entry_native, 0); assert_eq!(pos.quote_running_native, -150); assert_eq!(pos.avg_entry_price(), I80F48::from(0)); // Entry price zero when no position @@ -527,7 +542,7 @@ mod tests { let mut market = create_perp_market(); let mut pos = create_perp_position(10, -100, -100); // Go short 15 @ 20 - pos.change_base_and_entry_positions(&mut market, -15, 300); + pos.change_base_and_quote_positions(&mut market, -15, I80F48::from(300)); assert_eq!(pos.quote_entry_native, 100); assert_eq!(pos.quote_running_native, 200); assert_eq!(pos.avg_entry_price(), I80F48::from(20)); // Entry price zero when no position @@ -538,7 +553,7 @@ mod tests { let mut market = create_perp_market(); let mut pos = create_perp_position(-10, 100, 100); // Go short 15 @ 20 - pos.change_base_and_entry_positions(&mut market, 15, -300); + pos.change_base_and_quote_positions(&mut market, 15, I80F48::from(-300)); assert_eq!(pos.quote_entry_native, -100); assert_eq!(pos.quote_running_native, -200); assert_eq!(pos.avg_entry_price(), I80F48::from(20)); // Entry price zero when no position @@ -549,9 +564,9 @@ mod tests { let mut market = create_perp_market(); let mut pos = create_perp_position(0, 0, 0); // Buy 11 @ 10,000 - pos.change_base_and_entry_positions(&mut market, 11, -11 * 10_000); + pos.change_base_and_quote_positions(&mut market, 11, I80F48::from(-11 * 10_000)); // Sell 1 @ 12,000 - pos.change_base_and_entry_positions(&mut market, -1, 12_000); + pos.change_base_and_quote_positions(&mut market, -1, I80F48::from(12_000)); assert_eq!(pos.quote_entry_native, -10 * 10_000); assert_eq!(pos.quote_running_native, -98_000); assert_eq!(pos.base_position_lots, 10); @@ -574,7 +589,7 @@ mod tests { } // Apply all of the trades going forward trades.iter().for_each(|[qty, quote]| { - pos.change_base_and_entry_positions(&mut market, *qty, *quote); + pos.change_base_and_quote_positions(&mut market, *qty, I80F48::from(*quote)); }); // base_position should be sum of all base quantities assert_eq!( @@ -583,7 +598,7 @@ mod tests { ); // Reverse out all the trades trades.iter().for_each(|[qty, quote]| { - pos.change_base_and_entry_positions(&mut market, -*qty, -*quote); + pos.change_base_and_quote_positions(&mut market, -*qty, I80F48::from(-*quote)); }); // base position should be 0 assert_eq!(pos.base_position_lots, 0); diff --git a/programs/mango-v4/src/state/orderbook/book.rs b/programs/mango-v4/src/state/orderbook/book.rs index 95c35d662..f64043b31 100644 --- a/programs/mango-v4/src/state/orderbook/book.rs +++ b/programs/mango-v4/src/state/orderbook/book.rs @@ -468,7 +468,7 @@ fn apply_fees( let perp_account = mango_account .ensure_perp_position(market.perp_market_index)? .0; - perp_account.quote_position_native -= taker_fees; + perp_account.change_quote_position(-taker_fees); market.fees_accrued += taker_fees + maker_fees; Ok(()) diff --git a/programs/mango-v4/src/state/orderbook/mod.rs b/programs/mango-v4/src/state/orderbook/mod.rs index 92553011c..ca6d0d798 100644 --- a/programs/mango-v4/src/state/orderbook/mod.rs +++ b/programs/mango-v4/src/state/orderbook/mod.rs @@ -247,11 +247,11 @@ mod tests { assert_eq!(maker.perp_position_by_raw_index(0).asks_base_lots, 0); assert_eq!(maker.perp_position_by_raw_index(0).taker_base_lots, 0); assert_eq!(maker.perp_position_by_raw_index(0).taker_quote_lots, 0); - assert_eq!(maker.perp_position_by_raw_index(0).base_position_lots, 0); + assert_eq!(maker.perp_position_by_raw_index(0).base_position_lots(), 0); assert_eq!( maker .perp_position_by_raw_index(0) - .quote_position_native + .quote_position_native() .to_num::(), 0 ); @@ -305,9 +305,9 @@ mod tests { taker.perp_position_by_raw_index(0).taker_quote_lots, match_quantity * price ); - assert_eq!(taker.perp_position_by_raw_index(0).base_position_lots, 0); + assert_eq!(taker.perp_position_by_raw_index(0).base_position_lots(), 0); assert_eq!( - taker.perp_position_by_raw_index(0).quote_position_native, + taker.perp_position_by_raw_index(0).quote_position_native(), -match_quote * market.taker_fee ); @@ -343,11 +343,11 @@ mod tests { assert_eq!(maker.perp_position_by_raw_index(0).taker_base_lots, 0); assert_eq!(maker.perp_position_by_raw_index(0).taker_quote_lots, 0); assert_eq!( - maker.perp_position_by_raw_index(0).base_position_lots, + maker.perp_position_by_raw_index(0).base_position_lots(), match_quantity ); assert_eq!( - maker.perp_position_by_raw_index(0).quote_position_native, + maker.perp_position_by_raw_index(0).quote_position_native(), -match_quote - match_quote * market.maker_fee ); @@ -356,11 +356,11 @@ mod tests { assert_eq!(taker.perp_position_by_raw_index(0).taker_base_lots, 0); assert_eq!(taker.perp_position_by_raw_index(0).taker_quote_lots, 0); assert_eq!( - taker.perp_position_by_raw_index(0).base_position_lots, + taker.perp_position_by_raw_index(0).base_position_lots(), -match_quantity ); assert_eq!( - taker.perp_position_by_raw_index(0).quote_position_native, + taker.perp_position_by_raw_index(0).quote_position_native(), match_quote - match_quote * market.taker_fee ); } diff --git a/programs/mango-v4/tests/program_test/utils.rs b/programs/mango-v4/tests/program_test/utils.rs index b2aed5a87..24f8d50c0 100644 --- a/programs/mango-v4/tests/program_test/utils.rs +++ b/programs/mango-v4/tests/program_test/utils.rs @@ -88,8 +88,8 @@ pub fn get_pnl_native( ) -> I80F48 { let contract_size = perp_market.base_lot_size; let new_quote_pos = - I80F48::from_num(-perp_position.base_position_lots * contract_size) * oracle_price; - perp_position.quote_position_native - new_quote_pos + I80F48::from_num(-perp_position.base_position_lots() * contract_size) * oracle_price; + perp_position.quote_position_native() - new_quote_pos } pub fn assert_mango_error( diff --git a/programs/mango-v4/tests/test_perp.rs b/programs/mango-v4/tests/test_perp.rs index e4b4d4095..f10bd6918 100644 --- a/programs/mango-v4/tests/test_perp.rs +++ b/programs/mango-v4/tests/test_perp.rs @@ -341,12 +341,12 @@ async fn test_perp() -> Result<(), TransportError> { .unwrap(); let mango_account_0 = solana.get_account::(account_0).await; - assert_eq!(mango_account_0.perps[0].base_position_lots, 1); - assert!(mango_account_0.perps[0].quote_position_native < -100.019); + assert_eq!(mango_account_0.perps[0].base_position_lots(), 1); + assert!(mango_account_0.perps[0].quote_position_native() < -100.019); let mango_account_1 = solana.get_account::(account_1).await; - assert_eq!(mango_account_1.perps[0].base_position_lots, -1); - assert_eq!(mango_account_1.perps[0].quote_position_native, 100); + assert_eq!(mango_account_1.perps[0].base_position_lots(), -1); + assert_eq!(mango_account_1.perps[0].quote_position_native(), 100); send_tx( solana, diff --git a/programs/mango-v4/tests/test_perp_settle.rs b/programs/mango-v4/tests/test_perp_settle.rs index 2bd94f027..a36d9afa2 100644 --- a/programs/mango-v4/tests/test_perp_settle.rs +++ b/programs/mango-v4/tests/test_perp_settle.rs @@ -302,13 +302,13 @@ async fn test_perp_settle_pnl() -> Result<(), TransportError> { let mango_account_0 = solana.get_account::(account_0).await; let mango_account_1 = solana.get_account::(account_1).await; - assert_eq!(mango_account_0.perps[0].base_position_lots, 1); - assert_eq!(mango_account_1.perps[0].base_position_lots, -1); + assert_eq!(mango_account_0.perps[0].base_position_lots(), 1); + assert_eq!(mango_account_1.perps[0].base_position_lots(), -1); assert_eq!( - mango_account_0.perps[0].quote_position_native.round(), + mango_account_0.perps[0].quote_position_native().round(), -100_020 ); - assert_eq!(mango_account_1.perps[0].quote_position_native, 100_000); + assert_eq!(mango_account_1.perps[0].quote_position_native(), 100_000); } // Bank must be valid for quote currency @@ -545,21 +545,23 @@ async fn test_perp_settle_pnl() -> Result<(), TransportError> { let mango_account_1 = solana.get_account::(account_1).await; assert_eq!( - mango_account_0.perps[0].base_position_lots, 1, + mango_account_0.perps[0].base_position_lots(), + 1, "base position unchanged for account 0" ); assert_eq!( - mango_account_1.perps[0].base_position_lots, -1, + mango_account_1.perps[0].base_position_lots(), + -1, "base position unchanged for account 1" ); assert_eq!( - mango_account_0.perps[0].quote_position_native.round(), + mango_account_0.perps[0].quote_position_native().round(), I80F48::from(-100_020) - partial_settle_amount, "quote position reduced for profitable position by max_settle_amount" ); assert_eq!( - mango_account_1.perps[0].quote_position_native.round(), + mango_account_1.perps[0].quote_position_native().round(), I80F48::from(100_000) + partial_settle_amount, "quote position increased for losing position by opposite of first account" ); @@ -607,21 +609,23 @@ async fn test_perp_settle_pnl() -> Result<(), TransportError> { let mango_account_1 = solana.get_account::(account_1).await; assert_eq!( - mango_account_0.perps[0].base_position_lots, 1, + mango_account_0.perps[0].base_position_lots(), + 1, "base position unchanged for account 0" ); assert_eq!( - mango_account_1.perps[0].base_position_lots, -1, + mango_account_1.perps[0].base_position_lots(), + -1, "base position unchanged for account 1" ); assert_eq!( - mango_account_0.perps[0].quote_position_native.round(), + mango_account_0.perps[0].quote_position_native().round(), I80F48::from(-100_020) - expected_pnl_0, "quote position reduced for profitable position" ); assert_eq!( - mango_account_1.perps[0].quote_position_native.round(), + mango_account_1.perps[0].quote_position_native().round(), I80F48::from(100_000) + expected_pnl_0, "quote position increased for losing position by opposite of first account" ); @@ -700,21 +704,23 @@ async fn test_perp_settle_pnl() -> Result<(), TransportError> { let mango_account_1 = solana.get_account::(account_1).await; assert_eq!( - mango_account_0.perps[0].base_position_lots, 1, + mango_account_0.perps[0].base_position_lots(), + 1, "base position unchanged for account 0" ); assert_eq!( - mango_account_1.perps[0].base_position_lots, -1, + mango_account_1.perps[0].base_position_lots(), + -1, "base position unchanged for account 1" ); assert_eq!( - mango_account_0.perps[0].quote_position_native.round(), + mango_account_0.perps[0].quote_position_native().round(), I80F48::from(-100_500) + expected_pnl_1, "quote position increased for losing position" ); assert_eq!( - mango_account_1.perps[0].quote_position_native.round(), + mango_account_1.perps[0].quote_position_native().round(), I80F48::from(100_480) - expected_pnl_1, "quote position reduced for losing position by opposite of first account" ); diff --git a/programs/mango-v4/tests/test_perp_settle_fees.rs b/programs/mango-v4/tests/test_perp_settle_fees.rs index e7655c805..9c9e4f0ea 100644 --- a/programs/mango-v4/tests/test_perp_settle_fees.rs +++ b/programs/mango-v4/tests/test_perp_settle_fees.rs @@ -299,15 +299,15 @@ async fn test_perp_settle_fees() -> Result<(), TransportError> { .unwrap(); let mango_account_0 = solana.get_account::(account_0).await; - assert_eq!(mango_account_0.perps[0].base_position_lots, 1); + assert_eq!(mango_account_0.perps[0].base_position_lots(), 1); assert_eq!( - mango_account_0.perps[0].quote_position_native.round(), + mango_account_0.perps[0].quote_position_native().round(), -100_020 ); let mango_account_1 = solana.get_account::(account_1).await; - assert_eq!(mango_account_1.perps[0].base_position_lots, -1); - assert_eq!(mango_account_1.perps[0].quote_position_native, 100_000); + assert_eq!(mango_account_1.perps[0].base_position_lots(), -1); + assert_eq!(mango_account_1.perps[0].quote_position_native(), 100_000); // Bank must be valid for quote currency let result = send_tx( @@ -528,12 +528,13 @@ async fn test_perp_settle_fees() -> Result<(), TransportError> { let perp_market = solana.get_account::(perp_market).await; assert_eq!( - mango_account_1.perps[0].base_position_lots, -1, + mango_account_1.perps[0].base_position_lots(), + -1, "base position unchanged for account 1" ); assert_eq!( - mango_account_1.perps[0].quote_position_native.round(), + mango_account_1.perps[0].quote_position_native().round(), I80F48::from(100_000) + partial_settle_amount, "quote position increased for losing position by fee settle amount" ); @@ -582,12 +583,13 @@ async fn test_perp_settle_fees() -> Result<(), TransportError> { let perp_market = solana.get_account::(perp_market).await; assert_eq!( - mango_account_1.perps[0].base_position_lots, -1, + mango_account_1.perps[0].base_position_lots(), + -1, "base position unchanged for account 1" ); assert_eq!( - mango_account_1.perps[0].quote_position_native.round(), + mango_account_1.perps[0].quote_position_native().round(), I80F48::from(100_000) + initial_fees, "quote position increased for losing position by fees settled" );