diff --git a/programs/mango-v4/src/state/mango_account.rs b/programs/mango-v4/src/state/mango_account.rs index 3f199a7ca..1be1e927f 100644 --- a/programs/mango-v4/src/state/mango_account.rs +++ b/programs/mango-v4/src/state/mango_account.rs @@ -126,6 +126,9 @@ pub struct MangoAccount { pub perps: Vec, pub padding7: u32, pub perp_open_orders: Vec, + // WARNING: This does not have further fields, like tcs, intentionally: + // There are existing accounts that don't have them and adding them here + // would break backwards compatibility. } impl MangoAccount { @@ -170,9 +173,9 @@ impl MangoAccount { perp_oo_count: u8, token_conditional_swap_count: u8, ) -> Result { - require_gte!(16, token_count); + require_gte!(8, token_count); require_gte!(8, serum3_count); - require_gte!(8, perp_count); + require_gte!(4, perp_count); require_gte!(64, perp_oo_count); require_gte!(64, token_conditional_swap_count); @@ -1540,7 +1543,7 @@ mod tests { account.tokens.resize(8, TokenPosition::default()); account.tokens[0].token_index = 8; account.serum3.resize(8, Serum3Orders::default()); - account.perps.resize(8, PerpPosition::default()); + account.perps.resize(4, PerpPosition::default()); account.perps[0].market_index = 9; account.perp_open_orders.resize(8, PerpOpenOrder::default()); account.next_token_conditional_swap_id = 13; @@ -1554,7 +1557,7 @@ mod tests { }; assert_eq!( 8 + account_bytes_with_tcs.len(), - MangoAccount::space(8, 8, 8, 8, 0).unwrap() + MangoAccount::space(8, 8, 4, 8, 0).unwrap() ); let account2 = MangoAccountValue::from_bytes(&account_bytes_without_tcs).unwrap(); diff --git a/programs/mango-v4/tests/cases/test_bankrupt_tokens.rs b/programs/mango-v4/tests/cases/test_bankrupt_tokens.rs index 0b6e1d73c..0480b3cc2 100644 --- a/programs/mango-v4/tests/cases/test_bankrupt_tokens.rs +++ b/programs/mango-v4/tests/cases/test_bankrupt_tokens.rs @@ -68,13 +68,10 @@ async fn test_bankrupt_tokens_socialize_loss() -> Result<(), TransportError> { solana, AccountCreateInstruction { account_num: 0, - token_count: 16, - serum3_count: 8, - perp_count: 8, - perp_oo_count: 8, group, owner, payer, + ..Default::default() }, ) .await @@ -325,13 +322,10 @@ async fn test_bankrupt_tokens_insurance_fund() -> Result<(), TransportError> { solana, AccountCreateInstruction { account_num: 2, - token_count: 16, - serum3_count: 8, - perp_count: 8, - perp_oo_count: 8, group, owner, payer, + ..Default::default() }, ) .await @@ -379,13 +373,10 @@ async fn test_bankrupt_tokens_insurance_fund() -> Result<(), TransportError> { solana, AccountCreateInstruction { account_num: 0, - token_count: 16, - serum3_count: 8, - perp_count: 8, - perp_oo_count: 8, group, owner, payer, + ..Default::default() }, ) .await diff --git a/programs/mango-v4/tests/cases/test_basic.rs b/programs/mango-v4/tests/cases/test_basic.rs index c23195a75..a35cae56b 100644 --- a/programs/mango-v4/tests/cases/test_basic.rs +++ b/programs/mango-v4/tests/cases/test_basic.rs @@ -33,10 +33,11 @@ async fn test_basic() -> Result<(), TransportError> { solana, AccountCreateInstruction { account_num: 0, - token_count: 8, + token_count: 6, serum3_count: 7, perp_count: 0, perp_oo_count: 0, + token_conditional_swap_count: 0, group, owner, payer, @@ -46,46 +47,53 @@ async fn test_basic() -> Result<(), TransportError> { .unwrap() .account; let account_data: MangoAccount = solana.get_account(account).await; + assert_eq!(account_data.tokens.len(), 6); + assert_eq!( + account_data.tokens.iter().filter(|t| t.is_active()).count(), + 0 + ); + assert_eq!(account_data.serum3.len(), 7); + assert_eq!( + account_data.serum3.iter().filter(|s| s.is_active()).count(), + 0 + ); + + assert_eq!(account_data.perps.len(), 0); + assert_eq!(account_data.perp_open_orders.len(), 0); + + send_tx( + solana, + AccountExpandInstruction { + account_num: 0, + token_count: 8, + serum3_count: 8, + perp_count: 4, + perp_oo_count: 8, + token_conditional_swap_count: 4, + group, + owner, + payer, + ..Default::default() + }, + ) + .await + .unwrap() + .account; + let account_data: MangoAccount = solana.get_account(account).await; assert_eq!(account_data.tokens.len(), 8); assert_eq!( account_data.tokens.iter().filter(|t| t.is_active()).count(), 0 ); - assert_eq!(account_data.serum3.len(), 7); - assert_eq!( - account_data.serum3.iter().filter(|s| s.is_active()).count(), - 0 - ); - - send_tx( - solana, - AccountExpandInstruction { - account_num: 0, - token_count: 16, - serum3_count: 8, - perp_count: 8, - perp_oo_count: 8, - group, - owner, - payer, - ..Default::default() - }, - ) - .await - .unwrap() - .account; - let account_data: MangoAccount = solana.get_account(account).await; - assert_eq!(account_data.tokens.len(), 16); - assert_eq!( - account_data.tokens.iter().filter(|t| t.is_active()).count(), - 0 - ); assert_eq!(account_data.serum3.len(), 8); assert_eq!( account_data.serum3.iter().filter(|s| s.is_active()).count(), 0 ); + assert_eq!(account_data.perps.len(), 4); + assert_eq!(account_data.perp_open_orders.len(), 8); + // // TEST: Deposit funds // diff --git a/programs/mango-v4/tests/cases/test_health_compute.rs b/programs/mango-v4/tests/cases/test_health_compute.rs index df86aa17b..bdf407851 100644 --- a/programs/mango-v4/tests/cases/test_health_compute.rs +++ b/programs/mango-v4/tests/cases/test_health_compute.rs @@ -9,7 +9,7 @@ async fn test_health_compute_tokens() -> Result<(), TransportError> { let admin = TestKeypair::new(); let owner = context.users[0].key; let payer = context.users[1].key; - let mints = &context.mints[0..10]; + let mints = &context.mints[0..8]; // // SETUP: Create a group and an account @@ -28,7 +28,7 @@ async fn test_health_compute_tokens() -> Result<(), TransportError> { create_funded_account(&solana, group, owner, 0, &context.users[1], mints, 1000, 0).await; // TODO: actual explicit CU comparisons. - // On 2023-2-5 the final deposit costs 57622 CU and each new token increases it by roughly 2400 CU + // On 2023-8-18 the final deposit costs 56245 CU and each new token increases it by roughly 2800 CU Ok(()) } @@ -64,13 +64,10 @@ async fn test_health_compute_serum() -> Result<(), TransportError> { solana, AccountCreateInstruction { account_num: 0, - token_count: 16, - serum3_count: 8, - perp_count: 8, - perp_oo_count: 8, group, owner, payer, + ..Default::default() }, ) .await @@ -164,7 +161,7 @@ async fn test_health_compute_perp() -> Result<(), TransportError> { let admin = TestKeypair::new(); let owner = context.users[0].key; let payer = context.users[1].key; - let mints = &context.mints[0..8]; + let mints = &context.mints[0..5]; let payer_mint_accounts = &context.users[1].token_accounts[0..mints.len()]; // @@ -266,7 +263,7 @@ async fn test_health_compute_perp() -> Result<(), TransportError> { } // TODO: actual explicit CU comparisons. - // On 2023-2-5 the final deposit costs 60732 CU and each new market increases it by roughly 3400 CU + // On 2023-8-18 the final deposit costs 51879 CU and each new market increases it by roughly 4100 CU Ok(()) } diff --git a/programs/mango-v4/tests/cases/test_liq_perps_bankruptcy.rs b/programs/mango-v4/tests/cases/test_liq_perps_bankruptcy.rs index 3e944b755..d89980821 100644 --- a/programs/mango-v4/tests/cases/test_liq_perps_bankruptcy.rs +++ b/programs/mango-v4/tests/cases/test_liq_perps_bankruptcy.rs @@ -68,19 +68,6 @@ async fn test_liq_perps_bankruptcy() -> Result<(), TransportError> { let base_token = &tokens[1]; // used for perp market let collateral_token = &tokens[2]; // used for adjusting account health - // deposit some funds, to the vaults aren't empty - let liqor = create_funded_account( - &solana, - group, - owner, - 250, - &context.users[1], - mints, - 10000, - 0, - ) - .await; - // all perp markets used here default to price = 1.0, base_lot_size = 100 let price_lots = 100; @@ -95,6 +82,18 @@ async fn test_liq_perps_bankruptcy() -> Result<(), TransportError> { let adj_price = 1.0 + pnl as f64 / -100.0; let adj_price_lots = (price_lots as f64 * adj_price) as i64; + let fresh_liqor = create_funded_account( + &solana, + group, + owner, + 200 + perp_market_index as u32, + &context_ref.users[1], + mints, + 10000, + 0, + ) + .await; + let mango_v4::accounts::PerpCreateMarket { perp_market, .. } = send_tx( solana, PerpCreateMarketInstruction { @@ -236,7 +235,7 @@ async fn test_liq_perps_bankruptcy() -> Result<(), TransportError> { health as f64 ); - (perp_market, account) + (perp_market, account, fresh_liqor) }; let mut setup_perp = |health: i64, pnl: i64, settle_limit: i64| { let out = setup_perp_inner(perp_market_index, health, pnl, settle_limit); @@ -265,7 +264,7 @@ async fn test_liq_perps_bankruptcy() -> Result<(), TransportError> { (settlement, insur, loss) }; - let liqor_info = |perp_market: Pubkey| async move { + let liqor_info = |perp_market: Pubkey, liqor: Pubkey| async move { let perp_market = solana.get_account::(perp_market).await; let liqor_data = solana.get_account::(liqor).await; let liqor_perp = liqor_data @@ -278,7 +277,7 @@ async fn test_liq_perps_bankruptcy() -> Result<(), TransportError> { }; { - let (perp_market, account) = setup_perp(-28, -50, -10).await; + let (perp_market, account, liqor) = setup_perp(-28, -50, -10).await; let liqor_quote_before = account_position(solana, liqor, quote_token.bank).await; send_tx( @@ -306,12 +305,12 @@ async fn test_liq_perps_bankruptcy() -> Result<(), TransportError> { let acc_data = solana.get_account::(account).await; assert_eq!(acc_data.perps[0].quote_position_native(), -49); assert_eq!(acc_data.being_liquidated, 1); - let (_liqor_data, liqor_perp) = liqor_info(perp_market).await; + let (_liqor_data, liqor_perp) = liqor_info(perp_market, liqor).await; assert_eq!(liqor_perp.quote_position_native(), -1); } { - let (perp_market, account) = setup_perp(-28, -50, -10).await; + let (perp_market, account, liqor) = setup_perp(-28, -50, -10).await; fund_insurance(2).await; let liqor_quote_before = account_position(solana, liqor, quote_token.bank).await; @@ -344,12 +343,12 @@ async fn test_liq_perps_bankruptcy() -> Result<(), TransportError> { 0.1 )); assert_eq!(acc_data.being_liquidated, 0); - let (_liqor_data, liqor_perp) = liqor_info(perp_market).await; + let (_liqor_data, liqor_perp) = liqor_info(perp_market, liqor).await; assert_eq!(liqor_perp.quote_position_native(), -11); } { - let (perp_market, account) = setup_perp(-28, -50, -10).await; + let (perp_market, account, liqor) = setup_perp(-28, -50, -10).await; fund_insurance(5).await; send_tx( @@ -372,7 +371,7 @@ async fn test_liq_perps_bankruptcy() -> Result<(), TransportError> { // no insurance { - let (perp_market, account) = setup_perp(-28, -50, -10).await; + let (perp_market, account, liqor) = setup_perp(-28, -50, -10).await; send_tx( solana, @@ -391,7 +390,7 @@ async fn test_liq_perps_bankruptcy() -> Result<(), TransportError> { // no settlement: no settle health { - let (perp_market, account) = setup_perp(-200, -50, -10).await; + let (perp_market, account, liqor) = setup_perp(-200, -50, -10).await; fund_insurance(5).await; send_tx( @@ -411,7 +410,7 @@ async fn test_liq_perps_bankruptcy() -> Result<(), TransportError> { // no settlement: no settle limit { - let (perp_market, account) = setup_perp(-40, -50, 0).await; + let (perp_market, account, liqor) = setup_perp(-40, -50, 0).await; // no insurance send_tx( @@ -431,7 +430,7 @@ async fn test_liq_perps_bankruptcy() -> Result<(), TransportError> { // no socialized loss: fully covered by insurance fund { - let (perp_market, account) = setup_perp(-40, -50, -5).await; + let (perp_market, account, liqor) = setup_perp(-40, -50, -5).await; fund_insurance(42).await; send_tx( diff --git a/programs/mango-v4/tests/cases/test_liq_tokens.rs b/programs/mango-v4/tests/cases/test_liq_tokens.rs index 3cb41c023..f7862974b 100644 --- a/programs/mango-v4/tests/cases/test_liq_tokens.rs +++ b/programs/mango-v4/tests/cases/test_liq_tokens.rs @@ -197,13 +197,10 @@ async fn test_liq_tokens_with_token() -> Result<(), TransportError> { solana, AccountCreateInstruction { account_num: 2, - token_count: 16, - serum3_count: 8, - perp_count: 8, - perp_oo_count: 8, group, owner, payer, + ..Default::default() }, ) .await @@ -233,13 +230,10 @@ async fn test_liq_tokens_with_token() -> Result<(), TransportError> { solana, AccountCreateInstruction { account_num: 0, - token_count: 16, - serum3_count: 8, - perp_count: 8, - perp_oo_count: 8, group, owner, payer, + ..Default::default() }, ) .await diff --git a/programs/mango-v4/tests/cases/test_margin_trade.rs b/programs/mango-v4/tests/cases/test_margin_trade.rs index 3ef544143..ae14710bf 100644 --- a/programs/mango-v4/tests/cases/test_margin_trade.rs +++ b/programs/mango-v4/tests/cases/test_margin_trade.rs @@ -58,13 +58,10 @@ async fn test_margin_trade() -> Result<(), BanksClientError> { solana, AccountCreateInstruction { account_num: 0, - token_count: 16, - serum3_count: 8, - perp_count: 8, - perp_oo_count: 8, group, owner, payer, + ..Default::default() }, ) .await diff --git a/programs/mango-v4/tests/cases/test_position_lifetime.rs b/programs/mango-v4/tests/cases/test_position_lifetime.rs index de4e0c27e..84f066b4a 100644 --- a/programs/mango-v4/tests/cases/test_position_lifetime.rs +++ b/programs/mango-v4/tests/cases/test_position_lifetime.rs @@ -30,13 +30,10 @@ async fn test_position_lifetime() -> Result<(), TransportError> { solana, AccountCreateInstruction { account_num: 0, - token_count: 16, - serum3_count: 8, - perp_count: 8, - perp_oo_count: 8, group, owner, payer, + ..Default::default() }, ) .await diff --git a/programs/mango-v4/tests/cases/test_token_conditional_swap.rs b/programs/mango-v4/tests/cases/test_token_conditional_swap.rs index 5fb872266..8a70b86ca 100644 --- a/programs/mango-v4/tests/cases/test_token_conditional_swap.rs +++ b/programs/mango-v4/tests/cases/test_token_conditional_swap.rs @@ -50,6 +50,20 @@ async fn test_token_conditional_swap() -> Result<(), TransportError> { 0, ) .await; + let no_tcs_account = send_tx( + solana, + AccountCreateInstruction { + account_num: 2, + token_conditional_swap_count: 0, + group, + owner, + payer, + ..Default::default() + }, + ) + .await + .unwrap() + .account; send_tx( solana, @@ -73,7 +87,7 @@ async fn test_token_conditional_swap() -> Result<(), TransportError> { let tx_result = send_tx( solana, TokenConditionalSwapCreateInstruction { - account, + account: no_tcs_account, owner, buy_mint: quote_token.mint.pubkey, sell_mint: base_token.mint.pubkey, @@ -96,10 +110,10 @@ async fn test_token_conditional_swap() -> Result<(), TransportError> { solana, AccountExpandInstruction { account_num: 0, - token_count: 16, + token_count: 8, serum3_count: 8, - perp_count: 8, - perp_oo_count: 8, + perp_count: 4, + perp_oo_count: 16, token_conditional_swap_count: 2, group, owner, diff --git a/programs/mango-v4/tests/program_test/mango_client.rs b/programs/mango-v4/tests/program_test/mango_client.rs index 523f7b013..654953416 100644 --- a/programs/mango-v4/tests/program_test/mango_client.rs +++ b/programs/mango-v4/tests/program_test/mango_client.rs @@ -1814,10 +1814,26 @@ pub struct AccountCreateInstruction { pub serum3_count: u8, pub perp_count: u8, pub perp_oo_count: u8, + pub token_conditional_swap_count: u8, pub group: Pubkey, pub owner: TestKeypair, pub payer: TestKeypair, } +impl Default for AccountCreateInstruction { + fn default() -> Self { + AccountCreateInstruction { + account_num: 0, + token_count: 8, + serum3_count: 8, + perp_count: 4, + perp_oo_count: 16, + token_conditional_swap_count: 1, + group: Default::default(), + owner: Default::default(), + payer: Default::default(), + } + } +} #[async_trait::async_trait(?Send)] impl ClientInstruction for AccountCreateInstruction { type Accounts = mango_v4::accounts::AccountCreate; @@ -1833,7 +1849,7 @@ impl ClientInstruction for AccountCreateInstruction { serum3_count: self.serum3_count, perp_count: self.perp_count, perp_oo_count: self.perp_oo_count, - token_conditional_swap_count: 0, + token_conditional_swap_count: self.token_conditional_swap_count, name: "my_mango_account".to_string(), }; diff --git a/programs/mango-v4/tests/program_test/mango_setup.rs b/programs/mango-v4/tests/program_test/mango_setup.rs index 684390fd6..e09a70239 100644 --- a/programs/mango-v4/tests/program_test/mango_setup.rs +++ b/programs/mango-v4/tests/program_test/mango_setup.rs @@ -163,13 +163,10 @@ pub async fn create_funded_account( solana, AccountCreateInstruction { account_num, - token_count: 16, - serum3_count: 8, - perp_count: 8, - perp_oo_count: 8, group, owner, payer: payer.key, + ..Default::default() }, ) .await diff --git a/ts/client/scripts/create-gov-ix.ts b/ts/client/scripts/create-gov-ix.ts index 80ec93ead..e3f26fa18 100644 --- a/ts/client/scripts/create-gov-ix.ts +++ b/ts/client/scripts/create-gov-ix.ts @@ -370,7 +370,7 @@ async function createMangoAccount(): Promise { const group = await client.getGroup(new PublicKey(GROUP_PK)); const ix = await client.program.methods - .accountCreate(0, 8, 8, 8, 32, 'Mango DAO 0') + .accountCreate(0, 8, 8, 4, 32, 'Mango DAO 0') .accounts({ group: group.publicKey, owner: new PublicKey('5tgfd6XgwiXB9otEnzFpXK11m7Q7yZUaAJzWK4oT5UGF'), diff --git a/ts/client/src/client.ts b/ts/client/src/client.ts index e6d39abff..d82775875 100644 --- a/ts/client/src/client.ts +++ b/ts/client/src/client.ts @@ -740,7 +740,7 @@ export class MangoClient { accountNumber ?? 0, tokenCount ?? 8, serum3Count ?? 8, - perpCount ?? 8, + perpCount ?? 4, perpOoCount ?? 32, name ?? '', )