From 8ffa91633bc5792ed5c4dbe0ced14177c6bf0b50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakob=20Pov=C5=A1i=C4=8D?= Date: Wed, 1 Nov 2023 16:28:30 +0100 Subject: [PATCH] fix: price liquidations with price bias --- .../marginfi_account/liquidate.rs | 4 +- programs/marginfi/src/state/price.rs | 42 +++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/programs/marginfi/src/instructions/marginfi_account/liquidate.rs b/programs/marginfi/src/instructions/marginfi_account/liquidate.rs index 3160a49d..0607e8ce 100644 --- a/programs/marginfi/src/instructions/marginfi_account/liquidate.rs +++ b/programs/marginfi/src/instructions/marginfi_account/liquidate.rs @@ -118,7 +118,7 @@ pub fn lending_account_liquidate( current_timestamp, MAX_PRICE_AGE_SEC, )?; - asset_pf.get_price()? + asset_pf.get_price_with_lower_bias()? }; let mut liab_bank = ctx.accounts.liab_bank.load_mut()?; @@ -131,7 +131,7 @@ pub fn lending_account_liquidate( MAX_PRICE_AGE_SEC, )?; - liab_pf.get_price()? + liab_pf.get_price_with_higher_bias()? }; let final_discount = I80F48::ONE - (LIQUIDATION_INSURANCE_FEE + LIQUIDATION_LIQUIDATOR_FEE); diff --git a/programs/marginfi/src/state/price.rs b/programs/marginfi/src/state/price.rs index 584f9ff0..0e05fca0 100644 --- a/programs/marginfi/src/state/price.rs +++ b/programs/marginfi/src/state/price.rs @@ -32,6 +32,8 @@ pub trait PriceAdapter { /// Get a normalized price range for the given price feed. /// The range is the price +/- the CONF_INTERVAL_MULTIPLE * confidence interval. fn get_price_range(&self) -> MarginfiResult<(I80F48, I80F48)>; + fn get_price_with_lower_bias(&self) -> MarginfiResult; + fn get_price_with_higher_bias(&self) -> MarginfiResult; } #[enum_dispatch(PriceAdapter)] @@ -161,6 +163,24 @@ impl PriceAdapter for PythEmaPriceFeed { Ok((lowest_price, highest_price)) } + + fn get_price_with_lower_bias(&self) -> MarginfiResult { + let price = self.get_price()?; + let conf_interval = self.get_confidence_interval()?; + + let price = price.checked_sub(conf_interval).ok_or_else(math_error!())?; + + Ok(price) + } + + fn get_price_with_higher_bias(&self) -> MarginfiResult { + let price = self.get_price()?; + let conf_interval = self.get_confidence_interval()?; + + let price = price.checked_add(conf_interval).ok_or_else(math_error!())?; + + Ok(price) + } } pub struct SwitchboardV2PriceFeed { @@ -248,6 +268,28 @@ impl PriceAdapter for SwitchboardV2PriceFeed { Ok((lowest_price, highest_price)) } + + fn get_price_with_lower_bias(&self) -> MarginfiResult { + let base_price = self.get_price()?; + let price_range = self.get_confidence_interval()?; + + let lowest_price = base_price + .checked_sub(price_range) + .ok_or_else(math_error!())?; + + Ok(lowest_price) + } + + fn get_price_with_higher_bias(&self) -> MarginfiResult { + let base_price = self.get_price()?; + let price_range = self.get_confidence_interval()?; + + let highest_price = base_price + .checked_add(price_range) + .ok_or_else(math_error!())?; + + Ok(highest_price) + } } /// A slimmed down version of the AggregatorAccountData struct copied from the switchboard-v2/src/aggregator.rs