From af5187f9bb6ea5558e83421554532e657fb62580 Mon Sep 17 00:00:00 2001 From: jordy25519 Date: Mon, 18 Nov 2024 17:44:14 -0500 Subject: [PATCH] IDL 2.100.0 update (#74) * supports high maintenance mode in margin calc --- .github/workflows/build.yml | 2 +- build.rs | 31 ++-- crates/drift-ffi-sys | 2 +- crates/drift-idl-gen/src/lib.rs | 74 +++++--- crates/src/drift_idl.rs | 313 ++++++++++++++++++++++++++++++-- crates/src/ffi.rs | 19 +- crates/src/math/liquidation.rs | 12 +- res/drift.json | 158 +++++++++++++++- 8 files changed, 537 insertions(+), 74 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9efb74f..43c6676 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -32,7 +32,7 @@ jobs: rustup component add clippy rustfmt - name: install libdrift_ffi_sys run: | - curl -L https://github.com/user-attachments/files/17160233/libdrift_ffi_sys.so.zip > ffi.zip + curl -L https://github.com/user-attachments/files/17806677/libdrift_ffi_sys.so.zip > ffi.zip unzip ffi.zip ldd libdrift_ffi_sys.so sudo cp libdrift_ffi_sys.so /usr/lib diff --git a/build.rs b/build.rs index dca5a95..e2b7eb4 100644 --- a/build.rs +++ b/build.rs @@ -59,6 +59,10 @@ fn main() { fail_build(); } + // install the dylib to system path + let libffi_out_path = + drift_ffi_sys_crate.join(Path::new(&format!("target/{profile}/{LIB}.{lib_ext}"))); + // Build ffi crate and link let mut ffi_build = std::process::Command::new("rustup"); ffi_build @@ -89,9 +93,6 @@ fn main() { String::from_utf8_lossy(output.stderr.as_slice()) ); } - // install the dylib to system path - let libffi_out_path = - drift_ffi_sys_crate.join(Path::new(&format!("target/{profile}/{LIB}.{lib_ext}"))); if let Ok(out_dir) = std::env::var("OUT_DIR") { let _output = std::process::Command::new("cp") @@ -103,19 +104,19 @@ fn main() { .expect("install ok"); println!("{LIB}: searching for lib at: {out_dir}"); println!("cargo:rustc-link-search=native={out_dir}"); - } else { - let _output = std::process::Command::new("ln") - .args([ - "-sf", - libffi_out_path.to_str().expect("ffi build path"), - "/usr/local/lib/", - ]) - .output() - .expect("install ok"); - - println!("{LIB}: searching for lib at: /usr/local/lib"); - println!("cargo:rustc-link-search=native=/usr/local/lib"); } + + let _output = std::process::Command::new("ln") + .args([ + "-sf", + libffi_out_path.to_str().expect("ffi build path"), + "/usr/local/lib/", + ]) + .output() + .expect("install ok"); + + println!("{LIB}: searching for lib at: /usr/local/lib"); + println!("cargo:rustc-link-search=native=/usr/local/lib"); } if let Ok(lib_path) = std::env::var("CARGO_DRIFT_FFI_PATH") { diff --git a/crates/drift-ffi-sys b/crates/drift-ffi-sys index 719a0f9..0d5df4c 160000 --- a/crates/drift-ffi-sys +++ b/crates/drift-ffi-sys @@ -1 +1 @@ -Subproject commit 719a0f9511a5bb49228841ff1e3c500025dfcc40 +Subproject commit 0d5df4c857466cb9132763bb925d94c9a1b96f5c diff --git a/crates/drift-idl-gen/src/lib.rs b/crates/drift-idl-gen/src/lib.rs index 04b5094..393b46f 100644 --- a/crates/drift-idl-gen/src/lib.rs +++ b/crates/drift-idl-gen/src/lib.rs @@ -264,34 +264,69 @@ fn generate_idl_types(idl: &Idl) -> String { for account in &idl.accounts { let struct_name = Ident::new(&account.name, proc_macro2::Span::call_site()); - let struct_fields = account.account_type.fields.iter().map(|field| { - let field_name = - Ident::new(&to_snake_case(&field.name), proc_macro2::Span::call_site()); + let mut has_vec_field = false; + let struct_fields: Vec = account + .account_type + .fields + .iter() + .map(|field| { + let field_name = + Ident::new(&to_snake_case(&field.name), proc_macro2::Span::call_site()); + if let ArgType::Vec { .. } = field.field_type { + has_vec_field = true; + } + let mut serde_decorator = TokenStream::new(); + let mut field_type: Type = + syn::parse_str(&field.field_type.to_rust_type()).unwrap(); + // workaround for padding types preventing outertype from deriving 'Default' + if field_name == "padding" { + if let ArgType::Array { array: (_t, len) } = &field.field_type { + field_type = syn::parse_str(&format!("Padding<{len}>")).unwrap(); + serde_decorator = quote! { + #[serde(skip)] + }; + } + } - let mut serde_decorator = TokenStream::new(); - let mut field_type: Type = syn::parse_str(&field.field_type.to_rust_type()).unwrap(); - // workaround for padding types preventing outertype from deriving 'Default' - if field_name == "padding" { - if let ArgType::Array { array: (_t, len) } = &field.field_type { - field_type = syn::parse_str(&format!("Padding<{len}>")).unwrap(); - serde_decorator = quote! { - #[serde(skip)] - }; + quote! { + #serde_decorator + pub #field_name: #field_type, } + }) + .collect(); + + let derive_tokens = if !has_vec_field { + quote! { + #[derive(AnchorSerialize, AnchorDeserialize, InitSpace, Serialize, Deserialize, Copy, Clone, Default, Debug, PartialEq)] + } + } else { + // can't derive `Copy` on accounts with `Vec` field + // `InitSpace` requires a 'max_len' but no point enforcing here if unset on program side + quote! { + #[derive(AnchorSerialize, AnchorDeserialize, Serialize, Deserialize, Clone, Default, Debug, PartialEq)] } + }; + let zc_tokens = if !has_vec_field { + // without copy can't derive the ZeroCopy trait quote! { - #serde_decorator - pub #field_name: #field_type, + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Pod for #struct_name {} + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Zeroable for #struct_name {} + #[automatically_derived] + impl anchor_lang::ZeroCopy for #struct_name {} } - }); + } else { + Default::default() + }; let discriminator: TokenStream = format!("{:?}", sighash("account", &account.name)) .parse() .unwrap(); let struct_def = quote! { #[repr(C)] - #[derive(AnchorSerialize, AnchorDeserialize, InitSpace, Serialize, Deserialize, Copy, Clone, Default, Debug, PartialEq)] + #derive_tokens pub struct #struct_name { #(#struct_fields)* } @@ -299,12 +334,7 @@ fn generate_idl_types(idl: &Idl) -> String { impl anchor_lang::Discriminator for #struct_name { const DISCRIMINATOR: [u8; 8] = #discriminator; } - #[automatically_derived] - unsafe impl anchor_lang::__private::bytemuck::Pod for #struct_name {} - #[automatically_derived] - unsafe impl anchor_lang::__private::bytemuck::Zeroable for #struct_name {} - #[automatically_derived] - impl anchor_lang::ZeroCopy for #struct_name {} + #zc_tokens #[automatically_derived] impl anchor_lang::AccountSerialize for #struct_name { fn try_serialize(&self, writer: &mut W) -> anchor_lang::Result<()> { diff --git a/crates/src/drift_idl.rs b/crates/src/drift_idl.rs index edcb4ab..ae29ea4 100644 --- a/crates/src/drift_idl.rs +++ b/crates/src/drift_idl.rs @@ -52,7 +52,9 @@ pub mod instructions { #[automatically_derived] impl anchor_lang::InstructionData for InitializeRfqUser {} #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] - pub struct InitializeSwiftUserOrders {} + pub struct InitializeSwiftUserOrders { + pub num_orders: u16, + } #[automatically_derived] impl anchor_lang::Discriminator for InitializeSwiftUserOrders { const DISCRIMINATOR: [u8; 8] = [26, 91, 2, 246, 96, 153, 117, 194]; @@ -60,6 +62,16 @@ pub mod instructions { #[automatically_derived] impl anchor_lang::InstructionData for InitializeSwiftUserOrders {} #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] + pub struct ResizeSwiftUserOrders { + pub num_orders: u16, + } + #[automatically_derived] + impl anchor_lang::Discriminator for ResizeSwiftUserOrders { + const DISCRIMINATOR: [u8; 8] = [36, 57, 40, 90, 193, 150, 249, 53]; + } + #[automatically_derived] + impl anchor_lang::InstructionData for ResizeSwiftUserOrders {} + #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] pub struct InitializeReferrerName { pub name: [u8; 32], } @@ -409,6 +421,14 @@ pub mod instructions { #[automatically_derived] impl anchor_lang::InstructionData for DeleteUser {} #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] + pub struct DeleteSwiftUserOrders {} + #[automatically_derived] + impl anchor_lang::Discriminator for DeleteSwiftUserOrders { + const DISCRIMINATOR: [u8; 8] = [83, 157, 116, 215, 177, 177, 158, 20]; + } + #[automatically_derived] + impl anchor_lang::InstructionData for DeleteSwiftUserOrders {} + #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] pub struct ReclaimRent {} #[automatically_derived] impl anchor_lang::Discriminator for ReclaimRent { @@ -500,6 +520,14 @@ pub mod instructions { #[automatically_derived] impl anchor_lang::InstructionData for UpdateUserFuelBonus {} #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] + pub struct UpdateUserStatsReferrerStatus {} + #[automatically_derived] + impl anchor_lang::Discriminator for UpdateUserStatsReferrerStatus { + const DISCRIMINATOR: [u8; 8] = [174, 154, 72, 42, 191, 148, 145, 205]; + } + #[automatically_derived] + impl anchor_lang::InstructionData for UpdateUserStatsReferrerStatus {} + #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] pub struct UpdateUserOpenOrdersCount {} #[automatically_derived] impl anchor_lang::Discriminator for UpdateUserOpenOrdersCount { @@ -2698,6 +2726,25 @@ pub mod types { pub uuid: [u8; 8], pub max_slot: u64, pub order_id: u32, + pub padding: u32, + } + #[repr(C)] + #[derive( + AnchorSerialize, + AnchorDeserialize, + InitSpace, + Serialize, + Deserialize, + Copy, + Clone, + Default, + Debug, + PartialEq, + )] + pub struct SwiftUserOrdersFixed { + pub user_pubkey: Pubkey, + pub padding: u32, + pub len: u32, } #[repr(C)] #[derive( @@ -3360,6 +3407,7 @@ pub mod types { SettlePnl, SettlePnlWithPosition, Liquidation, + AmmImmediateFill, } #[derive( AnchorSerialize, @@ -3493,6 +3541,24 @@ pub mod types { Debug, PartialEq, )] + pub enum AMMAvailability { + #[default] + Immediate, + AfterMinDuration, + Unavailable, + } + #[derive( + AnchorSerialize, + AnchorDeserialize, + InitSpace, + Serialize, + Deserialize, + Copy, + Clone, + Default, + Debug, + PartialEq, + )] pub enum SettlePnlMode { #[default] MustSettle, @@ -3573,6 +3639,7 @@ pub mod types { LiqPaused, FundingPaused, SettlePnlPaused, + AmmImmediateFillPaused, } #[derive( AnchorSerialize, @@ -4518,32 +4585,18 @@ pub mod accounts { } #[repr(C)] #[derive( - AnchorSerialize, - AnchorDeserialize, - InitSpace, - Serialize, - Deserialize, - Copy, - Clone, - Default, - Debug, - PartialEq, + AnchorSerialize, AnchorDeserialize, Serialize, Deserialize, Clone, Default, Debug, PartialEq, )] pub struct SwiftUserOrders { pub user_pubkey: Pubkey, - pub swift_order_data: [SwiftOrderId; 32], + pub padding: u32, + pub swift_order_data: Vec, } #[automatically_derived] impl anchor_lang::Discriminator for SwiftUserOrders { const DISCRIMINATOR: [u8; 8] = [67, 121, 127, 98, 21, 50, 57, 193]; } #[automatically_derived] - unsafe impl anchor_lang::__private::bytemuck::Pod for SwiftUserOrders {} - #[automatically_derived] - unsafe impl anchor_lang::__private::bytemuck::Zeroable for SwiftUserOrders {} - #[automatically_derived] - impl anchor_lang::ZeroCopy for SwiftUserOrders {} - #[automatically_derived] impl anchor_lang::AccountSerialize for SwiftUserOrders { fn try_serialize(&self, writer: &mut W) -> anchor_lang::Result<()> { if writer.write_all(&Self::DISCRIMINATOR).is_err() { @@ -5104,7 +5157,7 @@ pub mod accounts { AccountMeta { pubkey: self.user, is_signer: false, - is_writable: true, + is_writable: false, }, AccountMeta { pubkey: self.payer, @@ -5155,6 +5208,82 @@ pub mod accounts { } #[repr(C)] #[derive(Copy, Clone, Default, AnchorSerialize, AnchorDeserialize, Serialize, Deserialize)] + pub struct ResizeSwiftUserOrders { + pub swift_user_orders: Pubkey, + pub authority: Pubkey, + pub user: Pubkey, + pub system_program: Pubkey, + } + #[automatically_derived] + impl anchor_lang::Discriminator for ResizeSwiftUserOrders { + const DISCRIMINATOR: [u8; 8] = [237, 41, 225, 39, 0, 209, 116, 228]; + } + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Pod for ResizeSwiftUserOrders {} + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Zeroable for ResizeSwiftUserOrders {} + #[automatically_derived] + impl anchor_lang::ZeroCopy for ResizeSwiftUserOrders {} + #[automatically_derived] + impl anchor_lang::InstructionData for ResizeSwiftUserOrders {} + #[automatically_derived] + impl ToAccountMetas for ResizeSwiftUserOrders { + fn to_account_metas(&self) -> Vec { + vec![ + AccountMeta { + pubkey: self.swift_user_orders, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: self.authority, + is_signer: true, + is_writable: true, + }, + AccountMeta { + pubkey: self.user, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: self.system_program, + is_signer: false, + is_writable: false, + }, + ] + } + } + #[automatically_derived] + impl anchor_lang::AccountSerialize for ResizeSwiftUserOrders { + fn try_serialize(&self, writer: &mut W) -> anchor_lang::Result<()> { + if writer.write_all(&Self::DISCRIMINATOR).is_err() { + return Err(anchor_lang::error::ErrorCode::AccountDidNotSerialize.into()); + } + if AnchorSerialize::serialize(self, writer).is_err() { + return Err(anchor_lang::error::ErrorCode::AccountDidNotSerialize.into()); + } + Ok(()) + } + } + #[automatically_derived] + impl anchor_lang::AccountDeserialize for ResizeSwiftUserOrders { + fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result { + let given_disc = &buf[..8]; + if Self::DISCRIMINATOR != given_disc { + return Err(anchor_lang::error!( + anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch + )); + } + Self::try_deserialize_unchecked(buf) + } + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + let mut data: &[u8] = &buf[8..]; + AnchorDeserialize::deserialize(&mut data) + .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize.into()) + } + } + #[repr(C)] + #[derive(Copy, Clone, Default, AnchorSerialize, AnchorDeserialize, Serialize, Deserialize)] pub struct InitializeReferrerName { pub referrer_name: Pubkey, pub user: Pubkey, @@ -7653,6 +7782,82 @@ pub mod accounts { } #[repr(C)] #[derive(Copy, Clone, Default, AnchorSerialize, AnchorDeserialize, Serialize, Deserialize)] + pub struct DeleteSwiftUserOrders { + pub user: Pubkey, + pub swift_user_orders: Pubkey, + pub state: Pubkey, + pub authority: Pubkey, + } + #[automatically_derived] + impl anchor_lang::Discriminator for DeleteSwiftUserOrders { + const DISCRIMINATOR: [u8; 8] = [183, 16, 243, 132, 133, 172, 85, 107]; + } + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Pod for DeleteSwiftUserOrders {} + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Zeroable for DeleteSwiftUserOrders {} + #[automatically_derived] + impl anchor_lang::ZeroCopy for DeleteSwiftUserOrders {} + #[automatically_derived] + impl anchor_lang::InstructionData for DeleteSwiftUserOrders {} + #[automatically_derived] + impl ToAccountMetas for DeleteSwiftUserOrders { + fn to_account_metas(&self) -> Vec { + vec![ + AccountMeta { + pubkey: self.user, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: self.swift_user_orders, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: self.state, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: self.authority, + is_signer: true, + is_writable: false, + }, + ] + } + } + #[automatically_derived] + impl anchor_lang::AccountSerialize for DeleteSwiftUserOrders { + fn try_serialize(&self, writer: &mut W) -> anchor_lang::Result<()> { + if writer.write_all(&Self::DISCRIMINATOR).is_err() { + return Err(anchor_lang::error::ErrorCode::AccountDidNotSerialize.into()); + } + if AnchorSerialize::serialize(self, writer).is_err() { + return Err(anchor_lang::error::ErrorCode::AccountDidNotSerialize.into()); + } + Ok(()) + } + } + #[automatically_derived] + impl anchor_lang::AccountDeserialize for DeleteSwiftUserOrders { + fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result { + let given_disc = &buf[..8]; + if Self::DISCRIMINATOR != given_disc { + return Err(anchor_lang::error!( + anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch + )); + } + Self::try_deserialize_unchecked(buf) + } + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + let mut data: &[u8] = &buf[8..]; + AnchorDeserialize::deserialize(&mut data) + .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize.into()) + } + } + #[repr(C)] + #[derive(Copy, Clone, Default, AnchorSerialize, AnchorDeserialize, Serialize, Deserialize)] pub struct ReclaimRent { pub user: Pubkey, pub user_stats: Pubkey, @@ -8443,6 +8648,76 @@ pub mod accounts { } #[repr(C)] #[derive(Copy, Clone, Default, AnchorSerialize, AnchorDeserialize, Serialize, Deserialize)] + pub struct UpdateUserStatsReferrerStatus { + pub state: Pubkey, + pub authority: Pubkey, + pub user_stats: Pubkey, + } + #[automatically_derived] + impl anchor_lang::Discriminator for UpdateUserStatsReferrerStatus { + const DISCRIMINATOR: [u8; 8] = [88, 125, 77, 90, 13, 11, 141, 158]; + } + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Pod for UpdateUserStatsReferrerStatus {} + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Zeroable for UpdateUserStatsReferrerStatus {} + #[automatically_derived] + impl anchor_lang::ZeroCopy for UpdateUserStatsReferrerStatus {} + #[automatically_derived] + impl anchor_lang::InstructionData for UpdateUserStatsReferrerStatus {} + #[automatically_derived] + impl ToAccountMetas for UpdateUserStatsReferrerStatus { + fn to_account_metas(&self) -> Vec { + vec![ + AccountMeta { + pubkey: self.state, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: self.authority, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: self.user_stats, + is_signer: false, + is_writable: true, + }, + ] + } + } + #[automatically_derived] + impl anchor_lang::AccountSerialize for UpdateUserStatsReferrerStatus { + fn try_serialize(&self, writer: &mut W) -> anchor_lang::Result<()> { + if writer.write_all(&Self::DISCRIMINATOR).is_err() { + return Err(anchor_lang::error::ErrorCode::AccountDidNotSerialize.into()); + } + if AnchorSerialize::serialize(self, writer).is_err() { + return Err(anchor_lang::error::ErrorCode::AccountDidNotSerialize.into()); + } + Ok(()) + } + } + #[automatically_derived] + impl anchor_lang::AccountDeserialize for UpdateUserStatsReferrerStatus { + fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result { + let given_disc = &buf[..8]; + if Self::DISCRIMINATOR != given_disc { + return Err(anchor_lang::error!( + anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch + )); + } + Self::try_deserialize_unchecked(buf) + } + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + let mut data: &[u8] = &buf[8..]; + AnchorDeserialize::deserialize(&mut data) + .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize.into()) + } + } + #[repr(C)] + #[derive(Copy, Clone, Default, AnchorSerialize, AnchorDeserialize, Serialize, Deserialize)] pub struct UpdateUserOpenOrdersCount { pub state: Pubkey, pub authority: Pubkey, diff --git a/crates/src/ffi.rs b/crates/src/ffi.rs index f5d4978..eaf6c2b 100644 --- a/crates/src/ffi.rs +++ b/crates/src/ffi.rs @@ -54,6 +54,7 @@ extern "C" { market: &accounts::PerpMarket, size: u128, margin_type: MarginRequirementType, + high_leverage_mode: bool, ) -> FfiResult; #[allow(improper_ctypes)] pub fn perp_market_get_open_interest(market: &accounts::PerpMarket) -> u128; @@ -246,8 +247,11 @@ impl accounts::PerpMarket { &self, size: u128, margin_requirement_type: MarginRequirementType, + high_leverage_mode: bool, ) -> SdkResult { - to_sdk_result(unsafe { perp_market_get_margin_ratio(self, size, margin_requirement_type) }) + to_sdk_result(unsafe { + perp_market_get_margin_ratio(self, size, margin_requirement_type, high_leverage_mode) + }) } pub fn get_open_interest(&self) -> u128 { unsafe { perp_market_get_open_interest(self) } @@ -651,22 +655,31 @@ mod tests { margin_ratio_initial: 1_000 * MARGIN_PRECISION, // 10% margin_ratio_maintenance: 500, // 5% imf_factor: 0, // No impact for simplicity + // enable HL mode for this market + high_leverage_margin_ratio_maintenance: 1_234, + high_leverage_margin_ratio_initial: 4_321, ..Default::default() }; let size = 1_000 * MARGIN_PRECISION as u128; // Assuming MARGIN_PRECISION is defined // Test initial margin ratio - let result = perp_market.get_margin_ratio(size, MarginRequirementType::Initial); + let result = perp_market.get_margin_ratio(size, MarginRequirementType::Initial, false); assert!(result.is_ok()); let initial_margin_ratio = result.unwrap(); assert_eq!(initial_margin_ratio, 1_000 * MARGIN_PRECISION); // 10% // Test maintenance margin ratio - let result = perp_market.get_margin_ratio(size, MarginRequirementType::Maintenance); + let result = perp_market.get_margin_ratio(size, MarginRequirementType::Maintenance, false); assert!(result.is_ok()); let maintenance_margin_ratio = result.unwrap(); assert_eq!(maintenance_margin_ratio, 500); // 5% + + // HL mode + let result = perp_market.get_margin_ratio(size, MarginRequirementType::Maintenance, true); + assert!(result.is_ok()); + let maintenance_margin_ratio = result.unwrap(); + assert_eq!(maintenance_margin_ratio, 1_234); // 5% } #[test] diff --git a/crates/src/math/liquidation.rs b/crates/src/math/liquidation.rs index 2d7704e..0f1704d 100644 --- a/crates/src/math/liquidation.rs +++ b/crates/src/math/liquidation.rs @@ -19,7 +19,7 @@ use crate::{ accounts::{PerpMarket, SpotMarket, User}, MarginRequirementType, PerpPosition, }, - DriftClient, MarketId, SdkError, SdkResult, SpotPosition, + DriftClient, MarginMode, MarketId, SdkError, SdkResult, SpotPosition, }; /// Info on a position's liquidation price and unrealized PnL @@ -178,8 +178,12 @@ pub fn calculate_liquidation_price_inner( let perp_position_with_lp = perp_position.simulate_settled_lp_position(perp_market, oracle_price)?; - let perp_free_collateral_delta = - calculate_perp_free_collateral_delta(&perp_position_with_lp, perp_market, oracle_price); + let perp_free_collateral_delta = calculate_perp_free_collateral_delta( + &perp_position_with_lp, + perp_market, + oracle_price, + user.margin_mode, + ); // user holding spot asset case let mut spot_free_collateral_delta = 0; @@ -210,6 +214,7 @@ fn calculate_perp_free_collateral_delta( position: &PerpPosition, market: &PerpMarket, oracle_price: i64, + margin_mode: MarginMode, ) -> i64 { let current_base_asset_amount = position.base_asset_amount; @@ -220,6 +225,7 @@ fn calculate_perp_free_collateral_delta( .get_margin_ratio( worst_case_base_amount.unsigned_abs(), MarginRequirementType::Maintenance, + margin_mode == MarginMode::HighLeverage, ) .unwrap(); let margin_ratio = (margin_ratio as i64 * QUOTE_PRECISION_I64) / MARGIN_PRECISION as i64; diff --git a/res/drift.json b/res/drift.json index 2374bf4..c72e535 100644 --- a/res/drift.json +++ b/res/drift.json @@ -1,5 +1,5 @@ { - "version": "2.97.0", + "version": "2.100.0", "name": "drift", "instructions": [ { @@ -144,7 +144,7 @@ }, { "name": "user", - "isMut": true, + "isMut": false, "isSigner": false }, { @@ -163,7 +163,43 @@ "isSigner": false } ], - "args": [] + "args": [ + { + "name": "numOrders", + "type": "u16" + } + ] + }, + { + "name": "resizeSwiftUserOrders", + "accounts": [ + { + "name": "swiftUserOrders", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "user", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "numOrders", + "type": "u16" + } + ] }, { "name": "initializeReferrerName", @@ -1422,6 +1458,32 @@ ], "args": [] }, + { + "name": "deleteSwiftUserOrders", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "swiftUserOrders", + "isMut": true, + "isSigner": false + }, + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [] + }, { "name": "reclaimRent", "accounts": [ @@ -1751,6 +1813,27 @@ ], "args": [] }, + { + "name": "updateUserStatsReferrerStatus", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, { "name": "updateUserOpenOrdersCount", "accounts": [ @@ -7568,6 +7651,9 @@ }, { "name": "SwiftUserOrders", + "docs": [ + "* This struct is a duplicate of SwiftUserOrdersZeroCopy\n * It is used to give anchor an struct to generate the idl for clients\n * The struct SwiftUserOrdersZeroCopy is used to load the data in efficiently" + ], "type": { "kind": "struct", "fields": [ @@ -7575,15 +7661,16 @@ "name": "userPubkey", "type": "publicKey" }, + { + "name": "padding", + "type": "u32" + }, { "name": "swiftOrderData", "type": { - "array": [ - { - "defined": "SwiftOrderId" - }, - 32 - ] + "vec": { + "defined": "SwiftOrderId" + } } } ] @@ -9789,6 +9876,30 @@ { "name": "orderId", "type": "u32" + }, + { + "name": "padding", + "type": "u32" + } + ] + } + }, + { + "name": "SwiftUserOrdersFixed", + "type": { + "kind": "struct", + "fields": [ + { + "name": "userPubkey", + "type": "publicKey" + }, + { + "name": "padding", + "type": "u32" + }, + { + "name": "len", + "type": "u32" } ] } @@ -10692,7 +10803,10 @@ "name": "PlaceAndMake" }, { - "name": "PlaceAndTake" + "name": "PlaceAndTake", + "fields": [ + "bool" + ] }, { "name": "Liquidation" @@ -10888,6 +11002,9 @@ }, { "name": "Liquidation" + }, + { + "name": "AmmImmediateFill" } ] } @@ -11030,6 +11147,23 @@ ] } }, + { + "name": "AMMAvailability", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Immediate" + }, + { + "name": "AfterMinDuration" + }, + { + "name": "Unavailable" + } + ] + } + }, { "name": "SettlePnlMode", "type": { @@ -11120,6 +11254,9 @@ }, { "name": "SettlePnlPaused" + }, + { + "name": "AmmImmediateFillPaused" } ] } @@ -11681,6 +11818,7 @@ }, { "name": "hash", + "doc": "capitalized to (S)tring for drift-idl-gen to work easier", "type": "String", "index": false },