diff --git a/build.rs b/build.rs index 3908664..dca5a95 100644 --- a/build.rs +++ b/build.rs @@ -83,24 +83,39 @@ 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}"))); - 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"); - 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}"); + } 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"); + } } if let Ok(lib_path) = std::env::var("CARGO_DRIFT_FFI_PATH") { diff --git a/crates/src/dlob/dlob.rs b/crates/src/dlob/dlob.rs index e10ce22..345035c 100644 --- a/crates/src/dlob/dlob.rs +++ b/crates/src/dlob/dlob.rs @@ -11,13 +11,10 @@ use crate::{ dlob_node::{create_node, get_order_signature, DLOBNode, DirectionalNode, Node, NodeType}, market::{get_node_subtype_and_type, Exchange, OpenOrders, SubType}, }, - drift_idl::{ - ffi::OraclePriceData, - types::{MarketType, Order, OrderStatus}, - }, + drift_idl::types::{MarketType, Order, OrderStatus}, + ffi::OraclePriceData, math::order::is_resting_limit_order, - usermap::UserMap, - utils::market_type_to_string, + usermap::GlobalUserMap as UserMap, }; #[derive(Clone)] @@ -80,7 +77,7 @@ impl DLOB { } pub fn insert_order(&self, order: &Order, user_account: Pubkey, slot: u64) { - let market_type = market_type_to_string(&order.market_type); + let market_type = order.market_type.as_str(); let market_index = order.market_index; let (subtype, node_type) = get_node_subtype_and_type(order, slot); diff --git a/crates/src/dlob/dlob_builder.rs b/crates/src/dlob/dlob_builder.rs index 692c8cb..1b9547e 100644 --- a/crates/src/dlob/dlob_builder.rs +++ b/crates/src/dlob/dlob_builder.rs @@ -3,8 +3,7 @@ use std::sync::Arc; use tokio::sync::Mutex; use crate::{ - dlob::dlob::DLOB, event_emitter::EventEmitter, slot_subscriber::SlotSubscriber, - usermap::UserMap, SdkResult, + dlob::dlob::DLOB, slot_subscriber::SlotSubscriber, usermap::GlobalUserMap as UserMap, SdkResult, }; pub struct DLOBBuilder { @@ -12,7 +11,6 @@ pub struct DLOBBuilder { usermap: UserMap, rebuild_frequency: u64, dlob: DLOB, - event_emitter: EventEmitter, } impl DLOBBuilder { @@ -28,14 +26,13 @@ impl DLOBBuilder { usermap, rebuild_frequency, dlob: DLOB::new(), - event_emitter: EventEmitter::new(), } } pub async fn start_building(builder: Arc>) -> SdkResult<()> { let mut locked_builder = builder.lock().await; let rebuild_frequency = locked_builder.rebuild_frequency; - locked_builder.slot_subscriber.subscribe().await?; + locked_builder.slot_subscriber.subscribe(move |_slot| {}); locked_builder.usermap.subscribe().await?; drop(locked_builder); @@ -54,10 +51,10 @@ impl DLOBBuilder { Ok(()) } - pub fn build(&mut self) { + pub fn build(&mut self) -> &DLOB { self.dlob .build_from_usermap(&self.usermap, self.slot_subscriber.current_slot()); - self.event_emitter.emit(self.dlob.clone()); + &self.dlob } pub fn get_dlob(&self) -> DLOB { @@ -91,14 +88,11 @@ mod tests { ); let dlob_builder = DLOBBuilder::new(slot_subscriber, usermap, 5); - dlob_builder - .event_emitter - .clone() - .subscribe(DLOBBuilder::SUBSCRIPTION_ID, move |event| { - if let Some(_) = event.as_any().downcast_ref::() { - // dbg!("update received"); - } - }); + dlob_builder.subscribe(DLOBBuilder::SUBSCRIPTION_ID, move |event| { + if let Some(_) = event.as_any().downcast_ref::() { + // dbg!("update received"); + } + }); DLOBBuilder::start_building(Arc::new(Mutex::new(dlob_builder))) .await diff --git a/crates/src/dlob/dlob_node.rs b/crates/src/dlob/dlob_node.rs index 1625403..79f3b1e 100644 --- a/crates/src/dlob/dlob_node.rs +++ b/crates/src/dlob/dlob_node.rs @@ -1,9 +1,6 @@ use solana_sdk::pubkey::Pubkey; -use crate::{ - drift_idl::{ffi::OraclePriceData, types::Order}, - math::order::get_limit_price, -}; +use crate::{drift_idl::types::Order, ffi::OraclePriceData, math::order::get_limit_price}; #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum NodeType { diff --git a/crates/src/dlob/market.rs b/crates/src/dlob/market.rs index c8d3437..f6218d8 100644 --- a/crates/src/dlob/market.rs +++ b/crates/src/dlob/market.rs @@ -78,7 +78,14 @@ impl Market { } pub(crate) fn get_node_subtype_and_type(order: &Order, slot: u64) -> (SubType, NodeType) { - let is_inactive_trigger_order = order.must_be_triggered() && !order.triggered(); + // let is_inactive_trigger_order = order.must_be_triggered() && !order.triggered(); + let is_inactive_trigger_order = match (order.order_type, order.trigger_condition) { + ( + OrderType::TriggerMarket | OrderType::TriggerLimit, + OrderTriggerCondition::TriggeredAbove | OrderTriggerCondition::TriggeredBelow, + ) => true, + _ => false, + }; let node_type = if is_inactive_trigger_order { NodeType::Trigger diff --git a/crates/src/drift_idl.rs b/crates/src/drift_idl.rs index f5f848f..edcb4ab 100644 --- a/crates/src/drift_idl.rs +++ b/crates/src/drift_idl.rs @@ -44,6 +44,22 @@ pub mod instructions { #[automatically_derived] impl anchor_lang::InstructionData for InitializeUserStats {} #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] + pub struct InitializeRfqUser {} + #[automatically_derived] + impl anchor_lang::Discriminator for InitializeRfqUser { + const DISCRIMINATOR: [u8; 8] = [87, 2, 27, 16, 186, 206, 169, 38]; + } + #[automatically_derived] + impl anchor_lang::InstructionData for InitializeRfqUser {} + #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] + pub struct InitializeSwiftUserOrders {} + #[automatically_derived] + impl anchor_lang::Discriminator for InitializeSwiftUserOrders { + const DISCRIMINATOR: [u8; 8] = [26, 91, 2, 246, 96, 153, 117, 194]; + } + #[automatically_derived] + impl anchor_lang::InstructionData for InitializeSwiftUserOrders {} + #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] pub struct InitializeReferrerName { pub name: [u8; 32], } @@ -185,10 +201,20 @@ pub mod instructions { #[automatically_derived] impl anchor_lang::InstructionData for PlaceAndMakePerpOrder {} #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] + pub struct PlaceAndMakeSwiftPerpOrder { + pub params: OrderParams, + pub swift_order_uuid: [u8; 8], + } + #[automatically_derived] + impl anchor_lang::Discriminator for PlaceAndMakeSwiftPerpOrder { + const DISCRIMINATOR: [u8; 8] = [0, 160, 153, 76, 136, 212, 248, 16]; + } + #[automatically_derived] + impl anchor_lang::InstructionData for PlaceAndMakeSwiftPerpOrder {} + #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] pub struct PlaceSwiftTakerOrder { pub swift_message_bytes: Vec, pub swift_order_params_message_bytes: Vec, - pub swift_message_signature: Signature, } #[automatically_derived] impl anchor_lang::Discriminator for PlaceSwiftTakerOrder { @@ -197,6 +223,16 @@ pub mod instructions { #[automatically_derived] impl anchor_lang::InstructionData for PlaceSwiftTakerOrder {} #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] + pub struct PlaceAndMatchRfqOrders { + pub rfq_matches: Vec, + } + #[automatically_derived] + impl anchor_lang::Discriminator for PlaceAndMatchRfqOrders { + const DISCRIMINATOR: [u8; 8] = [111, 3, 51, 243, 178, 174, 219, 100]; + } + #[automatically_derived] + impl anchor_lang::InstructionData for PlaceAndMatchRfqOrders {} + #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] pub struct PlaceSpotOrder { pub params: OrderParams, } @@ -381,6 +417,16 @@ pub mod instructions { #[automatically_derived] impl anchor_lang::InstructionData for ReclaimRent {} #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] + pub struct EnableUserHighLeverageMode { + pub sub_account_id: u16, + } + #[automatically_derived] + impl anchor_lang::Discriminator for EnableUserHighLeverageMode { + const DISCRIMINATOR: [u8; 8] = [231, 24, 230, 112, 201, 173, 73, 184]; + } + #[automatically_derived] + impl anchor_lang::InstructionData for EnableUserHighLeverageMode {} + #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] pub struct FillPerpOrder { pub order_id: Option, pub maker_order_id: Option, @@ -438,6 +484,14 @@ pub mod instructions { #[automatically_derived] impl anchor_lang::InstructionData for UpdateUserIdle {} #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] + pub struct DisableUserHighLeverageMode {} + #[automatically_derived] + impl anchor_lang::Discriminator for DisableUserHighLeverageMode { + const DISCRIMINATOR: [u8; 8] = [183, 155, 45, 0, 226, 85, 213, 69]; + } + #[automatically_derived] + impl anchor_lang::InstructionData for DisableUserHighLeverageMode {} + #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] pub struct UpdateUserFuelBonus {} #[automatically_derived] impl anchor_lang::Discriminator for UpdateUserFuelBonus { @@ -1083,6 +1137,17 @@ pub mod instructions { #[automatically_derived] impl anchor_lang::InstructionData for UpdatePerpMarketMarginRatio {} #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] + pub struct UpdatePerpMarketHighLeverageMarginRatio { + pub margin_ratio_initial: u16, + pub margin_ratio_maintenance: u16, + } + #[automatically_derived] + impl anchor_lang::Discriminator for UpdatePerpMarketHighLeverageMarginRatio { + const DISCRIMINATOR: [u8; 8] = [88, 112, 86, 49, 24, 116, 74, 157]; + } + #[automatically_derived] + impl anchor_lang::InstructionData for UpdatePerpMarketHighLeverageMarginRatio {} + #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] pub struct UpdatePerpMarketFundingPeriod { pub funding_period: i64, } @@ -1801,6 +1866,27 @@ pub mod instructions { } #[automatically_derived] impl anchor_lang::InstructionData for InitializePythPullOracle {} + #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] + pub struct InitializeHighLeverageModeConfig { + pub max_users: u32, + } + #[automatically_derived] + impl anchor_lang::Discriminator for InitializeHighLeverageModeConfig { + const DISCRIMINATOR: [u8; 8] = [213, 167, 93, 246, 208, 130, 90, 248]; + } + #[automatically_derived] + impl anchor_lang::InstructionData for InitializeHighLeverageModeConfig {} + #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] + pub struct UpdateHighLeverageModeConfig { + pub max_users: u32, + pub reduce_only: bool, + } + #[automatically_derived] + impl anchor_lang::Discriminator for UpdateHighLeverageModeConfig { + const DISCRIMINATOR: [u8; 8] = [64, 122, 212, 93, 141, 217, 202, 55]; + } + #[automatically_derived] + impl anchor_lang::InstructionData for UpdateHighLeverageModeConfig {} } pub mod types { #![doc = r" IDL types"] @@ -2176,6 +2262,7 @@ pub mod types { PartialEq, )] pub struct SwiftServerMessage { + pub uuid: [u8; 8], pub swift_order_signature: Signature, pub slot: u64, } @@ -2194,7 +2281,6 @@ pub mod types { )] pub struct SwiftOrderParamsMessage { pub swift_order_params: OrderParams, - pub expected_order_id: i32, pub sub_account_id: u16, pub take_profit_order_params: Option, pub stop_loss_order_params: Option, @@ -2229,6 +2315,65 @@ pub mod types { Debug, PartialEq, )] + pub struct RFQMakerOrderParams { + pub uuid: [u8; 8], + pub authority: Pubkey, + pub sub_account_id: u16, + pub market_index: u16, + pub market_type: MarketType, + pub base_asset_amount: u64, + pub price: u64, + pub direction: PositionDirection, + pub max_ts: i64, + } + #[repr(C)] + #[derive( + AnchorSerialize, + AnchorDeserialize, + InitSpace, + Serialize, + Deserialize, + Copy, + Clone, + Default, + Debug, + PartialEq, + )] + pub struct RFQMakerMessage { + pub order_params: RFQMakerOrderParams, + pub signature: Signature, + } + #[repr(C)] + #[derive( + AnchorSerialize, + AnchorDeserialize, + InitSpace, + Serialize, + Deserialize, + Copy, + Clone, + Default, + Debug, + PartialEq, + )] + pub struct RFQMatch { + pub base_asset_amount: u64, + pub maker_order_params: RFQMakerOrderParams, + pub maker_signature: Signature, + } + #[repr(C)] + #[derive( + AnchorSerialize, + AnchorDeserialize, + InitSpace, + Serialize, + Deserialize, + Copy, + Clone, + Default, + Debug, + PartialEq, + )] pub struct ModifyOrderParams { pub direction: Option, pub base_asset_amount: Option, @@ -2395,6 +2540,23 @@ pub mod types { Debug, PartialEq, )] + pub struct RFQOrderId { + pub uuid: [u8; 8], + pub max_ts: i64, + } + #[repr(C)] + #[derive( + AnchorSerialize, + AnchorDeserialize, + InitSpace, + Serialize, + Deserialize, + Copy, + Clone, + Default, + Debug, + PartialEq, + )] pub struct InsuranceFund { pub vault: Pubkey, pub total_shares: u128, @@ -2532,6 +2694,24 @@ pub mod types { Debug, PartialEq, )] + pub struct SwiftOrderId { + pub uuid: [u8; 8], + pub max_slot: u64, + pub order_id: u32, + } + #[repr(C)] + #[derive( + AnchorSerialize, + AnchorDeserialize, + InitSpace, + Serialize, + Deserialize, + Copy, + Clone, + Default, + Debug, + PartialEq, + )] pub struct UserFees { pub total_fee_paid: u64, pub total_fee_rebate: u64, @@ -3025,6 +3205,7 @@ pub mod types { PlaceAndMake, PlaceAndTake, Liquidation, + RFQ, } #[derive( AnchorSerialize, @@ -3504,6 +3685,40 @@ pub mod types { Spot, Perp, } + #[derive( + AnchorSerialize, + AnchorDeserialize, + InitSpace, + Serialize, + Deserialize, + Copy, + Clone, + Default, + Debug, + PartialEq, + )] + pub enum ReferrerStatus { + #[default] + IsReferrer, + IsReferred, + } + #[derive( + AnchorSerialize, + AnchorDeserialize, + InitSpace, + Serialize, + Deserialize, + Copy, + Clone, + Default, + Debug, + PartialEq, + )] + pub enum MarginMode { + #[default] + Default, + HighLeverage, + } } pub mod accounts { #![doc = r" IDL Account types"] @@ -3724,6 +3939,65 @@ pub mod accounts { Debug, PartialEq, )] + pub struct HighLeverageModeConfig { + pub max_users: u32, + pub current_users: u32, + pub reduce_only: u8, + #[serde(skip)] + pub padding: Padding<31>, + } + #[automatically_derived] + impl anchor_lang::Discriminator for HighLeverageModeConfig { + const DISCRIMINATOR: [u8; 8] = [3, 196, 90, 189, 193, 64, 228, 234]; + } + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Pod for HighLeverageModeConfig {} + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Zeroable for HighLeverageModeConfig {} + #[automatically_derived] + impl anchor_lang::ZeroCopy for HighLeverageModeConfig {} + #[automatically_derived] + impl anchor_lang::AccountSerialize for HighLeverageModeConfig { + 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 HighLeverageModeConfig { + 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( + AnchorSerialize, + AnchorDeserialize, + InitSpace, + Serialize, + Deserialize, + Copy, + Clone, + Default, + Debug, + PartialEq, + )] pub struct InsuranceFundStake { pub authority: Pubkey, pub if_shares: u128, @@ -3943,8 +4217,11 @@ pub mod accounts { pub fuel_boost_position: u8, pub fuel_boost_taker: u8, pub fuel_boost_maker: u8, + pub padding1: u8, + pub high_leverage_margin_ratio_initial: u16, + pub high_leverage_margin_ratio_maintenance: u16, #[serde(skip)] - pub padding: Padding<43>, + pub padding: Padding<38>, } #[automatically_derived] impl anchor_lang::Discriminator for PerpMarket { @@ -3998,6 +4275,62 @@ pub mod accounts { Debug, PartialEq, )] + pub struct RFQUser { + pub user_pubkey: Pubkey, + pub rfq_order_data: [RFQOrderId; 32], + } + #[automatically_derived] + impl anchor_lang::Discriminator for RFQUser { + const DISCRIMINATOR: [u8; 8] = [213, 84, 187, 159, 70, 112, 52, 186]; + } + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Pod for RFQUser {} + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Zeroable for RFQUser {} + #[automatically_derived] + impl anchor_lang::ZeroCopy for RFQUser {} + #[automatically_derived] + impl anchor_lang::AccountSerialize for RFQUser { + 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 RFQUser { + 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( + AnchorSerialize, + AnchorDeserialize, + InitSpace, + Serialize, + Deserialize, + Copy, + Clone, + Default, + Debug, + PartialEq, + )] pub struct SpotMarket { pub pubkey: Pubkey, pub oracle: Pubkey, @@ -4196,13 +4529,69 @@ pub mod accounts { Debug, PartialEq, )] - pub struct User { - pub authority: Pubkey, - pub delegate: Pubkey, - pub name: [u8; 32], - pub spot_positions: [SpotPosition; 8], - pub perp_positions: [PerpPosition; 8], - pub orders: [Order; 32], + pub struct SwiftUserOrders { + pub user_pubkey: Pubkey, + pub swift_order_data: [SwiftOrderId; 32], + } + #[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() { + 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 SwiftUserOrders { + 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( + AnchorSerialize, + AnchorDeserialize, + InitSpace, + Serialize, + Deserialize, + Copy, + Clone, + Default, + Debug, + PartialEq, + )] + pub struct User { + pub authority: Pubkey, + pub delegate: Pubkey, + pub name: [u8; 32], + pub spot_positions: [SpotPosition; 8], + pub perp_positions: [PerpPosition; 8], + pub orders: [Order; 32], pub last_add_perp_lp_shares_ts: i64, pub total_deposits: u64, pub total_withdraws: u64, @@ -4223,7 +4612,8 @@ pub mod accounts { pub has_open_order: bool, pub open_auctions: u8, pub has_open_auction: bool, - pub padding1: [u8; 5], + pub margin_mode: MarginMode, + pub padding1: [u8; 4], pub last_fuel_bonus_update_ts: u32, #[serde(skip)] pub padding: Padding<12>, @@ -4294,7 +4684,7 @@ pub mod accounts { pub if_staked_quote_asset_amount: u64, pub number_of_sub_accounts: u16, pub number_of_sub_accounts_created: u16, - pub is_referrer: bool, + pub referrer_status: u8, pub disable_update_perp_bid_ask_twap: bool, pub padding1: [u8; 2], pub fuel_insurance: u32, @@ -4589,6 +4979,182 @@ pub mod accounts { } #[repr(C)] #[derive(Copy, Clone, Default, AnchorSerialize, AnchorDeserialize, Serialize, Deserialize)] + pub struct InitializeRfqUser { + pub rfq_user: Pubkey, + pub authority: Pubkey, + pub user: Pubkey, + pub payer: Pubkey, + pub rent: Pubkey, + pub system_program: Pubkey, + } + #[automatically_derived] + impl anchor_lang::Discriminator for InitializeRfqUser { + const DISCRIMINATOR: [u8; 8] = [92, 138, 138, 72, 176, 27, 12, 100]; + } + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Pod for InitializeRfqUser {} + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Zeroable for InitializeRfqUser {} + #[automatically_derived] + impl anchor_lang::ZeroCopy for InitializeRfqUser {} + #[automatically_derived] + impl anchor_lang::InstructionData for InitializeRfqUser {} + #[automatically_derived] + impl ToAccountMetas for InitializeRfqUser { + fn to_account_metas(&self) -> Vec { + vec![ + AccountMeta { + pubkey: self.rfq_user, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: self.authority, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: self.user, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: self.payer, + is_signer: true, + is_writable: true, + }, + AccountMeta { + pubkey: self.rent, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: self.system_program, + is_signer: false, + is_writable: false, + }, + ] + } + } + #[automatically_derived] + impl anchor_lang::AccountSerialize for InitializeRfqUser { + 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 InitializeRfqUser { + 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 InitializeSwiftUserOrders { + pub swift_user_orders: Pubkey, + pub authority: Pubkey, + pub user: Pubkey, + pub payer: Pubkey, + pub rent: Pubkey, + pub system_program: Pubkey, + } + #[automatically_derived] + impl anchor_lang::Discriminator for InitializeSwiftUserOrders { + const DISCRIMINATOR: [u8; 8] = [78, 117, 148, 206, 195, 205, 137, 8]; + } + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Pod for InitializeSwiftUserOrders {} + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Zeroable for InitializeSwiftUserOrders {} + #[automatically_derived] + impl anchor_lang::ZeroCopy for InitializeSwiftUserOrders {} + #[automatically_derived] + impl anchor_lang::InstructionData for InitializeSwiftUserOrders {} + #[automatically_derived] + impl ToAccountMetas for InitializeSwiftUserOrders { + 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: false, + }, + AccountMeta { + pubkey: self.user, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: self.payer, + is_signer: true, + is_writable: true, + }, + AccountMeta { + pubkey: self.rent, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: self.system_program, + is_signer: false, + is_writable: false, + }, + ] + } + } + #[automatically_derived] + impl anchor_lang::AccountSerialize for InitializeSwiftUserOrders { + 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 InitializeSwiftUserOrders { + 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, @@ -5619,10 +6185,105 @@ pub mod accounts { } #[repr(C)] #[derive(Copy, Clone, Default, AnchorSerialize, AnchorDeserialize, Serialize, Deserialize)] + pub struct PlaceAndMakeSwiftPerpOrder { + pub state: Pubkey, + pub user: Pubkey, + pub user_stats: Pubkey, + pub taker: Pubkey, + pub taker_stats: Pubkey, + pub taker_swift_user_orders: Pubkey, + pub authority: Pubkey, + } + #[automatically_derived] + impl anchor_lang::Discriminator for PlaceAndMakeSwiftPerpOrder { + const DISCRIMINATOR: [u8; 8] = [126, 41, 46, 87, 157, 255, 202, 213]; + } + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Pod for PlaceAndMakeSwiftPerpOrder {} + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Zeroable for PlaceAndMakeSwiftPerpOrder {} + #[automatically_derived] + impl anchor_lang::ZeroCopy for PlaceAndMakeSwiftPerpOrder {} + #[automatically_derived] + impl anchor_lang::InstructionData for PlaceAndMakeSwiftPerpOrder {} + #[automatically_derived] + impl ToAccountMetas for PlaceAndMakeSwiftPerpOrder { + fn to_account_metas(&self) -> Vec { + vec![ + AccountMeta { + pubkey: self.state, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: self.user, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: self.user_stats, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: self.taker, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: self.taker_stats, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: self.taker_swift_user_orders, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: self.authority, + is_signer: true, + is_writable: false, + }, + ] + } + } + #[automatically_derived] + impl anchor_lang::AccountSerialize for PlaceAndMakeSwiftPerpOrder { + 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 PlaceAndMakeSwiftPerpOrder { + 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 PlaceSwiftTakerOrder { pub state: Pubkey, pub user: Pubkey, pub user_stats: Pubkey, + pub swift_user_orders: Pubkey, pub authority: Pubkey, pub ix_sysvar: Pubkey, } @@ -5657,6 +6318,11 @@ pub mod accounts { is_signer: false, is_writable: true, }, + AccountMeta { + pubkey: self.swift_user_orders, + is_signer: false, + is_writable: true, + }, AccountMeta { pubkey: self.authority, is_signer: true, @@ -5701,6 +6367,88 @@ pub mod accounts { } #[repr(C)] #[derive(Copy, Clone, Default, AnchorSerialize, AnchorDeserialize, Serialize, Deserialize)] + pub struct PlaceAndMatchRfqOrders { + pub state: Pubkey, + pub user: Pubkey, + pub user_stats: Pubkey, + pub authority: Pubkey, + pub ix_sysvar: Pubkey, + } + #[automatically_derived] + impl anchor_lang::Discriminator for PlaceAndMatchRfqOrders { + const DISCRIMINATOR: [u8; 8] = [115, 0, 66, 163, 147, 164, 6, 212]; + } + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Pod for PlaceAndMatchRfqOrders {} + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Zeroable for PlaceAndMatchRfqOrders {} + #[automatically_derived] + impl anchor_lang::ZeroCopy for PlaceAndMatchRfqOrders {} + #[automatically_derived] + impl anchor_lang::InstructionData for PlaceAndMatchRfqOrders {} + #[automatically_derived] + impl ToAccountMetas for PlaceAndMatchRfqOrders { + fn to_account_metas(&self) -> Vec { + vec![ + AccountMeta { + pubkey: self.state, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: self.user, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: self.user_stats, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: self.authority, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: self.ix_sysvar, + is_signer: false, + is_writable: false, + }, + ] + } + } + #[automatically_derived] + impl anchor_lang::AccountSerialize for PlaceAndMatchRfqOrders { + 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 PlaceAndMatchRfqOrders { + 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 PlaceSpotOrder { pub state: Pubkey, pub user: Pubkey, @@ -6987,6 +7735,82 @@ pub mod accounts { } #[repr(C)] #[derive(Copy, Clone, Default, AnchorSerialize, AnchorDeserialize, Serialize, Deserialize)] + pub struct EnableUserHighLeverageMode { + pub state: Pubkey, + pub user: Pubkey, + pub authority: Pubkey, + pub high_leverage_mode_config: Pubkey, + } + #[automatically_derived] + impl anchor_lang::Discriminator for EnableUserHighLeverageMode { + const DISCRIMINATOR: [u8; 8] = [87, 74, 202, 252, 83, 254, 102, 158]; + } + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Pod for EnableUserHighLeverageMode {} + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Zeroable for EnableUserHighLeverageMode {} + #[automatically_derived] + impl anchor_lang::ZeroCopy for EnableUserHighLeverageMode {} + #[automatically_derived] + impl anchor_lang::InstructionData for EnableUserHighLeverageMode {} + #[automatically_derived] + impl ToAccountMetas for EnableUserHighLeverageMode { + fn to_account_metas(&self) -> Vec { + vec![ + AccountMeta { + pubkey: self.state, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: self.user, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: self.authority, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: self.high_leverage_mode_config, + is_signer: false, + is_writable: true, + }, + ] + } + } + #[automatically_derived] + impl anchor_lang::AccountSerialize for EnableUserHighLeverageMode { + 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 EnableUserHighLeverageMode { + 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 FillPerpOrder { pub state: Pubkey, pub authority: Pubkey, @@ -7196,12 +8020,88 @@ pub mod accounts { is_writable: true, }, AccountMeta { - pubkey: self.user, + pubkey: self.user, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: self.user_stats, + is_signer: false, + is_writable: true, + }, + ] + } + } + #[automatically_derived] + impl anchor_lang::AccountSerialize for FillSpotOrder { + 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 FillSpotOrder { + 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 TriggerOrder { + pub state: Pubkey, + pub authority: Pubkey, + pub filler: Pubkey, + pub user: Pubkey, + } + #[automatically_derived] + impl anchor_lang::Discriminator for TriggerOrder { + const DISCRIMINATOR: [u8; 8] = [236, 61, 42, 190, 152, 12, 106, 116]; + } + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Pod for TriggerOrder {} + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Zeroable for TriggerOrder {} + #[automatically_derived] + impl anchor_lang::ZeroCopy for TriggerOrder {} + #[automatically_derived] + impl anchor_lang::InstructionData for TriggerOrder {} + #[automatically_derived] + impl ToAccountMetas for TriggerOrder { + 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.filler, is_signer: false, is_writable: true, }, AccountMeta { - pubkey: self.user_stats, + pubkey: self.user, is_signer: false, is_writable: true, }, @@ -7209,7 +8109,7 @@ pub mod accounts { } } #[automatically_derived] - impl anchor_lang::AccountSerialize for FillSpotOrder { + impl anchor_lang::AccountSerialize for TriggerOrder { 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()); @@ -7221,7 +8121,7 @@ pub mod accounts { } } #[automatically_derived] - impl anchor_lang::AccountDeserialize for FillSpotOrder { + impl anchor_lang::AccountDeserialize for TriggerOrder { fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result { let given_disc = &buf[..8]; if Self::DISCRIMINATOR != given_disc { @@ -7239,26 +8139,26 @@ pub mod accounts { } #[repr(C)] #[derive(Copy, Clone, Default, AnchorSerialize, AnchorDeserialize, Serialize, Deserialize)] - pub struct TriggerOrder { + pub struct ForceCancelOrders { pub state: Pubkey, pub authority: Pubkey, pub filler: Pubkey, pub user: Pubkey, } #[automatically_derived] - impl anchor_lang::Discriminator for TriggerOrder { - const DISCRIMINATOR: [u8; 8] = [236, 61, 42, 190, 152, 12, 106, 116]; + impl anchor_lang::Discriminator for ForceCancelOrders { + const DISCRIMINATOR: [u8; 8] = [108, 153, 180, 51, 37, 158, 99, 93]; } #[automatically_derived] - unsafe impl anchor_lang::__private::bytemuck::Pod for TriggerOrder {} + unsafe impl anchor_lang::__private::bytemuck::Pod for ForceCancelOrders {} #[automatically_derived] - unsafe impl anchor_lang::__private::bytemuck::Zeroable for TriggerOrder {} + unsafe impl anchor_lang::__private::bytemuck::Zeroable for ForceCancelOrders {} #[automatically_derived] - impl anchor_lang::ZeroCopy for TriggerOrder {} + impl anchor_lang::ZeroCopy for ForceCancelOrders {} #[automatically_derived] - impl anchor_lang::InstructionData for TriggerOrder {} + impl anchor_lang::InstructionData for ForceCancelOrders {} #[automatically_derived] - impl ToAccountMetas for TriggerOrder { + impl ToAccountMetas for ForceCancelOrders { fn to_account_metas(&self) -> Vec { vec![ AccountMeta { @@ -7285,7 +8185,7 @@ pub mod accounts { } } #[automatically_derived] - impl anchor_lang::AccountSerialize for TriggerOrder { + impl anchor_lang::AccountSerialize for ForceCancelOrders { 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()); @@ -7297,7 +8197,7 @@ pub mod accounts { } } #[automatically_derived] - impl anchor_lang::AccountDeserialize for TriggerOrder { + impl anchor_lang::AccountDeserialize for ForceCancelOrders { fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result { let given_disc = &buf[..8]; if Self::DISCRIMINATOR != given_disc { @@ -7315,26 +8215,26 @@ pub mod accounts { } #[repr(C)] #[derive(Copy, Clone, Default, AnchorSerialize, AnchorDeserialize, Serialize, Deserialize)] - pub struct ForceCancelOrders { + pub struct UpdateUserIdle { pub state: Pubkey, pub authority: Pubkey, pub filler: Pubkey, pub user: Pubkey, } #[automatically_derived] - impl anchor_lang::Discriminator for ForceCancelOrders { - const DISCRIMINATOR: [u8; 8] = [108, 153, 180, 51, 37, 158, 99, 93]; + impl anchor_lang::Discriminator for UpdateUserIdle { + const DISCRIMINATOR: [u8; 8] = [229, 30, 7, 22, 26, 184, 224, 191]; } #[automatically_derived] - unsafe impl anchor_lang::__private::bytemuck::Pod for ForceCancelOrders {} + unsafe impl anchor_lang::__private::bytemuck::Pod for UpdateUserIdle {} #[automatically_derived] - unsafe impl anchor_lang::__private::bytemuck::Zeroable for ForceCancelOrders {} + unsafe impl anchor_lang::__private::bytemuck::Zeroable for UpdateUserIdle {} #[automatically_derived] - impl anchor_lang::ZeroCopy for ForceCancelOrders {} + impl anchor_lang::ZeroCopy for UpdateUserIdle {} #[automatically_derived] - impl anchor_lang::InstructionData for ForceCancelOrders {} + impl anchor_lang::InstructionData for UpdateUserIdle {} #[automatically_derived] - impl ToAccountMetas for ForceCancelOrders { + impl ToAccountMetas for UpdateUserIdle { fn to_account_metas(&self) -> Vec { vec![ AccountMeta { @@ -7361,7 +8261,7 @@ pub mod accounts { } } #[automatically_derived] - impl anchor_lang::AccountSerialize for ForceCancelOrders { + impl anchor_lang::AccountSerialize for UpdateUserIdle { 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()); @@ -7373,7 +8273,7 @@ pub mod accounts { } } #[automatically_derived] - impl anchor_lang::AccountDeserialize for ForceCancelOrders { + impl anchor_lang::AccountDeserialize for UpdateUserIdle { fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result { let given_disc = &buf[..8]; if Self::DISCRIMINATOR != given_disc { @@ -7391,26 +8291,26 @@ pub mod accounts { } #[repr(C)] #[derive(Copy, Clone, Default, AnchorSerialize, AnchorDeserialize, Serialize, Deserialize)] - pub struct UpdateUserIdle { + pub struct DisableUserHighLeverageMode { pub state: Pubkey, pub authority: Pubkey, - pub filler: Pubkey, pub user: Pubkey, + pub high_leverage_mode_config: Pubkey, } #[automatically_derived] - impl anchor_lang::Discriminator for UpdateUserIdle { - const DISCRIMINATOR: [u8; 8] = [229, 30, 7, 22, 26, 184, 224, 191]; + impl anchor_lang::Discriminator for DisableUserHighLeverageMode { + const DISCRIMINATOR: [u8; 8] = [126, 242, 88, 155, 81, 152, 143, 68]; } #[automatically_derived] - unsafe impl anchor_lang::__private::bytemuck::Pod for UpdateUserIdle {} + unsafe impl anchor_lang::__private::bytemuck::Pod for DisableUserHighLeverageMode {} #[automatically_derived] - unsafe impl anchor_lang::__private::bytemuck::Zeroable for UpdateUserIdle {} + unsafe impl anchor_lang::__private::bytemuck::Zeroable for DisableUserHighLeverageMode {} #[automatically_derived] - impl anchor_lang::ZeroCopy for UpdateUserIdle {} + impl anchor_lang::ZeroCopy for DisableUserHighLeverageMode {} #[automatically_derived] - impl anchor_lang::InstructionData for UpdateUserIdle {} + impl anchor_lang::InstructionData for DisableUserHighLeverageMode {} #[automatically_derived] - impl ToAccountMetas for UpdateUserIdle { + impl ToAccountMetas for DisableUserHighLeverageMode { fn to_account_metas(&self) -> Vec { vec![ AccountMeta { @@ -7424,12 +8324,12 @@ pub mod accounts { is_writable: false, }, AccountMeta { - pubkey: self.filler, + pubkey: self.user, is_signer: false, is_writable: true, }, AccountMeta { - pubkey: self.user, + pubkey: self.high_leverage_mode_config, is_signer: false, is_writable: true, }, @@ -7437,7 +8337,7 @@ pub mod accounts { } } #[automatically_derived] - impl anchor_lang::AccountSerialize for UpdateUserIdle { + impl anchor_lang::AccountSerialize for DisableUserHighLeverageMode { 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()); @@ -7449,7 +8349,7 @@ pub mod accounts { } } #[automatically_derived] - impl anchor_lang::AccountDeserialize for UpdateUserIdle { + impl anchor_lang::AccountDeserialize for DisableUserHighLeverageMode { fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result { let given_disc = &buf[..8]; if Self::DISCRIMINATOR != given_disc { @@ -12535,6 +13435,76 @@ pub mod accounts { } #[repr(C)] #[derive(Copy, Clone, Default, AnchorSerialize, AnchorDeserialize, Serialize, Deserialize)] + pub struct UpdatePerpMarketHighLeverageMarginRatio { + pub admin: Pubkey, + pub state: Pubkey, + pub perp_market: Pubkey, + } + #[automatically_derived] + impl anchor_lang::Discriminator for UpdatePerpMarketHighLeverageMarginRatio { + const DISCRIMINATOR: [u8; 8] = [94, 44, 114, 224, 250, 149, 47, 90]; + } + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Pod for UpdatePerpMarketHighLeverageMarginRatio {} + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Zeroable for UpdatePerpMarketHighLeverageMarginRatio {} + #[automatically_derived] + impl anchor_lang::ZeroCopy for UpdatePerpMarketHighLeverageMarginRatio {} + #[automatically_derived] + impl anchor_lang::InstructionData for UpdatePerpMarketHighLeverageMarginRatio {} + #[automatically_derived] + impl ToAccountMetas for UpdatePerpMarketHighLeverageMarginRatio { + fn to_account_metas(&self) -> Vec { + vec![ + AccountMeta { + pubkey: self.admin, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: self.state, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: self.perp_market, + is_signer: false, + is_writable: true, + }, + ] + } + } + #[automatically_derived] + impl anchor_lang::AccountSerialize for UpdatePerpMarketHighLeverageMarginRatio { + 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 UpdatePerpMarketHighLeverageMarginRatio { + 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 UpdatePerpMarketFundingPeriod { pub admin: Pubkey, pub state: Pubkey, @@ -17342,6 +18312,158 @@ pub mod accounts { .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize.into()) } } + #[repr(C)] + #[derive(Copy, Clone, Default, AnchorSerialize, AnchorDeserialize, Serialize, Deserialize)] + pub struct InitializeHighLeverageModeConfig { + pub admin: Pubkey, + pub high_leverage_mode_config: Pubkey, + pub state: Pubkey, + pub rent: Pubkey, + pub system_program: Pubkey, + } + #[automatically_derived] + impl anchor_lang::Discriminator for InitializeHighLeverageModeConfig { + const DISCRIMINATOR: [u8; 8] = [125, 235, 77, 45, 130, 90, 134, 48]; + } + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Pod for InitializeHighLeverageModeConfig {} + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Zeroable for InitializeHighLeverageModeConfig {} + #[automatically_derived] + impl anchor_lang::ZeroCopy for InitializeHighLeverageModeConfig {} + #[automatically_derived] + impl anchor_lang::InstructionData for InitializeHighLeverageModeConfig {} + #[automatically_derived] + impl ToAccountMetas for InitializeHighLeverageModeConfig { + fn to_account_metas(&self) -> Vec { + vec![ + AccountMeta { + pubkey: self.admin, + is_signer: true, + is_writable: true, + }, + AccountMeta { + pubkey: self.high_leverage_mode_config, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: self.state, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: self.rent, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: self.system_program, + is_signer: false, + is_writable: false, + }, + ] + } + } + #[automatically_derived] + impl anchor_lang::AccountSerialize for InitializeHighLeverageModeConfig { + 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 InitializeHighLeverageModeConfig { + 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 UpdateHighLeverageModeConfig { + pub admin: Pubkey, + pub high_leverage_mode_config: Pubkey, + pub state: Pubkey, + } + #[automatically_derived] + impl anchor_lang::Discriminator for UpdateHighLeverageModeConfig { + const DISCRIMINATOR: [u8; 8] = [254, 192, 159, 254, 254, 74, 141, 70]; + } + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Pod for UpdateHighLeverageModeConfig {} + #[automatically_derived] + unsafe impl anchor_lang::__private::bytemuck::Zeroable for UpdateHighLeverageModeConfig {} + #[automatically_derived] + impl anchor_lang::ZeroCopy for UpdateHighLeverageModeConfig {} + #[automatically_derived] + impl anchor_lang::InstructionData for UpdateHighLeverageModeConfig {} + #[automatically_derived] + impl ToAccountMetas for UpdateHighLeverageModeConfig { + fn to_account_metas(&self) -> Vec { + vec![ + AccountMeta { + pubkey: self.admin, + is_signer: true, + is_writable: true, + }, + AccountMeta { + pubkey: self.high_leverage_mode_config, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: self.state, + is_signer: false, + is_writable: false, + }, + ] + } + } + #[automatically_derived] + impl anchor_lang::AccountSerialize for UpdateHighLeverageModeConfig { + 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 UpdateHighLeverageModeConfig { + 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()) + } + } } pub mod errors { #![doc = r" IDL error types"] @@ -17929,6 +19051,30 @@ pub mod errors { InvalidSwiftOrderParam, #[msg("Place and take order success condition failed")] PlaceAndTakeOrderSuccessConditionFailed, + #[msg("Invalid High Leverage Mode Config")] + InvalidHighLeverageModeConfig, + #[msg("Invalid RFQ User Account")] + InvalidRFQUserAccount, + #[msg("RFQUserAccount should be mutable")] + RFQUserAccountWrongMutability, + #[msg("RFQUserAccount has too many active RFQs")] + RFQUserAccountFull, + #[msg("RFQ order not filled as expected")] + RFQOrderNotFilled, + #[msg("RFQ orders must be jit makers")] + InvalidRFQOrder, + #[msg("RFQ matches must be valid")] + InvalidRFQMatch, + #[msg("Invalid swift user account")] + InvalidSwiftUserAccount, + #[msg("Swift account wrong mutability")] + SwiftUserAccountWrongMutability, + #[msg("SwiftUserAccount has too many active orders")] + SwiftUserOrdersAccountFull, + #[msg("Order with swift uuid does not exist")] + SwiftOrderDoesNotExist, + #[msg("Swift order id cannot be 0s")] + InvalidSwiftOrderId, } } pub mod events { @@ -18026,6 +19172,16 @@ pub mod events { pub market_index: u16, } #[event] + pub struct SwiftOrderRecord { + pub user: Pubkey, + pub hash: String, + pub matching_order_params: OrderParams, + pub user_order_id: u32, + pub swift_order_max_slot: u64, + pub swift_order_uuid: [u8; 8], + pub ts: i64, + } + #[event] pub struct OrderRecord { pub ts: i64, pub user: Pubkey, diff --git a/crates/src/slot_subscriber.rs b/crates/src/slot_subscriber.rs index c4b3f19..0cc5b5c 100644 --- a/crates/src/slot_subscriber.rs +++ b/crates/src/slot_subscriber.rs @@ -1,15 +1,41 @@ -use std::sync::{Arc, Mutex}; +use std::{ + sync::{atomic::AtomicU64, Arc, Mutex}, + time::Duration, +}; use futures_util::StreamExt; use log::{debug, error, warn}; use solana_client::nonblocking::pubsub_client::PubsubClient; -use tokio::sync::oneshot; - -use crate::types::{SdkError, SdkResult}; - -/// To subscribe to slot updates, subscribe to the event_emitter's "slot" event type. +use solana_sdk::clock::Slot; +use tokio::sync::{ + mpsc::{self}, + oneshot, +}; + +use crate::{ + async_utils::{retry_policy, spawn_retry_task}, + types::{SdkError, SdkResult}, +}; + +/// Max. time for slot subscriber to run without an update +const SLOT_STALENESS_THRESHOLD: Duration = Duration::from_secs(4); + +const LOG_TARGET: &str = "slotsub"; + +/// Subscribes to network slot number increases +/// +/// ```example +/// let slot_subscriber = SlotSubscriber::new("http://rpc.example.com"); +/// slot_subscriber.subscribe(move |slot| { +/// dbg!("new slot", slot); +/// }).expect("subd"); +/// +/// // get latest slot +/// let latest_slot = slot_subscriber.current_slot(); +/// ``` +/// pub struct SlotSubscriber { - current_slot: Arc>, + current_slot: Arc, url: String, unsub: Mutex>>, } @@ -35,69 +61,74 @@ impl SlotSubscriber { pub fn new(url: String) -> Self { Self { - current_slot: Arc::new(Mutex::new(0)), + current_slot: Arc::default(), url, unsub: Mutex::new(None), } } - pub fn current_slot(&self) -> u64 { - let slot_guard = self.current_slot.lock().unwrap(); - *slot_guard + /// Returns the latest slot + pub fn current_slot(&self) -> Slot { + self.current_slot.load(std::sync::atomic::Ordering::Relaxed) } - pub async fn subscribe(&mut self, handler_fn: F) -> SdkResult<()> + pub fn subscribe(&mut self, handler_fn: F) -> SdkResult<()> where F: 'static + Send + Fn(SlotUpdate), { if self.is_subscribed() { return Ok(()); } - self.subscribe_ws(handler_fn).await?; - Ok(()) + self.subscribe_ws(handler_fn) } - async fn subscribe_ws(&mut self, handler_fn: F) -> SdkResult<()> + fn subscribe_ws(&mut self, handler_fn: F) -> SdkResult<()> where F: 'static + Send + Fn(SlotUpdate), { - let pubsub = PubsubClient::new(&self.url).await?; + let (slot_tx, mut slot_rx) = mpsc::channel(8); + let url = self.url.clone(); + + let join_handle = spawn_retry_task( + move || { + let task = SlotSubscriberTask { + endpoint: url.clone(), + slot_tx: slot_tx.clone(), + }; + task.slot_subscribe() + }, + retry_policy::forever(1), + ); + let (unsub_tx, mut unsub_rx) = oneshot::channel::<()>(); { let mut guard = self.unsub.try_lock().expect("uncontested"); *guard = Some(unsub_tx); } - let current_slot = self.current_slot.clone(); + let current_slot = Arc::clone(&self.current_slot); tokio::spawn(async move { - let (mut slot_updates, unsubscriber) = pubsub.slot_subscribe().await.unwrap(); loop { tokio::select! { biased; - message = slot_updates.next() => { - match message { - Some(message) => { - let slot = message.slot; - let mut current_slot_guard = current_slot.lock().unwrap(); - if slot >= *current_slot_guard { - *current_slot_guard = slot; - handler_fn(SlotUpdate::new(slot)); - } + new_slot = slot_rx.recv() => { + match new_slot { + Some(new_slot) => { + current_slot.store(new_slot, std::sync::atomic::Ordering::Relaxed); + handler_fn(SlotUpdate::new(new_slot)); } None => { - warn!("Slot stream ended"); - unsubscriber().await; - break; + } } } _ = &mut unsub_rx => { - debug!("Unsubscribing."); - unsubscriber().await; + debug!("unsubscribed"); break; } } } + join_handle.abort(); }); Ok(()) @@ -116,6 +147,42 @@ impl SlotSubscriber { } } +struct SlotSubscriberTask { + endpoint: String, + slot_tx: mpsc::Sender, +} + +impl SlotSubscriberTask { + async fn slot_subscribe(self) { + debug!(target: LOG_TARGET, "start task"); + let pubsub = match PubsubClient::new(&self.endpoint).await { + Ok(p) => p, + Err(err) => { + debug!(target: LOG_TARGET, "connect failed: {err:?}"); + return; + } + }; + let (mut slot_updates, unsubscriber) = match pubsub.slot_subscribe().await { + Ok(s) => s, + Err(err) => { + debug!(target: LOG_TARGET, "subscribe failed: {err:?}"); + return; + } + }; + + let mut current_slot = 0; + while let Ok(Some(message)) = + tokio::time::timeout(SLOT_STALENESS_THRESHOLD, slot_updates.next()).await + { + if message.slot >= current_slot { + current_slot = message.slot; + self.slot_tx.try_send(current_slot).expect("sent"); + } + } + warn!(target: LOG_TARGET, "slot stream stale or disconnected"); + unsubscriber().await; + } +} #[cfg(feature = "rpc_tests")] mod tests { use std::str::FromStr; diff --git a/crates/src/types.rs b/crates/src/types.rs index 5760c85..c4257ac 100644 --- a/crates/src/types.rs +++ b/crates/src/types.rs @@ -494,11 +494,23 @@ impl ReferrerInfo { } } -impl ToString for MarketType { - fn to_string(&self) -> String { +impl OrderType { + pub fn as_str(&self) -> &str { match self { - MarketType::Perp => "perp".into(), - MarketType::Spot => "spot".into(), + OrderType::Limit => "limit", + OrderType::Market => "market", + OrderType::Oracle => "oracle", + OrderType::TriggerLimit => "trigger_limit", + OrderType::TriggerMarket => "trigger_market", + } + } +} + +impl MarketType { + pub fn as_str(&self) -> &str { + match self { + MarketType::Perp => "perp", + MarketType::Spot => "spot", } } } @@ -536,8 +548,8 @@ mod tests { fn market_type_str() { assert_eq!(MarketType::from_str("PERP").unwrap(), MarketType::Perp,); assert_eq!(MarketType::from_str("spot").unwrap(), MarketType::Spot,); - assert_eq!("perp", &MarketType::Perp.to_string(),); - assert_eq!("spot", &MarketType::Spot.to_string(),); + assert_eq!("perp", MarketType::Perp.as_str()); + assert_eq!("spot", MarketType::Spot.as_str()); } #[test] diff --git a/res/drift.json b/res/drift.json index 540363e..2374bf4 100644 --- a/res/drift.json +++ b/res/drift.json @@ -1,5 +1,5 @@ { - "version": "2.96.0", + "version": "2.97.0", "name": "drift", "instructions": [ { @@ -93,6 +93,78 @@ ], "args": [] }, + { + "name": "initializeRfqUser", + "accounts": [ + { + "name": "rfqUser", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "initializeSwiftUserOrders", + "accounts": [ + { + "name": "swiftUserOrders", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, { "name": "initializeReferrerName", "accounts": [ @@ -608,6 +680,63 @@ } ] }, + { + "name": "placeAndMakeSwiftPerpOrder", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "taker", + "isMut": true, + "isSigner": false + }, + { + "name": "takerStats", + "isMut": true, + "isSigner": false + }, + { + "name": "takerSwiftUserOrders", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "OrderParams" + } + }, + { + "name": "swiftOrderUuid", + "type": { + "array": [ + "u8", + 8 + ] + } + } + ] + }, { "name": "placeSwiftTakerOrder", "accounts": [ @@ -626,6 +755,11 @@ "isMut": true, "isSigner": false }, + { + "name": "swiftUserOrders", + "isMut": true, + "isSigner": false + }, { "name": "authority", "isMut": false, @@ -650,14 +784,50 @@ { "name": "swiftOrderParamsMessageBytes", "type": "bytes" + } + ] + }, + { + "name": "placeAndMatchRfqOrders", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true }, { - "name": "swiftMessageSignature", + "name": "ixSysvar", + "isMut": false, + "isSigner": false, + "docs": [ + "the supplied Sysvar could be anything else.", + "The Instruction Sysvar has not been implemented", + "in the Anchor framework yet, so this is the safe approach." + ] + } + ], + "args": [ + { + "name": "rfqMatches", "type": { - "array": [ - "u8", - 64 - ] + "vec": { + "defined": "RFQMatch" + } } } ] @@ -1283,6 +1453,37 @@ ], "args": [] }, + { + "name": "enableUserHighLeverageMode", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "highLeverageModeConfig", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "subAccountId", + "type": "u16" + } + ] + }, { "name": "fillPerpOrder", "accounts": [ @@ -1498,6 +1699,32 @@ ], "args": [] }, + { + "name": "disableUserHighLeverageMode", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "highLeverageModeConfig", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, { "name": "updateUserFuelBonus", "accounts": [ @@ -3987,6 +4214,36 @@ } ] }, + { + "name": "updatePerpMarketHighLeverageMarginRatio", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "marginRatioInitial", + "type": "u16" + }, + { + "name": "marginRatioMaintenance", + "type": "u16" + } + ] + }, { "name": "updatePerpMarketFundingPeriod", "accounts": [ @@ -5952,6 +6209,72 @@ } } ] + }, + { + "name": "initializeHighLeverageModeConfig", + "accounts": [ + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "highLeverageModeConfig", + "isMut": true, + "isSigner": false + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "maxUsers", + "type": "u32" + } + ] + }, + { + "name": "updateHighLeverageModeConfig", + "accounts": [ + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "highLeverageModeConfig", + "isMut": true, + "isSigner": false + }, + { + "name": "state", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "maxUsers", + "type": "u32" + }, + { + "name": "reduceOnly", + "type": "bool" + } + ] } ], "accounts": [ @@ -6158,6 +6481,35 @@ ] } }, + { + "name": "HighLeverageModeConfig", + "type": { + "kind": "struct", + "fields": [ + { + "name": "maxUsers", + "type": "u32" + }, + { + "name": "currentUsers", + "type": "u32" + }, + { + "name": "reduceOnly", + "type": "u8" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 31 + ] + } + } + ] + } + }, { "name": "InsuranceFundStake", "type": { @@ -6546,12 +6898,47 @@ ], "type": "u8" }, + { + "name": "padding1", + "type": "u8" + }, + { + "name": "highLeverageMarginRatioInitial", + "type": "u16" + }, + { + "name": "highLeverageMarginRatioMaintenance", + "type": "u16" + }, { "name": "padding", "type": { "array": [ "u8", - 43 + 38 + ] + } + } + ] + } + }, + { + "name": "RFQUser", + "type": { + "kind": "struct", + "fields": [ + { + "name": "userPubkey", + "type": "publicKey" + }, + { + "name": "rfqOrderData", + "type": { + "array": [ + { + "defined": "RFQOrderId" + }, + 32 ] } } @@ -7164,15 +7551,38 @@ "type": "u16" }, { - "name": "maxInitializeUserFee", - "type": "u16" + "name": "maxInitializeUserFee", + "type": "u16" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 10 + ] + } + } + ] + } + }, + { + "name": "SwiftUserOrders", + "type": { + "kind": "struct", + "fields": [ + { + "name": "userPubkey", + "type": "publicKey" }, { - "name": "padding", + "name": "swiftOrderData", "type": { "array": [ - "u8", - 10 + { + "defined": "SwiftOrderId" + }, + 32 ] } } @@ -7401,12 +7811,18 @@ ], "type": "bool" }, + { + "name": "marginMode", + "type": { + "defined": "MarginMode" + } + }, { "name": "padding1", "type": { "array": [ "u8", - 5 + 4 ] } }, @@ -7530,11 +7946,13 @@ "type": "u16" }, { - "name": "isReferrer", + "name": "referrerStatus", "docs": [ - "Whether the user is a referrer. Sub account 0 can not be deleted if user is a referrer" + "Flags for referrer status:", + "First bit (LSB): 1 if user is a referrer, 0 otherwise", + "Second bit: 1 if user was referred, 0 otherwise" ], - "type": "bool" + "type": "u8" }, { "name": "disableUpdatePerpBidAskTwap", @@ -8135,6 +8553,15 @@ "type": { "kind": "struct", "fields": [ + { + "name": "uuid", + "type": { + "array": [ + "u8", + 8 + ] + } + }, { "name": "swiftOrderSignature", "type": { @@ -8162,10 +8589,6 @@ "defined": "OrderParams" } }, - { - "name": "expectedOrderId", - "type": "i32" - }, { "name": "subAccountId", "type": "u16" @@ -8205,6 +8628,109 @@ ] } }, + { + "name": "RFQMakerOrderParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "uuid", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "authority", + "type": "publicKey" + }, + { + "name": "subAccountId", + "type": "u16" + }, + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "marketType", + "type": { + "defined": "MarketType" + } + }, + { + "name": "baseAssetAmount", + "type": "u64" + }, + { + "name": "price", + "type": "u64" + }, + { + "name": "direction", + "type": { + "defined": "PositionDirection" + } + }, + { + "name": "maxTs", + "type": "i64" + } + ] + } + }, + { + "name": "RFQMakerMessage", + "type": { + "kind": "struct", + "fields": [ + { + "name": "orderParams", + "type": { + "defined": "RFQMakerOrderParams" + } + }, + { + "name": "signature", + "type": { + "array": [ + "u8", + 64 + ] + } + } + ] + } + }, + { + "name": "RFQMatch", + "type": { + "kind": "struct", + "fields": [ + { + "name": "baseAssetAmount", + "type": "u64" + }, + { + "name": "makerOrderParams", + "type": { + "defined": "RFQMakerOrderParams" + } + }, + { + "name": "makerSignature", + "type": { + "array": [ + "u8", + 64 + ] + } + } + ] + } + }, { "name": "ModifyOrderParams", "type": { @@ -9024,6 +9550,27 @@ ] } }, + { + "name": "RFQOrderId", + "type": { + "kind": "struct", + "fields": [ + { + "name": "uuid", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "maxTs", + "type": "i64" + } + ] + } + }, { "name": "InsuranceFund", "type": { @@ -9221,6 +9768,31 @@ ] } }, + { + "name": "SwiftOrderId", + "type": { + "kind": "struct", + "fields": [ + { + "name": "uuid", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "maxSlot", + "type": "u64" + }, + { + "name": "orderId", + "type": "u32" + } + ] + } + }, { "name": "UserFees", "type": { @@ -10124,6 +10696,9 @@ }, { "name": "Liquidation" + }, + { + "name": "RFQ" } ] } @@ -10659,6 +11234,34 @@ } ] } + }, + { + "name": "ReferrerStatus", + "type": { + "kind": "enum", + "variants": [ + { + "name": "IsReferrer" + }, + { + "name": "IsReferred" + } + ] + } + }, + { + "name": "MarginMode", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Default" + }, + { + "name": "HighLeverage" + } + ] + } } ], "events": [ @@ -11068,6 +11671,53 @@ } ] }, + { + "name": "SwiftOrderRecord", + "fields": [ + { + "name": "user", + "type": "publicKey", + "index": false + }, + { + "name": "hash", + "type": "String", + "index": false + }, + { + "name": "matchingOrderParams", + "type": { + "defined": "OrderParams" + }, + "index": false + }, + { + "name": "userOrderId", + "type": "u32", + "index": false + }, + { + "name": "swiftOrderMaxSlot", + "type": "u64", + "index": false + }, + { + "name": "swiftOrderUuid", + "type": { + "array": [ + "u8", + 8 + ] + }, + "index": false + }, + { + "name": "ts", + "type": "i64", + "index": false + } + ] + }, { "name": "OrderRecord", "fields": [ @@ -13152,6 +13802,66 @@ "code": 6289, "name": "PlaceAndTakeOrderSuccessConditionFailed", "msg": "Place and take order success condition failed" + }, + { + "code": 6290, + "name": "InvalidHighLeverageModeConfig", + "msg": "Invalid High Leverage Mode Config" + }, + { + "code": 6291, + "name": "InvalidRFQUserAccount", + "msg": "Invalid RFQ User Account" + }, + { + "code": 6292, + "name": "RFQUserAccountWrongMutability", + "msg": "RFQUserAccount should be mutable" + }, + { + "code": 6293, + "name": "RFQUserAccountFull", + "msg": "RFQUserAccount has too many active RFQs" + }, + { + "code": 6294, + "name": "RFQOrderNotFilled", + "msg": "RFQ order not filled as expected" + }, + { + "code": 6295, + "name": "InvalidRFQOrder", + "msg": "RFQ orders must be jit makers" + }, + { + "code": 6296, + "name": "InvalidRFQMatch", + "msg": "RFQ matches must be valid" + }, + { + "code": 6297, + "name": "InvalidSwiftUserAccount", + "msg": "Invalid swift user account" + }, + { + "code": 6298, + "name": "SwiftUserAccountWrongMutability", + "msg": "Swift account wrong mutability" + }, + { + "code": 6299, + "name": "SwiftUserOrdersAccountFull", + "msg": "SwiftUserAccount has too many active orders" + }, + { + "code": 6300, + "name": "SwiftOrderDoesNotExist", + "msg": "Order with swift uuid does not exist" + }, + { + "code": 6301, + "name": "InvalidSwiftOrderId", + "msg": "Swift order id cannot be 0s" } ], "metadata": {