From da6a129a69bb6475c2f6191abd8045d127f22114 Mon Sep 17 00:00:00 2001 From: Chris Heaney Date: Tue, 7 Jan 2025 12:47:10 -0500 Subject: [PATCH 1/5] program: account for fuel when there is full withdraw --- programs/drift/src/math/margin.rs | 23 +++++++++++++++++++ .../drift/src/state/margin_calculation.rs | 4 ++++ 2 files changed, 27 insertions(+) diff --git a/programs/drift/src/math/margin.rs b/programs/drift/src/math/margin.rs index be883b6ed..e25565fbb 100644 --- a/programs/drift/src/math/margin.rs +++ b/programs/drift/src/math/margin.rs @@ -254,6 +254,29 @@ pub fn calculate_margin_requirement_and_total_collateral_and_liability_info( validation::position::validate_spot_position(spot_position)?; if spot_position.is_available() { + // might need to update fuel to account for spot market deltas + if calculation.context.has_fuel_spot_delta(spot_position.market_index) { + let spot_market = spot_market_map.get_ref(&spot_position.market_index)?; + let (oracle_price_data, oracle_validity) = oracle_map.get_price_data_and_validity( + MarketType::Spot, + spot_market.market_index, + &spot_market.oracle_id(), + spot_market.historical_oracle_data.last_oracle_price_twap, + spot_market.get_max_confidence_interval_multiplier()?, + )?; + + let strict_oracle_price = StrictOraclePrice::new( + oracle_price_data.price, + spot_market + .historical_oracle_data + .last_oracle_price_twap_5min, + calculation.context.strict, + ); + strict_oracle_price.validate()?; + + calculation.update_fuel_spot_bonus(&spot_market, 0, &strict_oracle_price)?; + } + continue; } diff --git a/programs/drift/src/state/margin_calculation.rs b/programs/drift/src/state/margin_calculation.rs index 103d87808..dd95ef08e 100644 --- a/programs/drift/src/state/margin_calculation.rs +++ b/programs/drift/src/state/margin_calculation.rs @@ -105,6 +105,10 @@ impl MarginContext { self } + pub fn has_fuel_spot_delta(&self, market_index: u16) -> bool { + self.fuel_spot_deltas.iter().any(|(index, amount)| *index == market_index && *amount != 0) + } + pub fn fuel_numerator(mut self, user: &User, now: i64) -> Self { self.fuel_bonus_numerator = user.get_fuel_bonus_numerator(now).unwrap(); self From d9a594ec0d000c2946c5940dbea0ffbce0455e50 Mon Sep 17 00:00:00 2001 From: Chris Heaney Date: Tue, 7 Jan 2025 12:51:31 -0500 Subject: [PATCH 2/5] simplification --- programs/drift/src/math/margin.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/programs/drift/src/math/margin.rs b/programs/drift/src/math/margin.rs index e25565fbb..33d62d95d 100644 --- a/programs/drift/src/math/margin.rs +++ b/programs/drift/src/math/margin.rs @@ -257,12 +257,8 @@ pub fn calculate_margin_requirement_and_total_collateral_and_liability_info( // might need to update fuel to account for spot market deltas if calculation.context.has_fuel_spot_delta(spot_position.market_index) { let spot_market = spot_market_map.get_ref(&spot_position.market_index)?; - let (oracle_price_data, oracle_validity) = oracle_map.get_price_data_and_validity( - MarketType::Spot, - spot_market.market_index, + let oracle_price_data = oracle_map.get_price_data( &spot_market.oracle_id(), - spot_market.historical_oracle_data.last_oracle_price_twap, - spot_market.get_max_confidence_interval_multiplier()?, )?; let strict_oracle_price = StrictOraclePrice::new( From 3f0e8b4f8c96d0d3327ebd572448d5ed9b335eb2 Mon Sep 17 00:00:00 2001 From: Chris Heaney Date: Wed, 8 Jan 2025 13:23:08 -0500 Subject: [PATCH 3/5] update to have its own loop --- programs/drift/src/math/margin.rs | 50 ++++++++++++------- .../drift/src/state/margin_calculation.rs | 4 +- 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/programs/drift/src/math/margin.rs b/programs/drift/src/math/margin.rs index 33d62d95d..685134461 100644 --- a/programs/drift/src/math/margin.rs +++ b/programs/drift/src/math/margin.rs @@ -254,25 +254,6 @@ pub fn calculate_margin_requirement_and_total_collateral_and_liability_info( validation::position::validate_spot_position(spot_position)?; if spot_position.is_available() { - // might need to update fuel to account for spot market deltas - if calculation.context.has_fuel_spot_delta(spot_position.market_index) { - let spot_market = spot_market_map.get_ref(&spot_position.market_index)?; - let oracle_price_data = oracle_map.get_price_data( - &spot_market.oracle_id(), - )?; - - let strict_oracle_price = StrictOraclePrice::new( - oracle_price_data.price, - spot_market - .historical_oracle_data - .last_oracle_price_twap_5min, - calculation.context.strict, - ); - strict_oracle_price.validate()?; - - calculation.update_fuel_spot_bonus(&spot_market, 0, &strict_oracle_price)?; - } - continue; } @@ -611,6 +592,37 @@ pub fn calculate_margin_requirement_and_total_collateral_and_liability_info( calculation.validate_num_spot_liabilities()?; + // update fuel to account for spot market deltas where there is no spot position + let spot_fuel_deltas = calculation.context.fuel_spot_deltas; + for (market_index, delta) in spot_fuel_deltas.iter() { + if *delta == 0 { + continue; + } + + let spot_position = match user + .spot_positions + .iter() + .find(|p| p.market_index == *market_index && !p.is_available()) + { + Some(p) => p, + None => continue, + }; + + let spot_market = spot_market_map.get_ref(&spot_position.market_index)?; + let oracle_price_data = oracle_map.get_price_data(&spot_market.oracle_id())?; + + let strict_oracle_price = StrictOraclePrice::new( + oracle_price_data.price, + spot_market + .historical_oracle_data + .last_oracle_price_twap_5min, + calculation.context.strict, + ); + strict_oracle_price.validate()?; + + calculation.update_fuel_spot_bonus(&spot_market, 0, &strict_oracle_price)?; + } + Ok(calculation) } diff --git a/programs/drift/src/state/margin_calculation.rs b/programs/drift/src/state/margin_calculation.rs index dd95ef08e..424b22975 100644 --- a/programs/drift/src/state/margin_calculation.rs +++ b/programs/drift/src/state/margin_calculation.rs @@ -106,7 +106,9 @@ impl MarginContext { } pub fn has_fuel_spot_delta(&self, market_index: u16) -> bool { - self.fuel_spot_deltas.iter().any(|(index, amount)| *index == market_index && *amount != 0) + self.fuel_spot_deltas + .iter() + .any(|(index, amount)| *index == market_index && *amount != 0) } pub fn fuel_numerator(mut self, user: &User, now: i64) -> Self { From 1753f8b34363275fc6d3a59124d8bc60e7c9ba11 Mon Sep 17 00:00:00 2001 From: Chris Heaney Date: Wed, 8 Jan 2025 13:23:43 -0500 Subject: [PATCH 4/5] rm has fuel delta --- programs/drift/src/state/margin_calculation.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/programs/drift/src/state/margin_calculation.rs b/programs/drift/src/state/margin_calculation.rs index 424b22975..103d87808 100644 --- a/programs/drift/src/state/margin_calculation.rs +++ b/programs/drift/src/state/margin_calculation.rs @@ -105,12 +105,6 @@ impl MarginContext { self } - pub fn has_fuel_spot_delta(&self, market_index: u16) -> bool { - self.fuel_spot_deltas - .iter() - .any(|(index, amount)| *index == market_index && *amount != 0) - } - pub fn fuel_numerator(mut self, user: &User, now: i64) -> Self { self.fuel_bonus_numerator = user.get_fuel_bonus_numerator(now).unwrap(); self From 627c8c0db5433e9b954bbc0e0309fe4168740214 Mon Sep 17 00:00:00 2001 From: Chris Heaney Date: Wed, 8 Jan 2025 18:33:09 -0500 Subject: [PATCH 5/5] cAHNGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46bde12b4..ed66a92ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixes +- program: account for fuel when there is full withdraw ([#1413](https://github.com/drift-labs/protocol-v2/pull/1413)) + ### Breaking ## [2.105.0] - 2025-01-02