1use crate::{
2 drift_idl::{
3 errors::ErrorCode,
4 types::{MarginCalculationMode, MarginRequirementType, MarketIdentifier},
5 },
6 types::OracleSource,
7};
8
9pub mod account_list_builder;
10pub mod auction;
11pub mod constants;
12pub mod leverage;
13pub mod liquidation;
14pub mod order;
15
16#[derive(Clone, Copy, Debug)]
17pub struct MarginContext {
18 pub margin_type: MarginRequirementType,
19 pub mode: MarginCalculationMode,
20 pub strict: bool,
21 pub margin_buffer: u128,
22 pub fuel_bonus_numerator: i64,
23 pub fuel_bonus: u64,
24 pub fuel_perp_delta: Option<(u16, i64)>,
25 pub fuel_spot_deltas: [(u16, i128); 2],
26}
27
28impl MarginContext {
29 pub fn standard(margin_type: MarginRequirementType) -> Self {
30 Self {
31 margin_type,
32 mode: MarginCalculationMode::Standard {
33 track_open_orders_fraction: false,
34 },
35 strict: false,
36 margin_buffer: 0,
37 fuel_bonus_numerator: 0,
38 fuel_bonus: 0,
39 fuel_perp_delta: None,
40 fuel_spot_deltas: [(0, 0); 2],
41 }
42 }
43
44 pub fn strict(mut self, strict: bool) -> Self {
45 self.strict = strict;
46 self
47 }
48
49 pub fn margin_buffer(mut self, margin_buffer: u32) -> Self {
50 self.margin_buffer = margin_buffer as u128;
51 self
52 }
53
54 pub fn fuel_perp_delta(mut self, market_index: u16, delta: i64) -> Self {
57 self.fuel_perp_delta = Some((market_index, delta));
58 self
59 }
60
61 pub fn fuel_spot_delta(mut self, market_index: u16, delta: i128) -> Self {
62 self.fuel_spot_deltas[0] = (market_index, delta);
63 self
64 }
65
66 pub fn fuel_spot_deltas(mut self, deltas: [(u16, i128); 2]) -> Self {
67 self.fuel_spot_deltas = deltas;
68 self
69 }
70
71 pub fn track_open_orders_fraction(mut self) -> Result<Self, ErrorCode> {
72 match self.mode {
73 MarginCalculationMode::Standard {
74 track_open_orders_fraction: ref mut track,
75 } => {
76 *track = true;
77 }
78 _ => {
79 return Err(ErrorCode::InvalidMarginCalculation);
80 }
81 }
82 Ok(self)
83 }
84
85 pub fn liquidation(margin_buffer: u32) -> Self {
86 Self {
87 margin_type: MarginRequirementType::Maintenance,
88 mode: MarginCalculationMode::Liquidation {
89 market_to_track_margin_requirement: None,
90 },
91 margin_buffer: margin_buffer as u128,
92 strict: false,
93 fuel_bonus_numerator: 0,
94 fuel_bonus: 0,
95 fuel_perp_delta: None,
96 fuel_spot_deltas: [(0, 0); 2],
97 }
98 }
99
100 pub fn track_market_margin_requirement(
101 mut self,
102 market_identifier: MarketIdentifier,
103 ) -> Result<Self, ErrorCode> {
104 match self.mode {
105 MarginCalculationMode::Liquidation {
106 market_to_track_margin_requirement: ref mut market_to_track,
107 ..
108 } => {
109 *market_to_track = Some(market_identifier);
110 }
111 _ => {
112 return Err(ErrorCode::InvalidMarginCalculation);
113 }
114 }
115 Ok(self)
116 }
117}
118
119fn get_oracle_normalization_factor(a: OracleSource, b: OracleSource) -> (u64, u64) {
121 match (a, b) {
122 (OracleSource::PythLazer, OracleSource::PythLazer1M)
124 | (OracleSource::PythPull, OracleSource::Pyth1MPull) => (1_000_000, 1),
125 (OracleSource::PythLazer1M, OracleSource::PythLazer)
126 | (OracleSource::Pyth1MPull, OracleSource::PythPull) => (1, 1_000_000),
127 (OracleSource::PythLazer, OracleSource::PythLazer1K)
129 | (OracleSource::PythPull, OracleSource::Pyth1KPull) => (1_000, 1),
130 (OracleSource::PythLazer1K, OracleSource::PythLazer)
131 | (OracleSource::Pyth1KPull, OracleSource::PythPull) => (1, 1_000),
132 _ => (1, 1),
133 }
134}