From 34f6d492b1bf4f4df3d6b91372bed43d890d4121 Mon Sep 17 00:00:00 2001 From: jordy25519 Date: Thu, 31 Oct 2024 09:55:44 +0800 Subject: [PATCH 1/4] latest swift idl --- crates/src/drift_idl.rs | 1254 +++++++++++++++++++++++++++++++++++++-- res/drift.json | 750 ++++++++++++++++++++++- 2 files changed, 1935 insertions(+), 69 deletions(-) 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/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": { From 63cef6a10f1c6a38a214ef75dc7394d337e66f5a Mon Sep 17 00:00:00 2001 From: jordy25519 Date: Fri, 1 Nov 2024 08:29:35 +0800 Subject: [PATCH 2/4] to_string -> as_str --- crates/src/types.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/crates/src/types.rs b/crates/src/types.rs index 5760c85..38acbe3 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", } } } From 39d58a51bbc49a2456533be5c68c2cf9478865d0 Mon Sep 17 00:00:00 2001 From: jordy25519 Date: Fri, 1 Nov 2024 15:58:47 +0800 Subject: [PATCH 3/4] fix dlob build --- crates/src/dlob/dlob.rs | 11 ++++------- crates/src/dlob/dlob_builder.rs | 27 ++++++++++++--------------- crates/src/dlob/dlob_node.rs | 5 +---- crates/src/dlob/market.rs | 9 ++++++++- crates/src/drift_idl.rs | 6 ++++-- crates/src/types.rs | 4 ++-- 6 files changed, 31 insertions(+), 31 deletions(-) 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..9812073 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,16 @@ 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| {}) + .await?; locked_builder.usermap.subscribe().await?; drop(locked_builder); @@ -54,10 +54,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 +91,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 edcb4ab..97d721c 100644 --- a/crates/src/drift_idl.rs +++ b/crates/src/drift_idl.rs @@ -2,7 +2,6 @@ #![doc = r""] #![doc = r" Auto-generated IDL types, manual edits do not persist (see `crates/drift-idl-gen`)"] #![doc = r""] -use self::traits::ToAccountMetas; use anchor_lang::{ prelude::{ account, @@ -13,6 +12,8 @@ use anchor_lang::{ }; use serde::{Deserialize, Serialize}; use solana_sdk::{instruction::AccountMeta, pubkey::Pubkey}; + +use self::traits::ToAccountMetas; pub mod traits { use solana_sdk::instruction::AccountMeta; #[doc = r" This is distinct from the anchor_lang version of the trait"] @@ -1890,8 +1891,9 @@ pub mod instructions { } pub mod types { #![doc = r" IDL types"] - use super::*; use std::ops::Mul; + + use super::*; #[doc = ""] #[doc = " backwards compatible u128 deserializing data from rust <=1.76.0 when u/i128 was 8-byte aligned"] #[doc = " https://solana.stackexchange.com/questions/7720/using-u128-without-sacrificing-alignment-8"] diff --git a/crates/src/types.rs b/crates/src/types.rs index 38acbe3..c4257ac 100644 --- a/crates/src/types.rs +++ b/crates/src/types.rs @@ -548,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] From df2ea0323be1445c3d9a291f7707cd5649b3b8da Mon Sep 17 00:00:00 2001 From: jordy25519 Date: Tue, 5 Nov 2024 11:05:44 +0800 Subject: [PATCH 4/4] Strongly typed dlob --- Cargo.lock | 193 ++++++- Cargo.toml | 6 + benches/dlob.rs | 67 +++ crates/src/dlob/dlob.rs | 228 ++++---- crates/src/dlob/dlob_builder.rs | 4 +- crates/src/dlob/dlob_node.rs | 538 +++++++----------- crates/src/dlob/market.rs | 213 +++++-- crates/src/dlob/order_list.rs | 123 ++-- crates/src/drift_idl.rs | 6 +- .../websocket_program_account_subscriber.rs | 8 +- 10 files changed, 797 insertions(+), 589 deletions(-) create mode 100644 benches/dlob.rs diff --git a/Cargo.lock b/Cargo.lock index 15dd0a7..b300df6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -352,6 +352,12 @@ dependencies = [ "libc", ] +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + [[package]] name = "ansi_term" version = "0.12.1" @@ -989,6 +995,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + [[package]] name = "cc" version = "1.1.22" @@ -1033,6 +1045,33 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "cipher" version = "0.4.4" @@ -1066,7 +1105,7 @@ checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ "atty", "bitflags 1.3.2", - "clap_lex", + "clap_lex 0.2.4", "indexmap 1.9.3", "once_cell", "strsim 0.10.0", @@ -1074,6 +1113,25 @@ dependencies = [ "textwrap 0.16.1", ] +[[package]] +name = "clap" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +dependencies = [ + "anstyle", + "clap_lex 0.7.2", +] + [[package]] name = "clap_lex" version = "0.2.4" @@ -1083,6 +1141,12 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + [[package]] name = "colorchoice" version = "1.0.2" @@ -1205,6 +1269,42 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap 4.5.20", + "criterion-plot", + "is-terminal", + "itertools 0.10.5", + "num-traits", + "once_cell", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools 0.10.5", +] + [[package]] name = "crossbeam-channel" version = "0.5.13" @@ -1485,6 +1585,7 @@ dependencies = [ "base64 0.22.1", "bytemuck", "bytes", + "criterion", "dashmap 6.1.0", "drift-idl-gen", "env_logger 0.11.5", @@ -1863,6 +1964,16 @@ dependencies = [ "tracing", ] +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + [[package]] name = "hash32" version = "0.2.1" @@ -1926,6 +2037,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "hex" version = "0.4.3" @@ -2164,6 +2281,17 @@ version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" +[[package]] +name = "is-terminal" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +dependencies = [ + "hermit-abi 0.4.0", + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -2615,6 +2743,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "oorandom" +version = "11.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" + [[package]] name = "opaque-debug" version = "0.3.1" @@ -2728,6 +2862,34 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + [[package]] name = "polyval" version = "0.6.2" @@ -3232,6 +3394,15 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.24" @@ -4807,6 +4978,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "tinyvec" version = "1.8.0" @@ -5169,6 +5350,16 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" diff --git a/Cargo.toml b/Cargo.toml index a2e07eb..28bb9b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,8 +45,14 @@ type-layout = "0.2.0" [dev-dependencies] bytes = "1" +criterion = { version = "0.5", features = ["html_reports"] } hex = "0.4" hex-literal = "0.4" [build-dependencies] drift-idl-gen = { version = "0.1.1", path = "crates/drift-idl-gen"} + +[[bench]] +name = "dlob" +harness = false +required-features = ["dlob"] \ No newline at end of file diff --git a/benches/dlob.rs b/benches/dlob.rs new file mode 100644 index 0000000..8d67716 --- /dev/null +++ b/benches/dlob.rs @@ -0,0 +1,67 @@ +use std::hint::black_box; + +use criterion::{criterion_group, criterion_main, Criterion}; +use drift_rs::{ + dlob::dlob::DLOB, + drift_idl::types::{MarketType, Order}, + Pubkey, +}; + +fn dlob_insert(n: u64) { + let dlob = DLOB::new(); + let user_account = Pubkey::new_unique(); + let taking_limit_order = Order { + order_id: 1, + slot: 1, + market_index: 0, + market_type: MarketType::Perp, + ..Order::default() + }; + let floating_limit_order = Order { + order_id: 2, + oracle_price_offset: 1, + market_index: 0, + market_type: MarketType::Perp, + ..Order::default() + }; + let resting_limit_order = Order { + order_id: 3, + slot: 3, + market_index: 0, + market_type: MarketType::Perp, + ..Order::default() + }; + let market_order = Order { + order_id: 4, + slot: 4, + market_index: 0, + market_type: MarketType::Perp, + ..Order::default() + }; + let trigger_order = Order { + order_id: 5, + slot: 5, + market_index: 0, + market_type: MarketType::Perp, + ..Order::default() + }; + + dlob.insert_order(&taking_limit_order, user_account, 1); + dlob.insert_order(&floating_limit_order, user_account, 0); + dlob.insert_order(&resting_limit_order, user_account, 3); + dlob.insert_order(&market_order, user_account, 4); + dlob.insert_order(&trigger_order, user_account, 5); + + dlob.get_order(1, user_account); + dlob.get_order(2, user_account); + dlob.get_order(3, user_account); + dlob.get_order(4, user_account); + dlob.get_order(5, user_account); +} + +fn criterion_benchmark(c: &mut Criterion) { + c.bench_function("dlob 100", |b| b.iter(|| dlob_insert(black_box(100)))); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/crates/src/dlob/dlob.rs b/crates/src/dlob/dlob.rs index 345035c..ebe8a3a 100644 --- a/crates/src/dlob/dlob.rs +++ b/crates/src/dlob/dlob.rs @@ -3,12 +3,17 @@ use std::{collections::BinaryHeap, str::FromStr, sync::Arc}; use dashmap::DashSet; +use log::warn; use rayon::prelude::*; use solana_sdk::pubkey::Pubkey; +use super::dlob_node::{ + node_types::{RestingLimit, TakingLimit}, + NodeType, +}; use crate::{ dlob::{ - dlob_node::{create_node, get_order_signature, DLOBNode, DirectionalNode, Node, NodeType}, + dlob_node::{get_order_signature, DirectionalNode, Node}, market::{get_node_subtype_and_type, Exchange, OpenOrders, SubType}, }, drift_idl::types::{MarketType, Order, OrderStatus}, @@ -30,8 +35,8 @@ impl DLOB { let exchange = Exchange::new(); let open_orders = OpenOrders::new(); - open_orders.insert("perp".to_string(), DashSet::new()); - open_orders.insert("spot".to_string(), DashSet::new()); + open_orders.insert(MarketType::Perp.as_str().to_owned(), DashSet::new()); + open_orders.insert(MarketType::Spot.as_str().to_owned(), DashSet::new()); DLOB { exchange, @@ -77,43 +82,35 @@ impl DLOB { } pub fn insert_order(&self, order: &Order, user_account: Pubkey, slot: u64) { - 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); - let node = create_node(node_type, *order, user_account); self.exchange - .add_market_indempotent(&market_type, market_index); + .add_market_indempotent(order.market_type, market_index); let mut market = match order.market_type { MarketType::Perp => self.exchange.perp.get_mut(&market_index).expect("market"), MarketType::Spot => self.exchange.spot.get_mut(&market_index).expect("market"), }; - let order_list = market.get_order_list_for_node_insert(node_type); - match subtype { - SubType::Bid => order_list.insert_bid(node), - SubType::Ask => order_list.insert_ask(node), - _ => {} + SubType::Bid => market.insert_bid_node(node_type, *order, user_account), + SubType::Ask => market.insert_ask_node(node_type, *order, user_account), + _ => { + warn!(target: "dlob", "inserting order subtype: {subtype:?} is a noop"); + } } } pub fn get_order(&self, order_id: u32, user_account: Pubkey) -> Option { let order_signature = get_order_signature(order_id, user_account); - for order_list in self.exchange.get_order_lists() { - if let Some(node) = order_list.get_node(&order_signature) { - return Some(*node.get_order()); - } - } - - None + self.exchange.find_order(&order_signature) } fn update_resting_limit_orders_for_market_type(&mut self, slot: u64, market_type: MarketType) { - let mut new_taking_asks: BinaryHeap = BinaryHeap::new(); - let mut new_taking_bids: BinaryHeap = BinaryHeap::new(); + let mut new_taking_asks = BinaryHeap::>::default(); + let mut new_taking_bids = BinaryHeap::>::default(); let market = match market_type { MarketType::Perp => &self.exchange.perp, @@ -124,27 +121,27 @@ impl DLOB { let market = market_ref.value_mut(); for directional_node in market.taking_limit_orders.bids.iter() { - if is_resting_limit_order(directional_node.node.get_order(), slot) { + if is_resting_limit_order(directional_node.node.order(), slot) { market .resting_limit_orders - .insert_bid(directional_node.node) + .insert_bid(directional_node.node.transform()) } else { new_taking_bids.push(*directional_node) } } for directional_node in market.taking_limit_orders.asks.iter() { - if is_resting_limit_order(directional_node.node.get_order(), slot) { + if is_resting_limit_order(directional_node.node.order(), slot) { market .resting_limit_orders - .insert_ask(directional_node.node); + .insert_ask(directional_node.node.transform()); } else { new_taking_asks.push(*directional_node); } } - market.taking_limit_orders.bids = new_taking_bids.clone(); - market.taking_limit_orders.asks = new_taking_asks.clone(); + market.taking_limit_orders.bids.clone_from(&new_taking_bids); + market.taking_limit_orders.asks.clone_from(&new_taking_asks); } } @@ -163,36 +160,19 @@ impl DLOB { &self, market_type: MarketType, sub_type: SubType, - node_type: NodeType, market_index: u16, - ) -> Vec { - let market = match market_type { + node_type: NodeType, + ) -> Vec<(Order, Pubkey)> { + let mut market = match market_type { MarketType::Perp => self.exchange.perp.get_mut(&market_index).expect("market"), MarketType::Spot => self.exchange.spot.get_mut(&market_index).expect("market"), }; - let mut order_list = market.get_order_list_for_node_type(node_type); - - let mut best_orders: Vec = vec![]; match sub_type { - SubType::Bid => { - while !order_list.bids_empty() { - if let Some(node) = order_list.get_best_bid() { - best_orders.push(node); - } - } - } - SubType::Ask => { - while !order_list.asks_empty() { - if let Some(node) = order_list.get_best_ask() { - best_orders.push(node); - } - } - } + SubType::Bid => market.take_bids_by_node_type(node_type), + SubType::Ask => market.take_asks_by_node_type(node_type), _ => unimplemented!(), } - - best_orders } pub fn get_resting_limit_asks( @@ -201,35 +181,30 @@ impl DLOB { market_type: MarketType, market_index: u16, oracle_price_data: OraclePriceData, - ) -> Vec { + ) -> Vec> { self.update_resting_limit_orders(slot); + let mut market = match market_type { + MarketType::Perp => self.exchange.perp.get_mut(&market_index).expect("market"), + MarketType::Spot => self.exchange.spot.get_mut(&market_index).expect("market"), + }; - let mut resting_limit_orders = self.get_best_orders( - market_type, - SubType::Ask, - NodeType::RestingLimit, - market_index, - ); - let mut floating_limit_orders = self.get_best_orders( - market_type, - SubType::Ask, - NodeType::FloatingLimit, - market_index, - ); - - let comparative = Box::new( - |node_a: &Node, node_b: &Node, slot: u64, oracle_price_data: OraclePriceData| { - node_a.get_price(oracle_price_data, slot) - > node_b.get_price(oracle_price_data, slot) - }, + let (mut resting_limit_orders, mut floating_limit_orders) = ( + market.resting_limit_orders.get_best_asks(), + market.floating_limit_orders.get_best_asks(), ); - let mut all_orders = vec![]; + let mut all_orders = + Vec::with_capacity(resting_limit_orders.len() + floating_limit_orders.len()); all_orders.append(&mut resting_limit_orders); - all_orders.append(&mut floating_limit_orders); + all_orders.append( + &mut floating_limit_orders + .drain(..) + .map(|x| x.transform()) + .collect(), + ); all_orders.sort_by(|a, b| { - if comparative(a, b, slot, oracle_price_data) { + if a.price(oracle_price_data, slot) > b.price(oracle_price_data, slot) { std::cmp::Ordering::Greater } else { std::cmp::Ordering::Less @@ -245,35 +220,31 @@ impl DLOB { market_type: MarketType, market_index: u16, oracle_price_data: OraclePriceData, - ) -> Vec { + ) -> Vec> { self.update_resting_limit_orders(slot); - let mut resting_limit_orders = self.get_best_orders( - market_type, - SubType::Bid, - NodeType::RestingLimit, - market_index, - ); - let mut floating_limit_orders = self.get_best_orders( - market_type, - SubType::Bid, - NodeType::FloatingLimit, - market_index, - ); + let mut market = match market_type { + MarketType::Perp => self.exchange.perp.get_mut(&market_index).expect("market"), + MarketType::Spot => self.exchange.spot.get_mut(&market_index).expect("market"), + }; - let comparative = Box::new( - |node_a: &Node, node_b: &Node, slot: u64, oracle_price_data: OraclePriceData| { - node_a.get_price(oracle_price_data, slot) - < node_b.get_price(oracle_price_data, slot) - }, + let (mut resting_limit_orders, mut floating_limit_orders) = ( + market.resting_limit_orders.get_best_bids(), + market.floating_limit_orders.get_best_bids(), ); - let mut all_orders = vec![]; + let mut all_orders = + Vec::with_capacity(resting_limit_orders.len() + floating_limit_orders.len()); all_orders.append(&mut resting_limit_orders); - all_orders.append(&mut floating_limit_orders); + all_orders.append( + &mut floating_limit_orders + .drain(..) + .map(|x| x.transform()) + .collect(), + ); all_orders.sort_by(|a, b| { - if comparative(a, b, slot, oracle_price_data) { + if a.price(oracle_price_data, slot) < b.price(oracle_price_data, slot) { std::cmp::Ordering::Greater } else { std::cmp::Ordering::Less @@ -292,13 +263,14 @@ impl Default for DLOB { #[cfg(test)] mod tests { - use drift_idl::{ - math::constants::PRICE_PRECISION_U64, - state::user::{Order, OrderType}, - }; use solana_sdk::pubkey::Pubkey; use super::*; + use crate::{ + drift_idl::types::{Order, OrderType}, + math::constants::PRICE_PRECISION_U64, + PositionDirection, + }; #[test] fn test_dlob_insert() { @@ -362,45 +334,50 @@ mod tests { order_id: 1, slot: 1, market_index: 0, - direction: drift_idl::controller::position::PositionDirection::Long, + direction: PositionDirection::Long, market_type: MarketType::Perp, auction_duration: 1, + order_type: OrderType::Limit, ..Order::default() }; let order_2 = Order { order_id: 2, slot: 2, market_index: 0, - direction: drift_idl::controller::position::PositionDirection::Long, + direction: PositionDirection::Long, market_type: MarketType::Perp, auction_duration: 1, + order_type: OrderType::Limit, ..Order::default() }; let order_3 = Order { order_id: 3, slot: 3, market_index: 0, - direction: drift_idl::controller::position::PositionDirection::Long, + direction: PositionDirection::Long, market_type: MarketType::Perp, auction_duration: 1, + order_type: OrderType::Limit, ..Order::default() }; let order_4 = Order { order_id: 4, slot: 4, market_index: 0, - direction: drift_idl::controller::position::PositionDirection::Long, + direction: PositionDirection::Long, market_type: MarketType::Perp, auction_duration: 1, + order_type: OrderType::Limit, ..Order::default() }; let order_5 = Order { order_id: 5, slot: 5, market_index: 0, - direction: drift_idl::controller::position::PositionDirection::Long, + direction: PositionDirection::Long, market_type: MarketType::Perp, auction_duration: 1, + order_type: OrderType::Limit, ..Order::default() }; @@ -417,13 +394,13 @@ mod tests { assert!(dlob.get_order(5, user_account).is_some()); let best_orders = - dlob.get_best_orders(MarketType::Perp, SubType::Bid, NodeType::TakingLimit, 0); + dlob.get_best_orders(MarketType::Perp, SubType::Bid, 0, NodeType::TakingLimit); - assert_eq!(best_orders[0].get_order().slot, 1); - assert_eq!(best_orders[1].get_order().slot, 2); - assert_eq!(best_orders[2].get_order().slot, 3); - assert_eq!(best_orders[3].get_order().slot, 4); - assert_eq!(best_orders[4].get_order().slot, 5); + assert_eq!(best_orders[0].0.slot, 1); + assert_eq!(best_orders[1].0.slot, 2); + assert_eq!(best_orders[2].0.slot, 3); + assert_eq!(best_orders[3].0.slot, 4); + assert_eq!(best_orders[4].0.slot, 5); } #[test] @@ -435,9 +412,10 @@ mod tests { order_id: 1, slot: 1, market_index: 0, - direction: drift_idl::controller::position::PositionDirection::Long, + direction: PositionDirection::Long, market_type: MarketType::Perp, auction_duration: 1, + order_type: OrderType::Limit, ..Order::default() }; @@ -481,7 +459,7 @@ mod tests { order_id: 1, slot: 1, market_index: 0, - direction: drift_idl::controller::position::PositionDirection::Short, + direction: PositionDirection::Short, market_type: MarketType::Perp, order_type: OrderType::Limit, auction_duration: 10, @@ -493,7 +471,7 @@ mod tests { order_id: 2, slot: 11, market_index: 0, - direction: drift_idl::controller::position::PositionDirection::Short, + direction: PositionDirection::Short, market_type: MarketType::Perp, order_type: OrderType::Limit, auction_duration: 10, @@ -505,7 +483,7 @@ mod tests { order_id: 3, slot: 21, market_index: 0, - direction: drift_idl::controller::position::PositionDirection::Short, + direction: PositionDirection::Short, market_type: MarketType::Perp, order_type: OrderType::Limit, auction_duration: 10, @@ -532,7 +510,7 @@ mod tests { dlob.get_resting_limit_asks(slot, MarketType::Perp, 0, oracle_price_data); assert_eq!(resting_limit_asks.len(), 1); - assert_eq!(resting_limit_asks[0].get_order().order_id, 1); + assert_eq!(resting_limit_asks[0].order().order_id, 1); slot += 11; @@ -541,8 +519,8 @@ mod tests { dlob.get_resting_limit_asks(slot, MarketType::Perp, 0, oracle_price_data); assert_eq!(resting_limit_asks.len(), 2); - assert_eq!(resting_limit_asks[0].get_order().order_id, 1); - assert_eq!(resting_limit_asks[1].get_order().order_id, 2); + assert_eq!(resting_limit_asks[0].order().order_id, 1); + assert_eq!(resting_limit_asks[1].order().order_id, 2); slot += 11; @@ -551,9 +529,9 @@ mod tests { dlob.get_resting_limit_asks(slot, MarketType::Perp, 0, oracle_price_data); assert_eq!(resting_limit_asks.len(), 3); - assert_eq!(resting_limit_asks[0].get_order().order_id, 1); - assert_eq!(resting_limit_asks[1].get_order().order_id, 2); - assert_eq!(resting_limit_asks[2].get_order().order_id, 3); + assert_eq!(resting_limit_asks[0].order().order_id, 1); + assert_eq!(resting_limit_asks[1].order().order_id, 2); + assert_eq!(resting_limit_asks[2].order().order_id, 3); } #[test] @@ -575,7 +553,7 @@ mod tests { order_id: 1, slot: 1, market_index: 0, - direction: drift_idl::controller::position::PositionDirection::Long, + direction: PositionDirection::Long, market_type: MarketType::Perp, order_type: OrderType::Limit, auction_duration: 10, @@ -587,7 +565,7 @@ mod tests { order_id: 2, slot: 11, market_index: 0, - direction: drift_idl::controller::position::PositionDirection::Long, + direction: PositionDirection::Long, market_type: MarketType::Perp, order_type: OrderType::Limit, auction_duration: 10, @@ -599,7 +577,7 @@ mod tests { order_id: 3, slot: 21, market_index: 0, - direction: drift_idl::controller::position::PositionDirection::Long, + direction: PositionDirection::Long, market_type: MarketType::Perp, order_type: OrderType::Limit, auction_duration: 10, @@ -626,7 +604,7 @@ mod tests { dlob.get_resting_limit_bids(slot, MarketType::Perp, 0, oracle_price_data); assert_eq!(resting_limit_bids.len(), 1); - assert_eq!(resting_limit_bids[0].get_order().order_id, 1); + assert_eq!(resting_limit_bids[0].order().order_id, 1); slot += 11; @@ -635,8 +613,8 @@ mod tests { dlob.get_resting_limit_bids(slot, MarketType::Perp, 0, oracle_price_data); assert_eq!(resting_limit_bids.len(), 2); - assert_eq!(resting_limit_bids[0].get_order().order_id, 2); - assert_eq!(resting_limit_bids[1].get_order().order_id, 1); + assert_eq!(resting_limit_bids[0].order().order_id, 2); + assert_eq!(resting_limit_bids[1].order().order_id, 1); slot += 11; @@ -645,8 +623,8 @@ mod tests { dlob.get_resting_limit_bids(slot, MarketType::Perp, 0, oracle_price_data); assert_eq!(resting_limit_bids.len(), 3); - assert_eq!(resting_limit_bids[0].get_order().order_id, 3); - assert_eq!(resting_limit_bids[1].get_order().order_id, 2); - assert_eq!(resting_limit_bids[2].get_order().order_id, 1); + assert_eq!(resting_limit_bids[0].order().order_id, 3); + assert_eq!(resting_limit_bids[1].order().order_id, 2); + assert_eq!(resting_limit_bids[2].order().order_id, 1); } } diff --git a/crates/src/dlob/dlob_builder.rs b/crates/src/dlob/dlob_builder.rs index 9812073..e26bb33 100644 --- a/crates/src/dlob/dlob_builder.rs +++ b/crates/src/dlob/dlob_builder.rs @@ -65,7 +65,7 @@ impl DLOBBuilder { } } -#[cfg(test)] +#[cfg(feature = "rpc_tests")] mod tests { use env_logger; use solana_sdk::commitment_config::{CommitmentConfig, CommitmentLevel}; @@ -74,7 +74,6 @@ mod tests { use crate::{memcmp::get_user_with_order_filter, utils::get_ws_url}; #[tokio::test] - #[cfg(feature = "rpc_tests")] async fn test_dlob_builder() { env_logger::init(); let endpoint = "rpc".to_string(); @@ -105,7 +104,6 @@ mod tests { } #[tokio::test] - #[cfg(feature = "rpc_tests")] async fn test_build_time() { let endpoint = "rpc".to_string(); let commitment = CommitmentConfig { diff --git a/crates/src/dlob/dlob_node.rs b/crates/src/dlob/dlob_node.rs index 79f3b1e..dc7f74b 100644 --- a/crates/src/dlob/dlob_node.rs +++ b/crates/src/dlob/dlob_node.rs @@ -1,304 +1,214 @@ +use node_types::{FloatingLimit, Market, RestingLimit, TakingLimit, Trigger, VAMM}; use solana_sdk::pubkey::Pubkey; use crate::{drift_idl::types::Order, ffi::OraclePriceData, math::order::get_limit_price}; -#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub trait NodeKind: Eq + Ord + PartialOrd + Copy + Clone + std::fmt::Debug { + fn sort_value(order: &Order) -> Option; + fn is_base_filled(order: &Order) -> bool { + order.base_asset_amount_filled == order.base_asset_amount + } + fn get_price(order: &Order, oracle_price_data: OraclePriceData, slot: u64) -> u64 { + get_limit_price(order, &oracle_price_data, slot, None) + } +} + pub enum NodeType { - TakingLimit, RestingLimit, FloatingLimit, + TakingLimit, Market, Trigger, VAMM, } -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub enum SortDirection { - Ascending, - Descending, -} - -pub trait DLOBNode { - fn get_price(&self, oracle_price_data: OraclePriceData, slot: u64) -> u64; - fn is_vamm_node(&self) -> bool; - fn is_base_filled(&self) -> bool; - fn get_sort_value(&self, order: &Order) -> Option; - fn get_order(&self) -> &Order; - fn get_user_account(&self) -> Pubkey; - fn set_order(&mut self, order: Order); - fn get_node_type(&self) -> NodeType; - fn set_node_type(&mut self, node_type: NodeType); -} - -#[derive(Copy, Clone, Debug)] -pub enum Node { - OrderNode(OrderNode), - VAMMNode(VAMMNode), -} - -#[derive(Clone, Copy, Debug)] -pub struct DirectionalNode { - pub node: Node, - sort_direction: SortDirection, -} - -impl DirectionalNode { - pub fn new(node: Node, sort_direction: SortDirection) -> Self { - Self { - node, - sort_direction, +pub mod node_types { + use super::*; + #[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Debug)] + pub struct TakingLimit; + impl NodeKind for TakingLimit { + fn sort_value(order: &Order) -> Option { + Some(order.slot.into()) } } -} - -impl PartialEq for DirectionalNode { - fn eq(&self, other: &Self) -> bool { - self.node.eq(&other.node) + #[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Debug)] + pub struct RestingLimit; + impl NodeKind for RestingLimit { + fn sort_value(order: &Order) -> Option { + Some(order.price.into()) + } } -} - -impl Eq for DirectionalNode {} - -impl PartialOrd for DirectionalNode { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) + #[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Debug)] + pub struct FloatingLimit; + impl NodeKind for FloatingLimit { + fn sort_value(order: &Order) -> Option { + Some(order.oracle_price_offset.into()) + } } -} - -impl Ord for DirectionalNode { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - let mut cmp = self - .node - .get_sort_value(self.node.get_order()) - .partial_cmp(&other.node.get_sort_value(other.node.get_order())) - .unwrap_or(std::cmp::Ordering::Equal); - - if cmp == std::cmp::Ordering::Equal { - cmp = self.node.get_order().slot.cmp(&other.node.get_order().slot); + #[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Debug)] + pub struct Market; + impl NodeKind for Market { + fn sort_value(order: &Order) -> Option { + Some(order.slot.into()) } - - if self.sort_direction == SortDirection::Ascending { - cmp = cmp.reverse(); + } + #[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Debug)] + pub struct Trigger; + impl NodeKind for Trigger { + fn sort_value(order: &Order) -> Option { + Some(order.trigger_price.into()) + } + } + #[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Debug)] + pub struct VAMM; + impl NodeKind for VAMM { + fn sort_value(_order: &Order) -> Option { + None + } + fn is_base_filled(_order: &Order) -> bool { + false + } + fn get_price(order: &Order, _oracle_price_data: OraclePriceData, _slot: u64) -> u64 { + order.price } - - cmp } } -impl PartialEq for Node { - fn eq(&self, other: &Self) -> bool { - self.get_sort_value(self.get_order()) == other.get_sort_value(other.get_order()) - } +/// Strongly typed order entry the dlob +#[derive(Copy, Clone, Debug)] +pub struct Node { + order: Order, + user_account: Pubkey, + _phantom: std::marker::PhantomData, } -impl Eq for Node {} - -impl Node { - pub fn new(node_type: NodeType, order: Order, user_account: Pubkey) -> Self { - match node_type { - NodeType::TakingLimit => { - Node::OrderNode(OrderNode::new(NodeType::TakingLimit, order, user_account)) - } - NodeType::RestingLimit => { - Node::OrderNode(OrderNode::new(NodeType::RestingLimit, order, user_account)) - } - NodeType::FloatingLimit => { - Node::OrderNode(OrderNode::new(NodeType::FloatingLimit, order, user_account)) - } - NodeType::Market => { - Node::OrderNode(OrderNode::new(NodeType::Market, order, user_account)) - } - NodeType::Trigger => { - Node::OrderNode(OrderNode::new(NodeType::Trigger, order, user_account)) - } - NodeType::VAMM => Node::VAMMNode(VAMMNode::new(order, 0)), - } +impl PartialEq for Node { + fn eq(&self, other: &Self) -> bool { + T::sort_value(&self.order) == T::sort_value(&other.order) } } -impl DLOBNode for Node { - fn get_price(&self, oracle_price_data: OraclePriceData, slot: u64) -> u64 { - match self { - Node::OrderNode(order_node) => order_node.get_price(oracle_price_data, slot), - Node::VAMMNode(vamm_node) => vamm_node.get_price(oracle_price_data, slot), - } - } +impl Eq for Node {} - fn is_vamm_node(&self) -> bool { - match self { - Node::OrderNode(_) => false, - Node::VAMMNode(_) => true, - } +impl From> for (Order, Pubkey) { + fn from(value: Node) -> Self { + (value.order, value.user_account) } +} - fn is_base_filled(&self) -> bool { - match self { - Node::OrderNode(order_node) => order_node.is_base_filled(), - Node::VAMMNode(vamm_node) => vamm_node.is_base_filled(), - } +impl Node { + pub fn price(&self, oracle_price_data: OraclePriceData, slot: u64) -> u64 { + T::get_price(&self.order, oracle_price_data, slot) } - - fn get_sort_value(&self, order: &Order) -> Option { - match self { - Node::OrderNode(order_node) => order_node.get_sort_value(order), - Node::VAMMNode(vamm_node) => vamm_node.get_sort_value(order), - } + pub fn is_base_filled(&self) -> bool { + T::is_base_filled(&self.order) } - - fn get_order(&self) -> &Order { - match self { - Node::OrderNode(order_node) => order_node.get_order(), - Node::VAMMNode(vamm_node) => vamm_node.get_order(), - } + pub fn order(&self) -> &Order { + &self.order } - - fn get_user_account(&self) -> Pubkey { - match self { - Node::OrderNode(order_node) => order_node.get_user_account(), - Node::VAMMNode(vamm_node) => vamm_node.get_user_account(), - } + pub fn is_vamm(&self) -> bool { + self.user_account == Pubkey::default() } - - fn set_order(&mut self, order: Order) { - match self { - Node::OrderNode(order_node) => order_node.set_order(order), - Node::VAMMNode(vamm_node) => vamm_node.set_order(order), - } + pub fn set_order(&mut self, order: Order) { + self.order = order; } - - fn get_node_type(&self) -> NodeType { - match self { - Node::OrderNode(order_node) => order_node.get_node_type(), - Node::VAMMNode(_) => NodeType::VAMM, - } + pub fn user_account(&self) -> Pubkey { + self.user_account } - - fn set_node_type(&mut self, node_type: NodeType) { - match self { - Node::OrderNode(order_node) => order_node.set_node_type(node_type), - Node::VAMMNode(_) => unimplemented!(), - } + /// Get the sorting value for this node + pub fn sort_value(&self) -> Option { + T::sort_value(&self.order) } -} - -#[derive(Clone, Copy, Debug)] -pub struct OrderNode { - pub order: Order, - pub user_account: Pubkey, - pub node_type: NodeType, -} - -impl OrderNode { - pub fn new(node_type: NodeType, order: Order, user_account: Pubkey) -> Self { - Self { + /// Make a new order node of type `T` + pub fn new(order: Order, user_account: Pubkey) -> Node { + Node:: { order, user_account, - node_type, + _phantom: Default::default(), } } -} - -impl DLOBNode for OrderNode { - fn get_price(&self, oracle_price_data: OraclePriceData, slot: u64) -> u64 { - get_limit_price(&self.order, &oracle_price_data, slot, None) + /// Create a new trigger order node + pub fn trigger(order: Order, user_account: Pubkey) -> Node { + Node::::new(order, user_account) } - - fn is_vamm_node(&self) -> bool { - false + /// Create a new resting limit order node + pub fn resting_limit(order: Order, user_account: Pubkey) -> Node { + Node::::new(order, user_account) } - - fn is_base_filled(&self) -> bool { - self.order.base_asset_amount_filled == self.order.base_asset_amount + /// Create a new market order node + pub fn market(order: Order, user_account: Pubkey) -> Node { + Node::::new(order, user_account) } - - fn get_sort_value(&self, order: &Order) -> Option { - match self.node_type { - NodeType::TakingLimit => Some(order.slot.into()), - NodeType::RestingLimit => Some(order.price.into()), - NodeType::FloatingLimit => Some(order.oracle_price_offset.into()), - NodeType::Market => Some(order.slot.into()), - NodeType::Trigger => Some(order.trigger_price.into()), - NodeType::VAMM => None, - } + /// Create a new floating limit order node + pub fn floating_limit(order: Order, user_account: Pubkey) -> Node { + Node::::new(order, user_account) } - - fn get_order(&self) -> &Order { - &self.order - } - - fn get_user_account(&self) -> Pubkey { - self.user_account - } - - fn set_order(&mut self, order: Order) { - self.order = order; + /// Create a new taker limit order node + pub fn taking_limit(order: Order, user_account: Pubkey) -> Node { + Node::::new(order, user_account) } - - fn get_node_type(&self) -> NodeType { - self.node_type + /// Create a new VAMM order node + pub fn vamm(order: Order) -> Node { + Node::::new(order, Pubkey::default()) } - - fn set_node_type(&mut self, node_type: NodeType) { - self.node_type = node_type; + /// Transform self into a different order node + pub fn transform(self) -> Node { + Node::::new(self.order, self.user_account) } } -#[derive(Copy, Clone, Debug)] -pub struct VAMMNode { - pub order: Order, - pub price: u64, -} - -impl VAMMNode { - pub fn new(order: Order, price: u64) -> Self { - Self { order, price } - } +/// Order wrapped for sorting in high-level data structure +#[repr(transparent)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct DirectionalNode { + pub node: Node, } -impl DLOBNode for VAMMNode { - fn get_price(&self, _oracle_price_data: OraclePriceData, _slot: u64) -> u64 { - self.price +impl DirectionalNode { + /// Wrap `node` for ASCended sorting + pub fn asc(node: Node) -> DirectionalNode { + DirectionalNode:: { node } } - - fn is_vamm_node(&self) -> bool { - true - } - - fn is_base_filled(&self) -> bool { - false - } - - fn get_sort_value(&self, _order: &Order) -> Option { - None + /// Wrap `node` for Descended sorting + pub fn desc(node: Node) -> DirectionalNode { + DirectionalNode:: { node } } - - fn get_order(&self) -> &Order { - &self.order - } - - fn get_user_account(&self) -> Pubkey { - unimplemented!() + pub fn new(node: Node) -> DirectionalNode { + Self { node } } +} - fn set_order(&mut self, _order: Order) { - unimplemented!() - } +impl Ord for DirectionalNode { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let mut cmp = T::sort_value(&self.node.order) + .partial_cmp(&T::sort_value(&other.node.order)) + .unwrap_or(std::cmp::Ordering::Equal); - fn get_node_type(&self) -> NodeType { - NodeType::VAMM - } + if cmp == std::cmp::Ordering::Equal { + cmp = self.node.order().slot.cmp(&other.node.order().slot); + } - fn set_node_type(&mut self, _node_type: NodeType) { - unimplemented!() + if ASC == true { + cmp.reverse() + } else { + cmp + } } } -pub(crate) fn create_node(node_type: NodeType, order: Order, user_account: Pubkey) -> Node { - Node::new(node_type, order, user_account) +impl PartialOrd for DirectionalNode { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } } -pub(crate) fn get_order_signature(order_id: u32, user_account: Pubkey) -> String { - format!("{}-{}", order_id, user_account) +pub type OrderId = [u8; 32 + 4]; +#[inline] +pub(crate) fn get_order_signature(order_id: u32, user_account: Pubkey) -> OrderId { + let mut id_buf = [0u8; 36]; + id_buf[..32].copy_from_slice(&user_account.to_bytes()); + id_buf[32..36].copy_from_slice(&order_id.to_le_bytes()); + id_buf } #[cfg(test)] @@ -316,20 +226,17 @@ mod test { let user_account = Pubkey::new_unique(); - let taking_limit_order_node = create_node(NodeType::TakingLimit, order, user_account); - let resting_limit_order_node = create_node(NodeType::RestingLimit, order, user_account); - let floating_limit_order_node = create_node(NodeType::FloatingLimit, order, user_account); - let market_order_node = create_node(NodeType::Market, order, user_account); - let trigger_order_node = create_node(NodeType::Trigger, order, user_account); - - assert_eq!(taking_limit_order_node.get_sort_value(&order), Some(100)); - assert_eq!(resting_limit_order_node.get_sort_value(&order), Some(1_000)); - assert_eq!(market_order_node.get_sort_value(&order), Some(100)); - assert_eq!(trigger_order_node.get_sort_value(&order), Some(500)); - assert_eq!( - floating_limit_order_node.get_sort_value(&order), - Some(5_000) - ); + let taking_limit_order_node = Node::::new(order, user_account); + let resting_limit_order_node = Node::::new(order, user_account); + let floating_limit_order_node = Node::::new(order, user_account); + let market_order_node = Node::::new(order, user_account); + let trigger_order_node = Node::::new(order, user_account); + + assert_eq!(taking_limit_order_node.sort_value(), Some(100)); + assert_eq!(resting_limit_order_node.sort_value(), Some(1_000)); + assert_eq!(market_order_node.sort_value(), Some(100)); + assert_eq!(trigger_order_node.sort_value(), Some(500)); + assert_eq!(floating_limit_order_node.sort_value(), Some(5_000)); let mut order_2 = Order::default(); @@ -338,27 +245,17 @@ mod test { order_2.trigger_price = 600; order_2.oracle_price_offset = 6_000; - let taking_limit_order_node_2 = create_node(NodeType::TakingLimit, order_2, user_account); - let resting_limit_order_node_2 = create_node(NodeType::RestingLimit, order_2, user_account); - let floating_limit_order_node_2 = - create_node(NodeType::FloatingLimit, order_2, user_account); - let market_order_node_2 = create_node(NodeType::Market, order_2, user_account); - let trigger_order_node_2 = create_node(NodeType::Trigger, order_2, user_account); - - assert_eq!( - taking_limit_order_node_2.get_sort_value(&order_2), - Some(200) - ); - assert_eq!( - resting_limit_order_node_2.get_sort_value(&order_2), - Some(2_000) - ); - assert_eq!(market_order_node_2.get_sort_value(&order_2), Some(200)); - assert_eq!(trigger_order_node_2.get_sort_value(&order_2), Some(600)); - assert_eq!( - floating_limit_order_node_2.get_sort_value(&order_2), - Some(6_000) - ); + let taking_limit_order_node_2 = Node::::new(order_2, user_account); + let resting_limit_order_node_2 = Node::::new(order_2, user_account); + let floating_limit_order_node_2 = Node::::new(order_2, user_account); + let market_order_node_2 = Node::::new(order_2, user_account); + let trigger_order_node_2 = Node::::new(order_2, user_account); + + assert_eq!(taking_limit_order_node_2.sort_value(), Some(200)); + assert_eq!(resting_limit_order_node_2.sort_value(), Some(2_000)); + assert_eq!(market_order_node_2.sort_value(), Some(200)); + assert_eq!(trigger_order_node_2.sort_value(), Some(600)); + assert_eq!(floating_limit_order_node_2.sort_value(), Some(6_000)); let mut order_3 = Order::default(); @@ -367,27 +264,17 @@ mod test { order_3.trigger_price = 700; order_3.oracle_price_offset = 7_000; - let taking_limit_order_node_3 = create_node(NodeType::TakingLimit, order_3, user_account); - let resting_limit_order_node_3 = create_node(NodeType::RestingLimit, order_3, user_account); - let floating_limit_order_node_3 = - create_node(NodeType::FloatingLimit, order_3, user_account); - let market_order_node_3 = create_node(NodeType::Market, order_3, user_account); - let trigger_order_node_3 = create_node(NodeType::Trigger, order_3, user_account); - - assert_eq!( - taking_limit_order_node_3.get_sort_value(&order_3), - Some(300) - ); - assert_eq!( - resting_limit_order_node_3.get_sort_value(&order_3), - Some(3_000) - ); - assert_eq!(market_order_node_3.get_sort_value(&order_3), Some(300)); - assert_eq!(trigger_order_node_3.get_sort_value(&order_3), Some(700)); - assert_eq!( - floating_limit_order_node_3.get_sort_value(&order_3), - Some(7_000) - ); + let taking_limit_order_node_3 = Node::::new(order_3, user_account); + let resting_limit_order_node_3 = Node::::new(order_3, user_account); + let floating_limit_order_node_3 = Node::::new(order_3, user_account); + let market_order_node_3 = Node::::new(order_3, user_account); + let trigger_order_node_3 = Node::::new(order_3, user_account); + + assert_eq!(taking_limit_order_node_3.sort_value(), Some(300)); + assert_eq!(resting_limit_order_node_3.sort_value(), Some(3_000)); + assert_eq!(market_order_node_3.sort_value(), Some(300)); + assert_eq!(trigger_order_node_3.sort_value(), Some(700)); + assert_eq!(floating_limit_order_node_3.sort_value(), Some(7_000)); } #[test] @@ -401,12 +288,11 @@ mod test { order.trigger_price = 500; order.oracle_price_offset = 5_000; - let mut taking_limit_order_node = create_node(NodeType::TakingLimit, order, user_account); - let mut resting_limit_order_node = create_node(NodeType::RestingLimit, order, user_account); - let mut floating_limit_order_node = - create_node(NodeType::FloatingLimit, order, user_account); - let mut market_order_node = create_node(NodeType::Market, order, user_account); - let mut trigger_order_node = create_node(NodeType::Trigger, order, user_account); + let mut taking_limit_order_node = Node::::new(order, user_account); + let mut resting_limit_order_node = Node::::new(order, user_account); + let mut floating_limit_order_node = Node::::new(order, user_account); + let mut market_order_node = Node::::new(order, user_account); + let mut trigger_order_node = Node::::new(order, user_account); let mut order_2 = Order::default(); @@ -421,14 +307,11 @@ mod test { market_order_node.set_order(order_2); trigger_order_node.set_order(order_2); - assert_eq!(taking_limit_order_node.get_order().slot, 200); - assert_eq!(resting_limit_order_node.get_order().price, 2_000); - assert_eq!( - floating_limit_order_node.get_order().oracle_price_offset, - 6_000 - ); - assert_eq!(market_order_node.get_order().slot, 200); - assert_eq!(trigger_order_node.get_order().trigger_price, 600); + assert_eq!(taking_limit_order_node.order().slot, 200); + assert_eq!(resting_limit_order_node.order().price, 2_000); + assert_eq!(floating_limit_order_node.order().oracle_price_offset, 6_000); + assert_eq!(market_order_node.order().slot, 200); + assert_eq!(trigger_order_node.order().trigger_price, 600); } #[test] @@ -442,11 +325,11 @@ mod test { order.trigger_price = 500; order.oracle_price_offset = 5_000; - let taking_limit_order_node = create_node(NodeType::TakingLimit, order, user_account); - let resting_limit_order_node = create_node(NodeType::RestingLimit, order, user_account); - let floating_limit_order_node = create_node(NodeType::FloatingLimit, order, user_account); - let market_order_node = create_node(NodeType::Market, order, user_account); - let trigger_order_node = create_node(NodeType::Trigger, order, user_account); + let taking_limit_order_node = Node::::new(order, user_account); + let resting_limit_order_node = Node::::new(order, user_account); + let floating_limit_order_node = Node::::new(order, user_account); + let market_order_node = Node::::new(order, user_account); + let trigger_order_node = Node::::new(order, user_account); let mut order_2 = Order::default(); @@ -455,12 +338,11 @@ mod test { order_2.trigger_price = 600; order_2.oracle_price_offset = 6_000; - let taking_limit_order_node_2 = create_node(NodeType::TakingLimit, order_2, user_account); - let resting_limit_order_node_2 = create_node(NodeType::RestingLimit, order_2, user_account); - let floating_limit_order_node_2 = - create_node(NodeType::FloatingLimit, order_2, user_account); - let market_order_node_2 = create_node(NodeType::Market, order_2, user_account); - let trigger_order_node_2 = create_node(NodeType::Trigger, order_2, user_account); + let taking_limit_order_node_2 = Node::::new(order_2, user_account); + let resting_limit_order_node_2 = Node::::new(order_2, user_account); + let floating_limit_order_node_2 = Node::::new(order_2, user_account); + let market_order_node_2 = Node::::new(order_2, user_account); + let trigger_order_node_2 = Node::::new(order_2, user_account); assert_eq!(taking_limit_order_node, taking_limit_order_node); assert_eq!(resting_limit_order_node, resting_limit_order_node); @@ -474,20 +356,4 @@ mod test { assert_ne!(market_order_node, market_order_node_2); assert_ne!(trigger_order_node, trigger_order_node_2); } - - #[test] - #[should_panic(expected = "not implemented")] - fn test_vamm_node_get_user_account_panics() { - let order = Order::default(); - let vamm_node = VAMMNode::new(order, 100); - vamm_node.get_user_account(); - } - - #[test] - #[should_panic(expected = "not implemented")] - fn test_vamm_node_set_order_panics() { - let order = Order::default(); - let mut vamm_node = VAMMNode::new(order, 100); - vamm_node.set_order(order); - } } diff --git a/crates/src/dlob/market.rs b/crates/src/dlob/market.rs index f6218d8..d44c0ab 100644 --- a/crates/src/dlob/market.rs +++ b/crates/src/dlob/market.rs @@ -1,22 +1,24 @@ use dashmap::{DashMap, DashSet}; +use solana_sdk::pubkey::Pubkey; +use super::dlob_node::{ + node_types::{self, FloatingLimit, RestingLimit, TakingLimit, Trigger}, + Node, NodeType, OrderId, +}; use crate::{ - dlob::{ - dlob_node::{NodeType, SortDirection}, - order_list::Orderlist, - }, - drift_idl::types::{Order, OrderTriggerCondition, OrderType, PositionDirection}, + dlob::order_list::Orderlist, + drift_idl::types::{MarketType, Order, OrderTriggerCondition, OrderType, PositionDirection}, is_one_of_variant, math::order::is_resting_limit_order, }; #[derive(Clone)] pub(crate) struct Market { - pub resting_limit_orders: Orderlist, - pub floating_limit_orders: Orderlist, - pub taking_limit_orders: Orderlist, - pub market_orders: Orderlist, - pub trigger_orders: Orderlist, + pub resting_limit_orders: Orderlist, + pub floating_limit_orders: Orderlist, + pub taking_limit_orders: Orderlist, + pub market_orders: Orderlist, + pub trigger_orders: Orderlist, } #[derive(Copy, Clone, Debug)] @@ -30,41 +32,118 @@ pub enum SubType { impl Market { pub(crate) fn new() -> Market { Market { - resting_limit_orders: Orderlist::new( - SortDirection::Descending, - SortDirection::Ascending, - ), - floating_limit_orders: Orderlist::new( - SortDirection::Descending, - SortDirection::Ascending, - ), - taking_limit_orders: Orderlist::new(SortDirection::Ascending, SortDirection::Ascending), - market_orders: Orderlist::new(SortDirection::Ascending, SortDirection::Ascending), - trigger_orders: Orderlist::new(SortDirection::Ascending, SortDirection::Descending), + resting_limit_orders: Orderlist::::new(), + floating_limit_orders: Orderlist::::new(), + taking_limit_orders: Orderlist::::new(), + market_orders: Orderlist::::new(), + trigger_orders: Orderlist::::new(), + } + } + + pub(crate) fn insert_bid_node(&mut self, node_type: NodeType, order: Order, pubkey: Pubkey) { + match node_type { + NodeType::RestingLimit => self + .resting_limit_orders + .insert_bid(Node::new(order, pubkey)), + NodeType::FloatingLimit => self + .floating_limit_orders + .insert_bid(Node::new(order, pubkey)), + NodeType::TakingLimit => self + .taking_limit_orders + .insert_bid(Node::new(order, pubkey)), + NodeType::Market => self.market_orders.insert_bid(Node::new(order, pubkey)), + NodeType::Trigger => self.trigger_orders.insert_bid(Node::new(order, pubkey)), + NodeType::VAMM => panic!("VAMM order list not found"), + } + } + + pub(crate) fn insert_ask_node(&mut self, node_type: NodeType, order: Order, pubkey: Pubkey) { + match node_type { + NodeType::RestingLimit => self + .resting_limit_orders + .insert_ask(Node::new(order, pubkey)), + NodeType::FloatingLimit => self + .floating_limit_orders + .insert_ask(Node::new(order, pubkey)), + NodeType::TakingLimit => self + .taking_limit_orders + .insert_ask(Node::new(order, pubkey)), + NodeType::Market => self.market_orders.insert_ask(Node::new(order, pubkey)), + NodeType::Trigger => self.trigger_orders.insert_ask(Node::new(order, pubkey)), + NodeType::VAMM => panic!("VAMM order list not found"), } } - pub(crate) fn get_order_list_for_node_insert(&mut self, node_type: NodeType) -> &mut Orderlist { + pub(crate) fn take_bids_by_node_type(&mut self, node_type: NodeType) -> Vec<(Order, Pubkey)> { match node_type { - NodeType::RestingLimit => &mut self.resting_limit_orders, - NodeType::FloatingLimit => &mut self.floating_limit_orders, - NodeType::TakingLimit => &mut self.taking_limit_orders, - NodeType::Market => &mut self.market_orders, - NodeType::Trigger => &mut self.trigger_orders, + NodeType::RestingLimit => self + .resting_limit_orders + .get_best_bids() + .drain(..) + .map(Into::into) + .collect(), + NodeType::FloatingLimit => self + .floating_limit_orders + .get_best_bids() + .drain(..) + .map(Into::into) + .collect(), + NodeType::TakingLimit => self + .taking_limit_orders + .get_best_bids() + .drain(..) + .map(Into::into) + .collect(), + NodeType::Market => self + .market_orders + .get_best_bids() + .drain(..) + .map(Into::into) + .collect(), + NodeType::Trigger => self + .trigger_orders + .get_best_bids() + .drain(..) + .map(Into::into) + .collect(), NodeType::VAMM => panic!("VAMM order list not found"), } } - pub(crate) fn get_order_list_for_node_type(&self, node_type: NodeType) -> Orderlist { + pub(crate) fn take_asks_by_node_type(&mut self, node_type: NodeType) -> Vec<(Order, Pubkey)> { match node_type { - NodeType::RestingLimit => &self.resting_limit_orders, - NodeType::FloatingLimit => &self.floating_limit_orders, - NodeType::TakingLimit => &self.taking_limit_orders, - NodeType::Market => &self.market_orders, - NodeType::Trigger => &self.trigger_orders, + NodeType::RestingLimit => self + .resting_limit_orders + .get_best_asks() + .drain(..) + .map(Into::into) + .collect(), + NodeType::FloatingLimit => self + .floating_limit_orders + .get_best_asks() + .drain(..) + .map(Into::into) + .collect(), + NodeType::TakingLimit => self + .taking_limit_orders + .get_best_asks() + .drain(..) + .map(Into::into) + .collect(), + NodeType::Market => self + .market_orders + .get_best_asks() + .drain(..) + .map(Into::into) + .collect(), + NodeType::Trigger => self + .trigger_orders + .get_best_asks() + .drain(..) + .map(Into::into) + .collect(), NodeType::VAMM => panic!("VAMM order list not found"), } - .clone() } /// for debugging @@ -79,13 +158,15 @@ 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 = match (order.order_type, order.trigger_condition) { - ( - OrderType::TriggerMarket | OrderType::TriggerLimit, - OrderTriggerCondition::TriggeredAbove | OrderTriggerCondition::TriggeredBelow, - ) => true, + let is_triggered = match order.trigger_condition { + OrderTriggerCondition::TriggeredAbove | OrderTriggerCondition::TriggeredBelow => true, _ => false, }; + let must_be_triggered = match order.order_type { + OrderType::TriggerMarket | OrderType::TriggerLimit => true, + _ => false, + }; + let is_inactive_trigger_order = must_be_triggered && !is_triggered; let node_type = if is_inactive_trigger_order { NodeType::Trigger @@ -124,20 +205,20 @@ pub(crate) fn get_node_subtype_and_type(order: &Order, slot: u64) -> (SubType, N #[derive(Clone)] pub struct Exchange { - pub perp: DashMap, - pub spot: DashMap, + pub perp: DashMap, + pub spot: DashMap, } impl Exchange { pub fn new() -> Exchange { Exchange { - perp: DashMap::new(), - spot: DashMap::new(), + perp: DashMap::::default(), + spot: DashMap::::default(), } } - pub fn iter(&self) -> impl Iterator> { - vec![&self.perp, &self.spot].into_iter() + pub fn iter(&self) -> impl Iterator> { + [&self.perp, &self.spot].into_iter() } pub fn clear(&self) { @@ -145,43 +226,49 @@ impl Exchange { self.spot.clear(); } - pub fn add_market_indempotent(&self, market_type: &str, market_index: u16) { + pub fn add_market_indempotent(&self, market_type: MarketType, market_index: u16) { if !self.contains_market(market_type, market_index) { self.insert_market(market_type, market_index); } } - fn contains_market(&self, market_type: &str, market_index: u16) -> bool { + fn contains_market(&self, market_type: MarketType, market_index: u16) -> bool { match market_type { - "perp" => self.perp.contains_key(&market_index), - "spot" => self.spot.contains_key(&market_index), - _ => panic!("Invalid market type"), + MarketType::Perp => self.perp.contains_key(&market_index), + MarketType::Spot => self.spot.contains_key(&market_index), } } - fn insert_market(&self, market_type: &str, market_index: u16) { + fn insert_market(&self, market_type: MarketType, market_index: u16) { match market_type { - "perp" => self.perp.insert(market_index, Market::new()), - "spot" => self.spot.insert(market_index, Market::new()), - _ => panic!("Invalid market type"), + MarketType::Perp => self.perp.insert(market_index, Market::new()), + MarketType::Spot => self.spot.insert(market_index, Market::new()), }; } - pub fn get_order_lists(&self) -> Vec { - let mut order_lists = vec![]; - + pub fn find_order(&self, order: &OrderId) -> Option { for market_type_ref in self.iter() { for market_ref in market_type_ref.iter() { let market = market_ref.value(); - order_lists.push(market.resting_limit_orders.clone()); - order_lists.push(market.floating_limit_orders.clone()); - order_lists.push(market.taking_limit_orders.clone()); - order_lists.push(market.market_orders.clone()); - order_lists.push(market.trigger_orders.clone()); + if let Some(node) = market.resting_limit_orders.get_node(order) { + return Some(node.order().clone()); + } + if let Some(node) = market.floating_limit_orders.get_node(order) { + return Some(node.order().clone()); + } + if let Some(node) = market.taking_limit_orders.get_node(order) { + return Some(node.order().clone()); + } + if let Some(node) = market.market_orders.get_node(order) { + return Some(node.order().clone()); + } + if let Some(node) = market.trigger_orders.get_node(order) { + return Some(node.order().clone()); + } } } - order_lists + return None; } /// for debugging diff --git a/crates/src/dlob/order_list.rs b/crates/src/dlob/order_list.rs index 9929838..0c4b1e8 100644 --- a/crates/src/dlob/order_list.rs +++ b/crates/src/dlob/order_list.rs @@ -2,25 +2,21 @@ use std::collections::BinaryHeap; use dashmap::DashMap; -use crate::dlob::dlob_node::{get_order_signature, DLOBNode, DirectionalNode, Node, SortDirection}; +use crate::dlob::dlob_node::{get_order_signature, DirectionalNode, Node, NodeKind, OrderId}; #[derive(Clone, Debug)] -pub struct Orderlist { - pub bids: BinaryHeap, - pub asks: BinaryHeap, - pub order_sigs: DashMap, - bid_sort_direction: SortDirection, - ask_sort_direction: SortDirection, +pub struct Orderlist { + pub bids: BinaryHeap>, + pub asks: BinaryHeap>, + pub order_sigs: DashMap, ahash::RandomState>, } -impl Orderlist { - pub fn new(bid_sort_direction: SortDirection, ask_sort_direction: SortDirection) -> Self { +impl Orderlist { + pub fn new() -> Self { Orderlist { - bids: BinaryHeap::new(), - asks: BinaryHeap::new(), - order_sigs: DashMap::new(), - bid_sort_direction, - ask_sort_direction, + bids: BinaryHeap::>::new(), + asks: BinaryHeap::>::new(), + order_sigs: DashMap::default(), } } @@ -30,23 +26,23 @@ impl Orderlist { println!("Asks: {:?}", self.asks); } - pub fn insert_bid(&mut self, node: Node) { - let order_sig = get_order_signature(node.get_order().order_id, node.get_user_account()); - self.order_sigs.insert(order_sig.clone(), node); - let directional = DirectionalNode::new(node, self.bid_sort_direction); + pub fn insert_bid(&mut self, node: Node) { + let order_sig = get_order_signature(node.order().order_id, node.user_account()); + self.order_sigs.insert(order_sig, node); + let directional = DirectionalNode::::new(node); self.bids.push(directional); } - pub fn insert_ask(&mut self, node: Node) { - let order_sig = get_order_signature(node.get_order().order_id, node.get_user_account()); - self.order_sigs.insert(order_sig.clone(), node); - let directional = DirectionalNode::new(node, self.ask_sort_direction); + pub fn insert_ask(&mut self, node: Node) { + let order_sig = get_order_signature(node.order().order_id, node.user_account()); + self.order_sigs.insert(order_sig, node); + let directional = DirectionalNode::::new(node); self.asks.push(directional); } - pub fn get_best_bid(&mut self) -> Option { + pub fn get_best_bid(&mut self) -> Option> { if let Some(node) = self.bids.pop().map(|node| node.node) { - let order_sig = get_order_signature(node.get_order().order_id, node.get_user_account()); + let order_sig = get_order_signature(node.order().order_id, node.user_account()); if self.order_sigs.contains_key(&order_sig) { self.order_sigs.remove(&order_sig); return Some(node); @@ -55,9 +51,22 @@ impl Orderlist { None } - pub fn get_best_ask(&mut self) -> Option { + pub fn get_best_bids(&mut self) -> Vec> { + let mut bids = Vec::with_capacity(self.bids.len()); + while let Some(node) = self.bids.pop().map(|node| node.node) { + let order_sig = get_order_signature(node.order().order_id, node.user_account()); + if self.order_sigs.contains_key(&order_sig) { + self.order_sigs.remove(&order_sig); + bids.push(node); + } + } + + bids + } + + pub fn get_best_ask(&mut self) -> Option> { if let Some(node) = self.asks.pop().map(|node| node.node) { - let order_sig = get_order_signature(node.get_order().order_id, node.get_user_account()); + let order_sig = get_order_signature(node.order().order_id, node.user_account()); if self.order_sigs.contains_key(&order_sig) { self.order_sigs.remove(&order_sig); return Some(node); @@ -66,7 +75,20 @@ impl Orderlist { None } - pub fn get_node(&self, order_sig: &String) -> Option { + pub fn get_best_asks(&mut self) -> Vec> { + let mut asks = Vec::with_capacity(self.asks.len()); + while let Some(node) = self.asks.pop().map(|node| node.node) { + let order_sig = get_order_signature(node.order().order_id, node.user_account()); + if self.order_sigs.contains_key(&order_sig) { + self.order_sigs.remove(&order_sig); + asks.push(node); + } + } + + asks + } + + pub fn get_node(&self, order_sig: &OrderId) -> Option> { self.order_sigs.get(order_sig).map(|node| *node) } @@ -85,15 +107,14 @@ impl Orderlist { #[cfg(test)] mod tests { - use drift_idl::state::user::Order; use solana_sdk::pubkey::Pubkey; use super::*; - use crate::dlob::dlob_node::{create_node, NodeType}; + use crate::{dlob::dlob_node::node_types::TakingLimit, drift_idl::types::Order}; #[test] fn test_insertion_and_ordering() { - let mut orderlist = Orderlist::new(SortDirection::Ascending, SortDirection::Ascending); + let mut orderlist = Orderlist::::new(); let user_account = Pubkey::new_unique(); let order_1 = Order { order_id: 1, @@ -146,17 +167,17 @@ mod tests { ..Order::default() }; - let node_1 = create_node(NodeType::TakingLimit, order_1, user_account); - let node_2 = create_node(NodeType::TakingLimit, order_2, user_account); - let node_3 = create_node(NodeType::TakingLimit, order_3, user_account); - let node_4 = create_node(NodeType::TakingLimit, order_4, user_account); - let node_5 = create_node(NodeType::TakingLimit, order_5, user_account); + let node_1 = Node::::new(order_1, user_account); + let node_2 = Node::::new(order_2, user_account); + let node_3 = Node::::new(order_3, user_account); + let node_4 = Node::::new(order_4, user_account); + let node_5 = Node::::new(order_5, user_account); - let node_6 = create_node(NodeType::TakingLimit, order_6, user_account); - let node_7 = create_node(NodeType::TakingLimit, order_7, user_account); - let node_8 = create_node(NodeType::TakingLimit, order_8, user_account); - let node_9 = create_node(NodeType::TakingLimit, order_9, user_account); - let node_10 = create_node(NodeType::TakingLimit, order_10, user_account); + let node_6 = Node::::new(order_6, user_account); + let node_7 = Node::::new(order_7, user_account); + let node_8 = Node::::new(order_8, user_account); + let node_9 = Node::::new(order_9, user_account); + let node_10 = Node::::new(order_10, user_account); orderlist.insert_bid(node_1); orderlist.insert_bid(node_2); @@ -170,16 +191,16 @@ mod tests { orderlist.insert_ask(node_9); orderlist.insert_ask(node_10); - assert_eq!(orderlist.get_best_bid().unwrap().get_order().slot, 1); - assert_eq!(orderlist.get_best_bid().unwrap().get_order().slot, 2); - assert_eq!(orderlist.get_best_bid().unwrap().get_order().slot, 3); - assert_eq!(orderlist.get_best_bid().unwrap().get_order().slot, 4); - assert_eq!(orderlist.get_best_bid().unwrap().get_order().slot, 5); - - assert_eq!(orderlist.get_best_ask().unwrap().get_order().slot, 1); - assert_eq!(orderlist.get_best_ask().unwrap().get_order().slot, 2); - assert_eq!(orderlist.get_best_ask().unwrap().get_order().slot, 3); - assert_eq!(orderlist.get_best_ask().unwrap().get_order().slot, 4); - assert_eq!(orderlist.get_best_ask().unwrap().get_order().slot, 5); + assert_eq!(orderlist.get_best_bid().unwrap().order().slot, 1); + assert_eq!(orderlist.get_best_bid().unwrap().order().slot, 2); + assert_eq!(orderlist.get_best_bid().unwrap().order().slot, 3); + assert_eq!(orderlist.get_best_bid().unwrap().order().slot, 4); + assert_eq!(orderlist.get_best_bid().unwrap().order().slot, 5); + + assert_eq!(orderlist.get_best_ask().unwrap().order().slot, 1); + assert_eq!(orderlist.get_best_ask().unwrap().order().slot, 2); + assert_eq!(orderlist.get_best_ask().unwrap().order().slot, 3); + assert_eq!(orderlist.get_best_ask().unwrap().order().slot, 4); + assert_eq!(orderlist.get_best_ask().unwrap().order().slot, 5); } } diff --git a/crates/src/drift_idl.rs b/crates/src/drift_idl.rs index 97d721c..edcb4ab 100644 --- a/crates/src/drift_idl.rs +++ b/crates/src/drift_idl.rs @@ -2,6 +2,7 @@ #![doc = r""] #![doc = r" Auto-generated IDL types, manual edits do not persist (see `crates/drift-idl-gen`)"] #![doc = r""] +use self::traits::ToAccountMetas; use anchor_lang::{ prelude::{ account, @@ -12,8 +13,6 @@ use anchor_lang::{ }; use serde::{Deserialize, Serialize}; use solana_sdk::{instruction::AccountMeta, pubkey::Pubkey}; - -use self::traits::ToAccountMetas; pub mod traits { use solana_sdk::instruction::AccountMeta; #[doc = r" This is distinct from the anchor_lang version of the trait"] @@ -1891,9 +1890,8 @@ pub mod instructions { } pub mod types { #![doc = r" IDL types"] - use std::ops::Mul; - use super::*; + use std::ops::Mul; #[doc = ""] #[doc = " backwards compatible u128 deserializing data from rust <=1.76.0 when u/i128 was 8-byte aligned"] #[doc = " https://solana.stackexchange.com/questions/7720/using-u128-without-sacrificing-alignment-8"] diff --git a/crates/src/websocket_program_account_subscriber.rs b/crates/src/websocket_program_account_subscriber.rs index 1294a74..70cdb65 100644 --- a/crates/src/websocket_program_account_subscriber.rs +++ b/crates/src/websocket_program_account_subscriber.rs @@ -177,12 +177,8 @@ mod tests { }; let subscription_name = "Test"; - let mut ws_subscriber = WebsocketProgramAccountSubscriber::::new( - subscription_name, - mainnet_endpoint(), - options, - EventEmitter::new(), - ); + let mut ws_subscriber = + WebsocketProgramAccountSubscriber::::new(mainnet_endpoint(), options); let _ = ws_subscriber.subscribe().await; dbg!("sub'd");