diff --git a/programs/mango-v4/src/instructions/group_close.rs b/programs/mango-v4/src/instructions/group_close.rs index eeb3e5af3..0df176840 100644 --- a/programs/mango-v4/src/instructions/group_close.rs +++ b/programs/mango-v4/src/instructions/group_close.rs @@ -6,7 +6,7 @@ use anchor_spl::token::{self, CloseAccount, Token, TokenAccount}; pub struct GroupClose<'info> { #[account( mut, - constraint = group.load()?.testing == 1, + constraint = group.load()?.is_testing(), has_one = admin, has_one = insurance_vault, close = sol_destination diff --git a/programs/mango-v4/src/instructions/group_create.rs b/programs/mango-v4/src/instructions/group_create.rs index b25544f13..bdb1a6f80 100644 --- a/programs/mango-v4/src/instructions/group_create.rs +++ b/programs/mango-v4/src/instructions/group_create.rs @@ -38,7 +38,12 @@ pub struct GroupCreate<'info> { pub rent: Sysvar<'info, Rent>, } -pub fn group_create(ctx: Context, group_num: u32, testing: u8) -> Result<()> { +pub fn group_create( + ctx: Context, + group_num: u32, + testing: u8, + version: u8, +) -> Result<()> { let mut group = ctx.accounts.group.load_init()?; group.creator = ctx.accounts.creator.key(); group.admin = ctx.accounts.creator.key(); @@ -48,5 +53,6 @@ pub fn group_create(ctx: Context, group_num: u32, testing: u8) -> R group.bump = *ctx.bumps.get("group").ok_or(MangoError::SomeError)?; group.group_num = group_num; group.testing = testing; + group.version = version; Ok(()) } diff --git a/programs/mango-v4/src/instructions/perp_close_market.rs b/programs/mango-v4/src/instructions/perp_close_market.rs index 1bf40e29b..90c3bcdae 100644 --- a/programs/mango-v4/src/instructions/perp_close_market.rs +++ b/programs/mango-v4/src/instructions/perp_close_market.rs @@ -6,7 +6,7 @@ use crate::state::*; #[derive(Accounts)] pub struct PerpCloseMarket<'info> { #[account( - constraint = group.load()?.testing == 1, + constraint = group.load()?.is_testing(), has_one = admin, )] pub group: AccountLoader<'info, Group>, diff --git a/programs/mango-v4/src/instructions/perp_create_market.rs b/programs/mango-v4/src/instructions/perp_create_market.rs index 8abc21dd2..ea01edd4a 100644 --- a/programs/mango-v4/src/instructions/perp_create_market.rs +++ b/programs/mango-v4/src/instructions/perp_create_market.rs @@ -11,6 +11,7 @@ use crate::util::fill16_from_str; pub struct PerpCreateMarket<'info> { #[account( has_one = admin, + constraint = group.load()?.perps_supported() )] pub group: AccountLoader<'info, Group>, pub admin: Signer<'info>, diff --git a/programs/mango-v4/src/instructions/serum3_deregister_market.rs b/programs/mango-v4/src/instructions/serum3_deregister_market.rs index 3a4570ed1..f88baa8ee 100644 --- a/programs/mango-v4/src/instructions/serum3_deregister_market.rs +++ b/programs/mango-v4/src/instructions/serum3_deregister_market.rs @@ -7,7 +7,7 @@ use crate::state::*; pub struct Serum3DeregisterMarket<'info> { #[account( mut, - constraint = group.load()?.testing == 1, + constraint = group.load()?.is_testing(), has_one = admin, )] pub group: AccountLoader<'info, Group>, diff --git a/programs/mango-v4/src/instructions/serum3_register_market.rs b/programs/mango-v4/src/instructions/serum3_register_market.rs index 8523527f5..a8db144ee 100644 --- a/programs/mango-v4/src/instructions/serum3_register_market.rs +++ b/programs/mango-v4/src/instructions/serum3_register_market.rs @@ -10,6 +10,7 @@ pub struct Serum3RegisterMarket<'info> { #[account( mut, has_one = admin, + constraint = group.load()?.serum3_supported() )] pub group: AccountLoader<'info, Group>, pub admin: Signer<'info>, diff --git a/programs/mango-v4/src/instructions/stub_oracle_close.rs b/programs/mango-v4/src/instructions/stub_oracle_close.rs index 2814de1da..eb640c529 100644 --- a/programs/mango-v4/src/instructions/stub_oracle_close.rs +++ b/programs/mango-v4/src/instructions/stub_oracle_close.rs @@ -6,7 +6,7 @@ use crate::state::*; #[derive(Accounts)] pub struct StubOracleClose<'info> { #[account( - constraint = group.load()?.testing == 1, + constraint = group.load()?.is_testing(), has_one = admin, )] pub group: AccountLoader<'info, Group>, diff --git a/programs/mango-v4/src/instructions/token_add_bank.rs b/programs/mango-v4/src/instructions/token_add_bank.rs index a0e916460..a1de92419 100644 --- a/programs/mango-v4/src/instructions/token_add_bank.rs +++ b/programs/mango-v4/src/instructions/token_add_bank.rs @@ -11,6 +11,7 @@ use crate::state::*; pub struct TokenAddBank<'info> { #[account( has_one = admin, + constraint = group.load()?.multiple_banks_supported() )] pub group: AccountLoader<'info, Group>, pub admin: Signer<'info>, diff --git a/programs/mango-v4/src/instructions/token_deregister.rs b/programs/mango-v4/src/instructions/token_deregister.rs index 4f022a853..d5df31373 100644 --- a/programs/mango-v4/src/instructions/token_deregister.rs +++ b/programs/mango-v4/src/instructions/token_deregister.rs @@ -8,7 +8,7 @@ use anchor_lang::AccountsClose; #[instruction(token_index: TokenIndex)] pub struct TokenDeregister<'info> { #[account( - constraint = group.load()?.testing == 1, + constraint = group.load()?.is_testing(), has_one = admin, )] pub group: AccountLoader<'info, Group>, diff --git a/programs/mango-v4/src/lib.rs b/programs/mango-v4/src/lib.rs index 8b739b360..5d13821b7 100644 --- a/programs/mango-v4/src/lib.rs +++ b/programs/mango-v4/src/lib.rs @@ -32,8 +32,13 @@ pub mod mango_v4 { use super::*; - pub fn group_create(ctx: Context, group_num: u32, testing: u8) -> Result<()> { - instructions::group_create(ctx, group_num, testing) + pub fn group_create( + ctx: Context, + group_num: u32, + testing: u8, + version: u8, + ) -> Result<()> { + instructions::group_create(ctx, group_num, testing, version) } pub fn group_edit( diff --git a/programs/mango-v4/src/state/group.rs b/programs/mango-v4/src/state/group.rs index 971b988b1..e19d6b754 100644 --- a/programs/mango-v4/src/state/group.rs +++ b/programs/mango-v4/src/state/group.rs @@ -26,15 +26,35 @@ pub struct Group { pub insurance_mint: Pubkey, pub bump: u8, - // Only support closing/deregistering groups, stub oracles, tokens, and markets - // if testing == 1 + pub testing: u8, - pub padding2: [u8; 6], + + pub version: u8, + + pub padding2: [u8; 5], pub reserved: [u8; 8], } const_assert_eq!(size_of::(), 32 * 5 + 4 + 4 + 1 * 2 + 6 + 8); const_assert_eq!(size_of::() % 8, 0); +impl Group { + pub fn is_testing(&self) -> bool { + self.testing == 1 + } + + pub fn multiple_banks_supported(&self) -> bool { + self.is_testing() || self.version > 0 + } + + pub fn serum3_supported(&self) -> bool { + self.is_testing() || self.version > 0 + } + + pub fn perps_supported(&self) -> bool { + self.is_testing() || self.version > 0 + } +} + // note: using creator instead of admin, since admin can be changed #[macro_export] macro_rules! group_seeds { diff --git a/programs/mango-v4/tests/program_test/mango_client.rs b/programs/mango-v4/tests/program_test/mango_client.rs index c39a51bdc..a1d4a9d47 100644 --- a/programs/mango-v4/tests/program_test/mango_client.rs +++ b/programs/mango-v4/tests/program_test/mango_client.rs @@ -1230,6 +1230,7 @@ impl<'keypair> ClientInstruction for GroupCreateInstruction<'keypair> { let instruction = Self::Instruction { group_num: 0, testing: 1, + version: 0, }; let group = Pubkey::find_program_address( diff --git a/ts/client/src/client.ts b/ts/client/src/client.ts index d6a24817f..c21da3f64 100644 --- a/ts/client/src/client.ts +++ b/ts/client/src/client.ts @@ -76,11 +76,12 @@ export class MangoClient { public async groupCreate( groupNum: number, testing: boolean, + version: number, insuranceMintPk: PublicKey, ): Promise { const adminPk = (this.program.provider as AnchorProvider).wallet.publicKey; return await this.program.methods - .groupCreate(groupNum, testing ? 1 : 0) + .groupCreate(groupNum, testing ? 1 : 0, version) .accounts({ creator: adminPk, payer: adminPk, diff --git a/ts/client/src/mango_v4.ts b/ts/client/src/mango_v4.ts index d441e2a68..0f793982f 100644 --- a/ts/client/src/mango_v4.ts +++ b/ts/client/src/mango_v4.ts @@ -41,7 +41,7 @@ export type MangoV4 = { }, { "name": "insuranceVault", - "isMut": false, + "isMut": true, "isSigner": false, "pda": { "seeds": [ @@ -87,6 +87,10 @@ export type MangoV4 = { { "name": "testing", "type": "u8" + }, + { + "name": "version", + "type": "u8" } ] }, @@ -2865,12 +2869,16 @@ export type MangoV4 = { "name": "testing", "type": "u8" }, + { + "name": "version", + "type": "u8" + }, { "name": "padding2", "type": { "array": [ "u8", - 6 + 5 ] } }, @@ -4950,7 +4958,7 @@ export const IDL: MangoV4 = { }, { "name": "insuranceVault", - "isMut": false, + "isMut": true, "isSigner": false, "pda": { "seeds": [ @@ -4996,6 +5004,10 @@ export const IDL: MangoV4 = { { "name": "testing", "type": "u8" + }, + { + "name": "version", + "type": "u8" } ] }, @@ -7774,12 +7786,16 @@ export const IDL: MangoV4 = { "name": "testing", "type": "u8" }, + { + "name": "version", + "type": "u8" + }, { "name": "padding2", "type": { "array": [ "u8", - 6 + 5 ] } }, diff --git a/ts/client/src/scripts/example1-admin.ts b/ts/client/src/scripts/example1-admin.ts index 51430c687..c7cbe1e52 100644 --- a/ts/client/src/scripts/example1-admin.ts +++ b/ts/client/src/scripts/example1-admin.ts @@ -57,7 +57,7 @@ async function main() { console.log(`Creating Group...`); const insuranceMint = new PublicKey(DEVNET_MINTS.get('USDC')!); try { - await client.groupCreate(GROUP_NUM, true, insuranceMint); + await client.groupCreate(GROUP_NUM, true, insuranceMint, 0); } catch (error) { console.log(error); } diff --git a/ts/client/src/scripts/mb-example1-admin.ts b/ts/client/src/scripts/mb-example1-admin.ts index 8e7700481..74a8f681b 100644 --- a/ts/client/src/scripts/mb-example1-admin.ts +++ b/ts/client/src/scripts/mb-example1-admin.ts @@ -42,7 +42,7 @@ async function main() { console.log(`Creating Group...`); try { const insuranceMint = new PublicKey(MAINNET_MINTS.get('USDC')!); - await client.groupCreate(0, true, insuranceMint); + await client.groupCreate(0, true, insuranceMint, 0); } catch (error) { console.log(error); }