From c8efabec594969f5d462afe39f0dccd08783e079 Mon Sep 17 00:00:00 2001 From: jordy25519 Date: Mon, 18 Nov 2024 12:32:33 -0500 Subject: [PATCH 1/6] Add resize drift user orders --- crates/drift-idl-gen/src/lib.rs | 75 +++++--- crates/src/drift_idl.rs | 313 ++++++++++++++++++++++++++++++-- crates/src/ffi.rs | 17 +- crates/src/math/liquidation.rs | 12 +- res/drift.json | 158 +++++++++++++++- 5 files changed, 518 insertions(+), 57 deletions(-) diff --git a/crates/drift-idl-gen/src/lib.rs b/crates/drift-idl-gen/src/lib.rs index 04b5094..5023647 100644 --- a/crates/drift-idl-gen/src/lib.rs +++ b/crates/drift-idl-gen/src/lib.rs @@ -264,34 +264,70 @@ 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 { + dbg!(&field.name, "has vec"); + 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 +335,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..6f4a5c2 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,29 @@ mod tests { margin_ratio_initial: 1_000 * MARGIN_PRECISION, // 10% margin_ratio_maintenance: 500, // 5% imf_factor: 0, // No impact for simplicity + high_leverage_margin_ratio_maintenance: 1_234, ..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 }, From a322c7b993daf2fd43fe7156b296ea0bc49340d9 Mon Sep 17 00:00:00 2001 From: jordy25519 Date: Mon, 18 Nov 2024 13:25:58 -0500 Subject: [PATCH 2/6] high maintenance mode --- build.rs | 86 ++++++++++++++++++--------------- crates/drift-ffi-sys | 2 +- crates/drift-idl-gen/src/lib.rs | 1 - crates/src/ffi.rs | 2 + 4 files changed, 49 insertions(+), 42 deletions(-) diff --git a/build.rs b/build.rs index dca5a95..bd6bdee 100644 --- a/build.rs +++ b/build.rs @@ -59,51 +59,57 @@ fn main() { fail_build(); } - // Build ffi crate and link - let mut ffi_build = std::process::Command::new("rustup"); - ffi_build - .env_clear() - .envs(ffi_build_envs) - .current_dir(drift_ffi_sys_crate.clone()) - .args(["run", &ffi_toolchain, "cargo", "build"]); - - match profile.as_str() { - "debug" => (), - "release" => { - ffi_build.arg("--release"); + // install the dylib to system path + let lib_major_v = std::env::var("CARGO_PKG_VERSION_MAJOR").unwrap(); + let lib_minor_v = std::env::var("CARGO_PKG_VERSION_MINOR").unwrap(); + let libffi_out_path = drift_ffi_sys_crate.join(Path::new(&format!( + "target/{profile}/{LIB}.{lib_ext}.{lib_major_v}.{lib_minor_v}" + ))); + + if !libffi_out_path.exists() { + // Build ffi crate and link + let mut ffi_build = std::process::Command::new("rustup"); + ffi_build + .env_clear() + .envs(ffi_build_envs) + .current_dir(drift_ffi_sys_crate.clone()) + .args(["run", &ffi_toolchain, "cargo", "build"]); + + match profile.as_str() { + "debug" => (), + "release" => { + ffi_build.arg("--release"); + } + custom => { + ffi_build.arg(format!("--profile={custom}")); + } } - custom => { - ffi_build.arg(format!("--profile={custom}")); + + let output = ffi_build.output().expect("drift-ffi-sys built"); + if !output.status.success() { + eprintln!(" {}", String::from_utf8_lossy(output.stderr.as_slice())); + fail_build(); } - } - let output = ffi_build.output().expect("drift-ffi-sys built"); - if !output.status.success() { - eprintln!(" {}", String::from_utf8_lossy(output.stderr.as_slice())); - fail_build(); - } + if !output.status.success() { + eprintln!( + "{LIB} could not be installed: {}", + String::from_utf8_lossy(output.stderr.as_slice()) + ); + } - if !output.status.success() { - eprintln!( - "{LIB} could not be installed: {}", - 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") + .args([ + libffi_out_path.to_str().expect("ffi build path"), + out_dir.as_str(), + ]) + .output() + .expect("install ok"); + println!("{LIB}: searching for lib at: {out_dir}"); + println!("cargo:rustc-link-search=native={out_dir}"); + } - if let Ok(out_dir) = std::env::var("OUT_DIR") { - let _output = std::process::Command::new("cp") - .args([ - libffi_out_path.to_str().expect("ffi build path"), - out_dir.as_str(), - ]) - .output() - .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", diff --git a/crates/drift-ffi-sys b/crates/drift-ffi-sys index 719a0f9..bdbc10f 160000 --- a/crates/drift-ffi-sys +++ b/crates/drift-ffi-sys @@ -1 +1 @@ -Subproject commit 719a0f9511a5bb49228841ff1e3c500025dfcc40 +Subproject commit bdbc10f2895f8ac362cfe80af19ece3e43f72d86 diff --git a/crates/drift-idl-gen/src/lib.rs b/crates/drift-idl-gen/src/lib.rs index 5023647..393b46f 100644 --- a/crates/drift-idl-gen/src/lib.rs +++ b/crates/drift-idl-gen/src/lib.rs @@ -273,7 +273,6 @@ fn generate_idl_types(idl: &Idl) -> String { let field_name = Ident::new(&to_snake_case(&field.name), proc_macro2::Span::call_site()); if let ArgType::Vec { .. } = field.field_type { - dbg!(&field.name, "has vec"); has_vec_field = true; } let mut serde_decorator = TokenStream::new(); diff --git a/crates/src/ffi.rs b/crates/src/ffi.rs index 6f4a5c2..eaf6c2b 100644 --- a/crates/src/ffi.rs +++ b/crates/src/ffi.rs @@ -655,7 +655,9 @@ 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() }; From cc260b740566c451d0864635e807342ed4f159c2 Mon Sep 17 00:00:00 2001 From: jordy25519 Date: Mon, 18 Nov 2024 16:18:22 -0500 Subject: [PATCH 3/6] CI use built ffi lib --- .github/workflows/build.yml | 14 +++++++------- build.rs | 7 ++----- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9efb74f..2dbd5f1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,13 +30,13 @@ jobs: run: | rustup show active-toolchain 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 - unzip ffi.zip - ldd libdrift_ffi_sys.so - sudo cp libdrift_ffi_sys.so /usr/lib - ldconfig -p + # - name: install libdrift_ffi_sys + # run: | + # curl -L https://github.com/user-attachments/files/17160233/libdrift_ffi_sys.so.zip > ffi.zip + # unzip ffi.zip + # ldd libdrift_ffi_sys.so + # sudo cp libdrift_ffi_sys.so /usr/lib + # ldconfig -p - name: Format run: cargo fmt --all -- --check - name: Build diff --git a/build.rs b/build.rs index bd6bdee..d82067e 100644 --- a/build.rs +++ b/build.rs @@ -60,11 +60,8 @@ fn main() { } // install the dylib to system path - let lib_major_v = std::env::var("CARGO_PKG_VERSION_MAJOR").unwrap(); - let lib_minor_v = std::env::var("CARGO_PKG_VERSION_MINOR").unwrap(); - let libffi_out_path = drift_ffi_sys_crate.join(Path::new(&format!( - "target/{profile}/{LIB}.{lib_ext}.{lib_major_v}.{lib_minor_v}" - ))); + let libffi_out_path = + drift_ffi_sys_crate.join(Path::new(&format!("target/{profile}/{LIB}.{lib_ext}"))); if !libffi_out_path.exists() { // Build ffi crate and link From 08df3c27f7d1a2356e2e56a3e4674fd545d7c853 Mon Sep 17 00:00:00 2001 From: jordy25519 Date: Mon, 18 Nov 2024 16:23:24 -0500 Subject: [PATCH 4/6] CI use built ffi lib --- .github/workflows/build.yml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2dbd5f1..c1fc1d0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,13 +30,6 @@ jobs: run: | rustup show active-toolchain 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 - # unzip ffi.zip - # ldd libdrift_ffi_sys.so - # sudo cp libdrift_ffi_sys.so /usr/lib - # ldconfig -p - name: Format run: cargo fmt --all -- --check - name: Build @@ -59,5 +52,4 @@ jobs: RUST_LOG: info TEST_DEVNET_RPC_ENDPOINT: ${{ secrets.DEVNET_RPC_ENDPOINT }} TEST_MAINNET_RPC_ENDPOINT: ${{ secrets.MAINNET_RPC_ENDPOINT }} - TEST_PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY }} - CARGO_DRIFT_FFI_PATH: "/usr/lib" \ No newline at end of file + TEST_PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY }} \ No newline at end of file From 94d4b4c31dd634d5fb7a8c8fc6224bb202ff7ebd Mon Sep 17 00:00:00 2001 From: jordy25519 Date: Mon, 18 Nov 2024 16:54:16 -0500 Subject: [PATCH 5/6] update ffi lib for ci --- .github/workflows/build.yml | 10 +++++++++- crates/drift-ffi-sys | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c1fc1d0..43c6676 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,6 +30,13 @@ jobs: run: | rustup show active-toolchain rustup component add clippy rustfmt + - name: install libdrift_ffi_sys + run: | + 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 + ldconfig -p - name: Format run: cargo fmt --all -- --check - name: Build @@ -52,4 +59,5 @@ jobs: RUST_LOG: info TEST_DEVNET_RPC_ENDPOINT: ${{ secrets.DEVNET_RPC_ENDPOINT }} TEST_MAINNET_RPC_ENDPOINT: ${{ secrets.MAINNET_RPC_ENDPOINT }} - TEST_PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY }} \ No newline at end of file + TEST_PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY }} + CARGO_DRIFT_FFI_PATH: "/usr/lib" \ No newline at end of file diff --git a/crates/drift-ffi-sys b/crates/drift-ffi-sys index bdbc10f..0d5df4c 160000 --- a/crates/drift-ffi-sys +++ b/crates/drift-ffi-sys @@ -1 +1 @@ -Subproject commit bdbc10f2895f8ac362cfe80af19ece3e43f72d86 +Subproject commit 0d5df4c857466cb9132763bb925d94c9a1b96f5c From 7ee18c33d4e693da867928c5ebab57c7b92afba6 Mon Sep 17 00:00:00 2001 From: jordy25519 Date: Mon, 18 Nov 2024 17:17:03 -0500 Subject: [PATCH 6/6] tidy up --- build.rs | 88 +++++++++++++++++++++++++++----------------------------- 1 file changed, 43 insertions(+), 45 deletions(-) diff --git a/build.rs b/build.rs index d82067e..e2b7eb4 100644 --- a/build.rs +++ b/build.rs @@ -63,62 +63,60 @@ fn main() { let libffi_out_path = drift_ffi_sys_crate.join(Path::new(&format!("target/{profile}/{LIB}.{lib_ext}"))); - if !libffi_out_path.exists() { - // Build ffi crate and link - let mut ffi_build = std::process::Command::new("rustup"); - ffi_build - .env_clear() - .envs(ffi_build_envs) - .current_dir(drift_ffi_sys_crate.clone()) - .args(["run", &ffi_toolchain, "cargo", "build"]); - - match profile.as_str() { - "debug" => (), - "release" => { - ffi_build.arg("--release"); - } - custom => { - ffi_build.arg(format!("--profile={custom}")); - } + // Build ffi crate and link + let mut ffi_build = std::process::Command::new("rustup"); + ffi_build + .env_clear() + .envs(ffi_build_envs) + .current_dir(drift_ffi_sys_crate.clone()) + .args(["run", &ffi_toolchain, "cargo", "build"]); + + match profile.as_str() { + "debug" => (), + "release" => { + ffi_build.arg("--release"); } - - let output = ffi_build.output().expect("drift-ffi-sys built"); - if !output.status.success() { - eprintln!(" {}", String::from_utf8_lossy(output.stderr.as_slice())); - fail_build(); + custom => { + ffi_build.arg(format!("--profile={custom}")); } + } - if !output.status.success() { - eprintln!( - "{LIB} could not be installed: {}", - String::from_utf8_lossy(output.stderr.as_slice()) - ); - } + let output = ffi_build.output().expect("drift-ffi-sys built"); + if !output.status.success() { + eprintln!(" {}", String::from_utf8_lossy(output.stderr.as_slice())); + fail_build(); + } - if let Ok(out_dir) = std::env::var("OUT_DIR") { - let _output = std::process::Command::new("cp") - .args([ - libffi_out_path.to_str().expect("ffi build path"), - out_dir.as_str(), - ]) - .output() - .expect("install ok"); - println!("{LIB}: searching for lib at: {out_dir}"); - println!("cargo:rustc-link-search=native={out_dir}"); - } + if !output.status.success() { + eprintln!( + "{LIB} could not be installed: {}", + String::from_utf8_lossy(output.stderr.as_slice()) + ); + } - let _output = std::process::Command::new("ln") + if let Ok(out_dir) = std::env::var("OUT_DIR") { + let _output = std::process::Command::new("cp") .args([ - "-sf", libffi_out_path.to_str().expect("ffi build path"), - "/usr/local/lib/", + out_dir.as_str(), ]) .output() .expect("install ok"); - - println!("{LIB}: searching for lib at: /usr/local/lib"); - println!("cargo:rustc-link-search=native=/usr/local/lib"); + println!("{LIB}: searching for lib at: {out_dir}"); + println!("cargo:rustc-link-search=native={out_dir}"); } + + 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") {